// @(#)root/minuit2:$Id$
// Authors: M. Winkler, F. James, L. Moneta, A. Zsenei   2003-2005

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2005 LCG ROOT Math team,  CERN/PH-SFT                *
 *                                                                    *
 **********************************************************************/

#ifndef ROOT_Minuit2_MnHesse
#define ROOT_Minuit2_MnHesse

#include "Minuit2/MnConfig.h"
#include "Minuit2/MnStrategy.h"

#include <vector>

namespace ROOT {

namespace Minuit2 {

class FCNBase;
class MnUserParameterState;
class MnUserParameters;
class MnUserCovariance;
class MnUserTransformation;
class MinimumState;
class MnMachinePrecision;
class MnFcn;
class FunctionMinimum;
class FCNGradientBase;

//_______________________________________________________________________
/**
    API class for calculating the numerical covariance matrix
    (== 2x Inverse Hessian == 2x Inverse 2nd derivative); can be used by the
    user or Minuit itself
 */

class MnHesse {

public:
   /// default constructor with default strategy
   MnHesse() : fStrategy(MnStrategy(1)) {}

   /// constructor with user-defined strategy level
   MnHesse(unsigned int stra) : fStrategy(MnStrategy(stra)) {}

   /// conctructor with specific strategy
   MnHesse(const MnStrategy &stra) : fStrategy(stra) {}

   ~MnHesse() {}

   ///
   /// low-level API
   ///
   /// FCN + parameters + errors
   MnUserParameterState operator()(const FCNBase &, const std::vector<double> &, const std::vector<double> &,
                                   unsigned int maxcalls = 0) const;
   /// FCN + parameters + covariance
   MnUserParameterState operator()(const FCNBase &, const std::vector<double> &, unsigned int nrow,
                                   const std::vector<double> &, unsigned int maxcalls = 0) const;
   /// FCN + parameters + MnUserCovariance
   MnUserParameterState
   operator()(const FCNBase &, const std::vector<double> &, const MnUserCovariance &, unsigned int maxcalls = 0) const;
   ///
   /// high-level API
   ///
   /// FCN + MnUserParameters
   MnUserParameterState operator()(const FCNBase &, const MnUserParameters &, unsigned int maxcalls = 0) const;
   /// FCN + MnUserParameters + MnUserCovariance
   MnUserParameterState
   operator()(const FCNBase &, const MnUserParameters &, const MnUserCovariance &, unsigned int maxcalls = 0) const;
   /// FCN + MnUserParameterState
   MnUserParameterState operator()(const FCNBase &, const MnUserParameterState &, unsigned int maxcalls = 0) const;
   ///
   /// API to use MnHesse after minimization when function minimum is avalilable, otherwise information on the last
   /// state will be lost. (It would be needed to re-call the gradient and spend extra useless function calls) The
   /// Function Minimum is updated (modified) by adding the Hesse results as last state of minimization
   ///
   void operator()(const FCNBase &, FunctionMinimum &, unsigned int maxcalls = 0) const;

   /// internal interface
   ///
   MinimumState
   operator()(const MnFcn &, const MinimumState &, const MnUserTransformation &, unsigned int maxcalls = 0) const;

   /// forward interface of MnStrategy
   unsigned int Ncycles() const { return fStrategy.HessianNCycles(); }
   double Tolerstp() const { return fStrategy.HessianStepTolerance(); }
   double TolerG2() const { return fStrategy.HessianG2Tolerance(); }

private:

   /// internal function to compute the Hessian using numerical derivative computation
   MinimumState ComputeNumerical(const MnFcn &, const MinimumState &, const MnUserTransformation &, unsigned int maxcalls) const;

   /// internal function to compute the Hessian using an analytical computation or externally provided in the FCNGradientBase class
   MinimumState ComputeAnalytical(const FCNGradientBase &, const MinimumState &, const MnUserTransformation &) const;

   MnStrategy fStrategy;
};

} // namespace Minuit2

} // namespace ROOT

#endif // ROOT_Minuit2_MnHesse
