Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ typename ObjectToObjectMetric<TFixedDimension, TMovingDimension, TVirtualImage,
ObjectToObjectMetric<TFixedDimension, TMovingDimension, TVirtualImage, TParametersValueType>::GetNumberOfParameters()
const
{
return this->m_MovingTransform->GetNumberOfParameters();
const auto numberOfParameters = this->m_MovingTransform->GetNumberOfParameters();
if (numberOfParameters > NumericTraits<NumberOfParametersType>::max())
{
itkExceptionMacro("Moving transform has " << numberOfParameters << " parameters, exceeding the metric limit of "
<< NumericTraits<NumberOfParametersType>::max());
}
return static_cast<NumberOfParametersType>(numberOfParameters);
}

template <unsigned int TFixedDimension,
Expand Down
1 change: 1 addition & 0 deletions Modules/Numerics/Optimizersv4/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ set(
ITKOptimizersv4GTests
itkGradientDescentOptimizerv4ObserverGTest.cxx
itkMultiGradientOptimizerv4GTest.cxx
itkObjectToObjectMetricGTest.cxx
itkWindowConvergenceMonitoringFunctionGTest.cxx
)
creategoogletestdriver(ITKOptimizersv4 "${ITKOptimizersv4-Test_LIBRARIES}" "${ITKOptimizersv4GTests}")
Expand Down
130 changes: 130 additions & 0 deletions Modules/Numerics/Optimizersv4/test/itkObjectToObjectMetricGTest.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*=========================================================================
*
* Copyright NumFOCUS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/

// First include the header file to be tested:
#include "itkObjectToObjectMetric.h"

#include "itkGTest.h"
#include "itkIdentityTransform.h"
#include <limits>

namespace
{
class CountTransform : public itk::IdentityTransform<double, 3>
{
public:
ITK_DISALLOW_COPY_AND_MOVE(CountTransform);
using Self = CountTransform;
using Superclass = itk::IdentityTransform<double, 3>;
using Pointer = itk::SmartPointer<Self>;
using NumberOfParametersType = Superclass::NumberOfParametersType;
itkNewMacro(Self);
itkOverrideGetNameOfClassMacro(CountTransform);

void
SetCount(NumberOfParametersType count)
{
m_Count = count;
}

NumberOfParametersType
GetNumberOfParameters() const override
{
return m_Count;
}

protected:
CountTransform() = default;
~CountTransform() override = default;

private:
NumberOfParametersType m_Count{};
};

class CountMetric : public itk::ObjectToObjectMetric<3, 3>
{
public:
ITK_DISALLOW_COPY_AND_MOVE(CountMetric);
using Self = CountMetric;
using Superclass = itk::ObjectToObjectMetric<3, 3>;
using Pointer = itk::SmartPointer<Self>;
itkNewMacro(Self);
itkOverrideGetNameOfClassMacro(CountMetric);

MeasureType
GetValue() const override
{
return 0.0;
}

void
GetDerivative(DerivativeType & derivative) const override
{
derivative.SetSize(0);
}

void
GetValueAndDerivative(MeasureType & value, DerivativeType & derivative) const override
{
value = this->GetValue();
this->GetDerivative(derivative);
}

bool
SupportsArbitraryVirtualDomainSamples() const override
{
return false;
}

protected:
CountMetric() = default;
~CountMetric() override = default;
};
} // namespace

TEST(ObjectToObjectMetric, PreservesRepresentableParameterCounts)
{
const auto transform = CountTransform::New();
const auto metric = CountMetric::New();
metric->SetMovingTransform(transform);
using CountType = CountMetric::NumberOfParametersType;
for (const CountType count : { CountType{ 0 }, CountType{ 17 }, std::numeric_limits<CountType>::max() })
{
transform->SetCount(count);
EXPECT_EQ(metric->GetNumberOfParameters(), count);
}
}

TEST(ObjectToObjectMetric, RejectsParameterCountOverflow)
{
using TransformCountType = CountTransform::NumberOfParametersType;
using MetricCountType = CountMetric::NumberOfParametersType;
if constexpr (std::numeric_limits<TransformCountType>::digits <= std::numeric_limits<MetricCountType>::digits)
{
GTEST_SKIP() << "The transform count type is not wider than the metric count type";
}
else
{
const auto transform = CountTransform::New();
const auto metric = CountMetric::New();
metric->SetMovingTransform(transform);
const auto maximum = static_cast<TransformCountType>(std::numeric_limits<MetricCountType>::max());
transform->SetCount(maximum + TransformCountType{ 1 });
EXPECT_THROW(metric->GetNumberOfParameters(), itk::ExceptionObject);
}
}
Loading