// @(#)root/mathcore:$Id$
// Author: David Gonzalez Maline 2/2008
 /**********************************************************************
  *                                                                    *
  * Copyright (c) 2004  CERN                                           *
  * All rights reserved.                                               *
  *                                                                    *
  * For the licensing terms see $ROOTSYS/LICENSE.                      *
  * For the list of contributors see $ROOTSYS/README/CREDITS.          *
  *                                                                    *
  **********************************************************************/

// Header file for class BrentMinimizer1D
//
// Created by: Maline  at Mon Feb  4 09:32:36 2008
//
//


#ifndef ROOT_Math_BrentMinimizer1D
#define ROOT_Math_BrentMinimizer1D

#include "Math/IMinimizer1D.h"

#include "Math/IFunctionfwd.h"


namespace ROOT {
namespace Math {

//___________________________________________________________________________________________
/**
   User class for performing function minimization

   It will use the Brent Method for function minimization in a given interval.
   First, a grid search is used to bracket the minimum value
   with the a step size = (xmax-xmin)/npx. The step size
   can be controlled via the SetNpx() function. A default value of npx = 100 is used.
   The default value con be changed using the static method SetDefaultNpx.
   If the function is unimodal or if its extrema are far apart, setting the fNpx to
   a small value speeds the algorithm up many times.
   Then, Brent's method is applied on the bracketed interval.
   If the Brent method fails to converge the bracketing is repeated on the latest best estimate of the
   interval. The procedure is repeated with a maximum value (default =10) which can be set for all
   BrentRootFinder classes with the method SetDefaultNSearch



   This class is implemented from TF1::GetMinimum.

   To use the class, three steps have to be taken:
       1. Create the class.
       2. Set a function within an interval to look for the minimum.
       3. Call the Minimize function with the error parameters.

   If another minimization is to be performed, repeat the last two steps.

   @ingroup Min1D

 */

   class BrentMinimizer1D: private ROOT::Math::IMinimizer1D {

   public:

      /** Default Constructor. */
      BrentMinimizer1D();

      /** Default Destructor. */
      ~BrentMinimizer1D() override {}

   public:

      /** Return current estimate of the position of the minimum. */
      double XMinimum() const override {   return fXMinimum;  }

      /** Return current lower bound of the minimization interval. */
      double XLower() const override {   return fXMin;  }

      /** Return current upper bound of the minimization interval. */
      double XUpper() const override {   return fXMax;  }

      /** Return function value at current estimate of the minimum. */
      double FValMinimum() const override;

      /** Return function value at current lower bound of the minimization interval. */
      double FValLower() const override;

      /** Return function value at current upper bound of the minimization interval. */
      double FValUpper() const override;

      /** Find minimum position iterating until convergence specified by the absolute and relative tolerance or
          the maximum number of iteration is reached.
          Return true if iterations converged successfully
          \@param maxIter maximum number of iterations.
          \@param absTol desired absolute error in the minimum position (default 1.E-8)
          \@param absTol desired relative error in the minimum position (default = 1.E-10)
      */
      bool Minimize( int maxIter, double absTol = 1.E-8, double relTol = 1.E-10) override;

      /** Return number of iteration used to find minimum */
      int Iterations() const override { return fNIter; }

      /** Return name of minimization algorithm ("BrentMinimizer1D") */
      const char * Name() const override;

      /** Sets function to be minimized.

          \@param f Function to be minimized.
          \@param xlow Lower bound of the search interval.
          \@param xup Upper bound of the search interval.
      */
      void SetFunction(const ROOT::Math::IGenFunction& f, double xlow, double xup);

      /** Set the number of point used to bracket root using a grid */
      void SetNpx(int npx) { fNpx = npx; }

      /**
          Set a log grid scan (default is equidistant bins)
          will work only if xlow > 0
      */
      void SetLogScan(bool on) { fLogScan = on; }


      /** Returns status of last estimate. If = 0 is OK */
      int Status() const override { return fStatus; }

      // static function used to modify the default parameters

      /** set number of default Npx used at construction time (when SetNpx is not called)
          Default value is 100
       */
      static void SetDefaultNpx(int npx);

      /** set number of  times the bracketing search in combination with is done to find a good interval
          Default value is 10
       */
      static void SetDefaultNSearch(int n);

   private:

      const IGenFunction* fFunction; ///< Pointer to the function.
      bool fLogScan;                 ///< flag to control usage of a log scan
      int fNIter;                    ///< Number of iterations needed for the last estimation.
      int fNpx;                      ///< Number of points to bracket minimum with grid (def is 100)
      int fStatus;                   ///< Status of code of the last estimate
      double fXMin;                  ///< Lower bound of the search interval.
      double fXMax;                  ///< Upper bound of the search interval
      double fXMinimum;              ///< Position of the estimated minimum.

   };  // end class BrentMinimizer1D

} // end namespace Math

} // end namespace ROOT

#endif /* ROOT_Math_BrentMinimizer1D */
