////////////////////////////////////////////////////////////////////////
/// \class RAT::Optimisers::Minuit
///
/// \brief  Minuit based optimiser
///
/// \author Phil G Jones <p.jones22@physics.ox.ac.uk>
/// \author Matt Mottram < m.mottram@qmul.ac.uk> -- contact person
///
/// REVISION HISTORY:\n
///     26/04/2011 : P G Jones - New file \n
///     29/05/2013 : W J Heintzelman  Add variable fTol; change name of \n
///                  fMaxInterations to fMaxCalls for consistency with \n
///                  Minuit documentation; add SetD function. \n
///     24/11/2014 : W J Heintzelman  Add option to select Minuit method \n
///
/// \details This is a dumb optimiser, Minuit just optimises the numbers
///
////////////////////////////////////////////////////////////////////////

#ifndef __RAT_Optimiser_Minuit_
#define __RAT_Optimiser_Minuit_

#include <string>
#include <vector>

#include <RAT/Optimiser.hh>

#include <Minuit2/FCNBase.h>
using namespace ROOT::Minuit2;

namespace RAT
{

namespace Optimisers
{

class Minuit : public Optimiser, public FCNBase
{
public:
  virtual std::string GetName() const { return Minuit::Name(); }

  static std::string Name() { return std::string( "minuit" ); }

  /// Initialise the Minuit Optimiser
  void Initialise( const std::string& param );

  void BeginOfRun( DS::Run& run );

  void EndOfRun( DS::Run& ) { }

  void SetD( const std::string& param,
             double value );

  void SetI( const std::string& param,
             int value );

  void SetS( const std::string& param,
             const std::string& value );

  virtual double Minimise();

  virtual double Maximise();

  // Below follows the required Minuit functions
  virtual double operator()( const std::vector<double>& lParams ) const; ///< Vector of values to be optimised

  double Up() const { return fUp; }
  // End Minuit functions
protected:
  /// Invoke the Minuit optimiser
  double MinuitOptimise();

  std::string fIndex; ///< Optional ratdb index string
  double fTol; ///< Minuit fit tolerance; 0.1 is Minuit default.
  int fMaxCalls; ///< Maximum number of user function calls.
                 ///< For fMaxCalls=0, Minuit uses formula to set limit.
  double fMinFactor; ///< Always minimises, thus to maximise set this to -1
  double fUp; ///< Error definition 0.5 for likelihood 1 for chi?
  std::string fMethod;    ///< Method, either "Migrad", "Minimize", or
                          ///< "Simplex".   Default is "Migrad".
};

} //::Optimiser

} //::RAT

#endif