text: /*=========================================================================
   *
   *  Copyright Insight Software Consortium
   *
   *  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
   *
   *         http://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_hxx
  #define itkLBFGSOptimizerBasev4_hxx
  
  #include "itkLBFGSOptimizerBasev4.h"
  
  extern "C" {
    extern double v3p_netlib_dpmeps_();
  }
  
  namespace itk
  {
  
  template< typename TInternalVnlOptimizerType >
  class ITK_TEMPLATE_EXPORT LBFGSOptimizerBaseHelperv4: public TInternalVnlOptimizerType
  {
    public:
    using Self = LBFGSOptimizerBaseHelperv4;
    using Superclass = TInternalVnlOptimizerType;
  
    LBFGSOptimizerBaseHelperv4(vnl_cost_function & f,
                               LBFGSOptimizerBasev4<TInternalVnlOptimizerType> * itkObj):
    TInternalVnlOptimizerType(f),
    m_ItkObj(itkObj)
    {
    }
  
    protected:
    LBFGSOptimizerBasev4<TInternalVnlOptimizerType> * m_ItkObj;
  
    /** Handle new iteration event */
    bool report_iter() override;
  };
  
  
  template< typename TInternalVnlOptimizerType >
  bool
  LBFGSOptimizerBaseHelperv4<TInternalVnlOptimizerType>
  ::report_iter()
  {
    Superclass::report_iter();
  
    m_ItkObj->InvokeEvent( IterationEvent() );
    m_ItkObj->m_CurrentIteration = this->num_iterations_;
  
    // Return true to terminate the optimization loop.
    if ( this->num_iterations_ >= m_ItkObj->m_NumberOfIterations )
      {
      return true;
      }
    else
      {
      return false;
      }
  }
  
  template<typename TInternalVnlOptimizerType>
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::LBFGSOptimizerBasev4()
  
  {
    Superclass::SetNumberOfIterations(500);
  }
  
  template<typename TInternalVnlOptimizerType>
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::~LBFGSOptimizerBasev4() = default;
  
  template<typename TInternalVnlOptimizerType>
  void
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::PrintSelf(std::ostream & os, Indent indent) const
  {
    Superclass::PrintSelf(os, indent);
    os << indent << "Trace: ";
    if ( m_Trace )
      {
      os << "On";
      }
    else
      {
      os << "Off";
      }
    os << std::endl;
    os << indent << "MaximumNumberOfFunctionEvaluations: "
       << m_MaximumNumberOfFunctionEvaluations << std::endl;
    os << indent << "GradientConvergenceTolerance: "
       << m_GradientConvergenceTolerance << std::endl;
  }
  
  template<typename TInternalVnlOptimizerType>
  void
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::SetTrace(bool flag)
  {
    if ( flag == m_Trace )
      {
      return;
      }
  
    m_Trace = flag;
    if ( m_OptimizerInitialized )
      {
      m_VnlOptimizer->set_trace(m_Trace);
      }
  
    this->Modified();
  }
  
  template<typename TInternalVnlOptimizerType>
  void
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::SetMaximumNumberOfFunctionEvaluations(unsigned int n)
  {
    if ( n == m_MaximumNumberOfFunctionEvaluations )
      {
      return;
      }
  
    m_MaximumNumberOfFunctionEvaluations = n;
    if ( m_OptimizerInitialized )
      {
      m_VnlOptimizer->set_max_function_evals(
        static_cast< int >( m_MaximumNumberOfFunctionEvaluations ) );
      }
  
    this->Modified();
  }
  
  template<typename TInternalVnlOptimizerType>
  void
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::SetGradientConvergenceTolerance(double f)
  {
    if ( Math::ExactlyEquals(f, m_GradientConvergenceTolerance) )
      {
      return;
      }
  
    m_GradientConvergenceTolerance = f;
    if ( m_OptimizerInitialized )
      {
      m_VnlOptimizer->set_g_tolerance(m_GradientConvergenceTolerance);
      }
  
    this->Modified();
  }
  
  template<typename TInternalVnlOptimizerType>
  void
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::SetMetric(MetricType *metric)
  {
    // assign to base class
    this->m_Metric = metric;
  
    // assign to vnl cost-function adaptor
    const unsigned int numberOfParameters = metric->GetNumberOfParameters();
  
    auto * adaptor = new CostFunctionAdaptorType( numberOfParameters );
  
    adaptor->SetCostFunction( metric );
  
    this->SetCostFunctionAdaptor( adaptor );
  
    m_VnlOptimizer.reset( new InternalOptimizerType( *adaptor, this ) );
  }
  
  template<typename TInternalVnlOptimizerType>
  void
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::StartOptimization(bool /* doOnlyInitialization */)
  {
    // Check for a local-support transform.
    // These aren't currently supported, see main class documentation.
    if( this->GetMetric()->HasLocalSupport() )
      {
      itkExceptionMacro("The assigned transform has local-support. This is not supported for this optimizer. See the optimizer documentation.");
      }
  
    // Perform some verification, check scales,
    // pass settings to cost-function adaptor.
    Superclass::StartOptimization();
  }
  
  template<typename TInternalVnlOptimizerType>
  typename LBFGSOptimizerBasev4<TInternalVnlOptimizerType>::InternalOptimizerType *
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::GetOptimizer()
  {
    return m_VnlOptimizer.get();
  }
  
  template<typename TInternalVnlOptimizerType>
  const std::string
  LBFGSOptimizerBasev4<TInternalVnlOptimizerType>
  ::GetStopConditionDescription() const
  {
    m_StopConditionDescription.str("");
    m_StopConditionDescription << this->GetNameOfClass() << ": ";
    if ( m_VnlOptimizer )
      {
      switch ( m_VnlOptimizer->get_failure_code() )
        {
        case vnl_nonlinear_minimizer::ERROR_FAILURE:
          m_StopConditionDescription << "Failure";
          break;
        case vnl_nonlinear_minimizer::ERROR_DODGY_INPUT:
          m_StopConditionDescription << "Dodgy input";
          break;
        case vnl_nonlinear_minimizer::CONVERGED_FTOL:
          m_StopConditionDescription << "Function tolerance reached after "
                                      << m_CurrentIteration
                                      << " iterations. "
                                      << "The relative reduction of the cost function <= "
                                      << m_CostFunctionConvergenceFactor * v3p_netlib_dpmeps_()
                                      << " = CostFunctionConvergenceFactor ("
                                      << m_CostFunctionConvergenceFactor
                                      << ") * machine precision ("
                                      << v3p_netlib_dpmeps_()
                                      << ").";
          break;
        case vnl_nonlinear_minimizer::CONVERGED_XTOL:
          m_StopConditionDescription << "Solution tolerance reached";
          break;
        case vnl_nonlinear_minimizer::CONVERGED_XFTOL:
          m_StopConditionDescription << "Solution and Function tolerance both reached";
          break;
        case vnl_nonlinear_minimizer::CONVERGED_GTOL:
          m_StopConditionDescription << "Gradient tolerance reached. "
                                     << "Gradient tolerance is "
                                     << m_GradientConvergenceTolerance;
          break;
        case vnl_nonlinear_minimizer::FAILED_TOO_MANY_ITERATIONS:
          m_StopConditionDescription << "Too many function evaluations. Function evaluations  = "
                                     << m_MaximumNumberOfFunctionEvaluations;
          break;
        case vnl_nonlinear_minimizer::FAILED_FTOL_TOO_SMALL:
          m_StopConditionDescription << "Function tolerance too small";
          break;
        case vnl_nonlinear_minimizer::FAILED_XTOL_TOO_SMALL:
          m_StopConditionDescription << "Solution tolerance too small";
          break;
        case vnl_nonlinear_minimizer::FAILED_GTOL_TOO_SMALL:
          m_StopConditionDescription << "Gradient tolerance too small";
          break;
        case vnl_nonlinear_minimizer::FAILED_USER_REQUEST:
          m_StopConditionDescription << "User requested";
          break;
        }
      return m_StopConditionDescription.str();
      }
    else
      {
      return std::string("");
      }
  }
  } // end namespace itk
  
  #endif
  