/*========================================================================= * * 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. * *=========================================================================*/ #ifndef itkLBFGSOptimizerBasev4_h #define itkLBFGSOptimizerBasev4_h #include "itkSingleValuedNonLinearVnlOptimizerv4.h" #include "vnl/algo/vnl_lbfgs.h" #include "vnl/algo/vnl_lbfgsb.h" #include #include "ITKOptimizersv4Export.h" namespace itk { /* Necessary forward declaration see below for definition */ /** * \class LBFGSOptimizerBaseHelperv4 * \brief Wrapper helper around vnl optimizer. * * This class is used to translate iteration events, etc, from * vnl_lbfgsb into iteration events in ITK. * * \ingroup ITKOptimizersv4 */ // Forward reference because of circular dependencies template class ITK_TEMPLATE_EXPORT LBFGSOptimizerBaseHelperv4; /** * \class LBFGSOptimizerBasev4 * \brief Abstract base for vnl lbfgs algorithm optimizers in ITKv4 registration framework. * * \note The StopConditionDescription returned by this class is directly from the vnl * optimizer by calling m_VnlOptimizer->get_failure_code() . This seems to * return "Failure" even when no error has occurred. The same behavior is observed * in the ITKv3 version of this optimizer. * * \note Local-support (high-density) transforms. * Local-support transforms are not supported. To add support for these, * the class must be modified thusly: * * \note 1) Parameter updates: * In SingleValuedNonLinearCostFunctionAdaptor, the handling of the gradient * must be changed to accommodate the fact that local-support transforms expect * a gradient to be added to the transform parameters using the * UpdateTransformParameters method of the local support transform. Other optimizers * in the v4 framework use this method, but the use of the vnl optimizers here * complicates it. * * \note 2) Efficiency * To work efficiently with local-support transforms, this class should be * modified to use a single parameter object to avoid the multiple * parameter copies that are currently performed. It should work to use * the transform parameters pointer. * * This code has been adapted for the ITKv4 registration framework from the * v3 version, itkLBFGSOptimizer. * * \ingroup ITKOptimizersv4 */ template class ITK_TEMPLATE_EXPORT LBFGSOptimizerBasev4 : public SingleValuedNonLinearVnlOptimizerv4 { public: ITK_DISALLOW_COPY_AND_MOVE(LBFGSOptimizerBasev4); /** Standard "Self" type alias. */ using Self = LBFGSOptimizerBasev4; using Superclass = SingleValuedNonLinearVnlOptimizerv4; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(LBFGSOptimizerBasev4); using MetricType = Superclass::MetricType; using ParametersType = Superclass::ParametersType; using ScalesType = Superclass::ScalesType; /** Stop condition return string type */ using StopConditionReturnStringType = Superclass::StopConditionReturnStringType; /** Stop condition internal string type */ using StopConditionDescriptionType = Superclass::StopConditionDescriptionType; /** The vnl optimizer */ using InternalOptimizerType = LBFGSOptimizerBaseHelperv4; /** Method for getting access to the internal optimizer. */ InternalOptimizerType * GetOptimizer(); /** Start optimization with an initial value. */ void StartOptimization(bool doOnlyInitialization = false) override; /** Plug in a Cost Function into the optimizer */ void SetMetric(MetricType * metric) override; /** Set/Get the optimizer trace flag. If set to true, the optimizer * prints out information every iteration. */ virtual void SetTrace(bool flag); itkGetConstMacro(Trace, bool); itkBooleanMacro(Trace); /** Set/Get the maximum number of function evaluations allowed. */ virtual void SetMaximumNumberOfFunctionEvaluations(unsigned int n); itkGetConstMacro(MaximumNumberOfFunctionEvaluations, unsigned int); /** Set/Get the gradient convergence tolerance. This is a positive * real number that determines the accuracy with which the solution is to * be found. The optimization terminates when: * ||G|| < gtol max(1,||X||) where ||.|| denotes the Euclidean norm. */ virtual void SetGradientConvergenceTolerance(double f); itkGetConstMacro(GradientConvergenceTolerance, double); /** Get the reason for termination */ const StopConditionReturnStringType GetStopConditionDescription() const override; protected: LBFGSOptimizerBasev4(); ~LBFGSOptimizerBasev4() override = default; void PrintSelf(std::ostream & os, Indent indent) const override; using CostFunctionAdaptorType = Superclass::CostFunctionAdaptorType; bool m_OptimizerInitialized{ false }; using InternalOptimizerAutoPointer = std::unique_ptr; InternalOptimizerAutoPointer m_VnlOptimizer{}; mutable std::ostringstream m_StopConditionDescription{}; bool m_Trace{ false }; unsigned int m_MaximumNumberOfFunctionEvaluations{ 2000 }; double m_GradientConvergenceTolerance{ 1e-5 }; double m_InfinityNormOfProjectedGradient{ 0.0 }; double m_CostFunctionConvergenceFactor{ 1e+7 }; // give the helper access to member variables, to update iteration // counts, etc. friend class LBFGSOptimizerBaseHelperv4; friend class LBFGSBOptimizerHelperv4; }; template class ITK_TEMPLATE_EXPORT LBFGSOptimizerBaseHelperv4 : public TInternalVnlOptimizerType { public: using Self = LBFGSOptimizerBaseHelperv4; using Superclass = TInternalVnlOptimizerType; LBFGSOptimizerBaseHelperv4(vnl_cost_function & f, LBFGSOptimizerBasev4 * itkObj) : TInternalVnlOptimizerType(f) , m_ItkObj(itkObj) {} protected: LBFGSOptimizerBasev4 * m_ItkObj; /** Handle new iteration event */ bool report_iter() override; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkLBFGSOptimizerBasev4.hxx" #endif #endif /** Explicit instantiations */ #ifndef ITK_TEMPLATE_EXPLICIT_LBFGSOptimizerBasev4 // Explicit instantiation is required to ensure correct dynamic_cast // behavior across shared libraries. // // IMPORTANT: Since within the same compilation unit, // ITK_TEMPLATE_EXPLICIT_ defined and undefined states // need to be considered. This code *MUST* be *OUTSIDE* the header // guards. // #if defined(ITKOptimizersv4_EXPORTS) // We are building this library # define ITKOptimizersv4_EXPORT_EXPLICIT ITK_FORWARD_EXPORT #else // We are using this library # define ITKOptimizersv4_EXPORT_EXPLICIT ITKOptimizersv4_EXPORT #endif namespace itk { ITK_GCC_PRAGMA_DIAG_PUSH() ITK_GCC_PRAGMA_DIAG(ignored "-Wattributes") #if defined(_MSC_VER) # pragma warning(disable : 4661) // no suitable definition provided for explicit template instantiation request #endif extern template class ITKOptimizersv4_EXPORT_EXPLICIT LBFGSOptimizerBasev4; extern template class ITKOptimizersv4_EXPORT_EXPLICIT LBFGSOptimizerBasev4; ITK_GCC_PRAGMA_DIAG_POP() } // end namespace itk #undef ITKOptimizersv4_EXPORT_EXPLICIT #endif