// @(#)root/mathmore:$Id$
// Author: L. Moneta Thu Jan 25 11:13:48 2007

 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 * This library is free software; you can redistribute it and/or      *
 * modify it under the terms of the GNU General Public License        *
 * as published by the Free Software Foundation; either version 2     *
 * of the License, or (at your option) any later version.             *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * General Public License for more details.                           *
 *                                                                    *
 * You should have received a copy of the GNU General Public License  *
 * along with this library (see file COPYING); if not, write          *
 * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
 * 330, Boston, MA 02111-1307 USA, or contact the author.             *
 *                                                                    *

// Header file for class GSLSimAnnealing

#ifndef ROOT_Math_GSLSimAnnealing
#define ROOT_Math_GSLSimAnnealing

#include "Math/IFunctionfwd.h"

#include <vector>

namespace ROOT {

   namespace Math {

      class GSLRandomEngine;

   GSLSimAnFunc class description.
   Interface class for the  objetive function to be used in simulated annealing
   If user wants to re-implement some of the methods (like the one defining the metric) which are used by the
   the simulated annealing algorithm must build a user derived class.
   NOTE: Derived classes must re-implement the assignment and copy constructor to call them of the parent class

   @ingroup MultiMin
class GSLSimAnFunc {

      construct from an interface of a multi-dimensional function
   GSLSimAnFunc(const ROOT::Math::IMultiGenFunction & func, const double * x);

      construct from an interface of a multi-dimensional function
      Use optionally a scale factor (for each coordinate) which can  be used to scale the step sizes
      (this is used for example by the minimization algorithm)
   GSLSimAnFunc(const ROOT::Math::IMultiGenFunction & func, const double * x, const double * scale);


      derived classes might need to re-define completely the class
   GSLSimAnFunc() :


   /// virtual distructor (no operations)
   virtual ~GSLSimAnFunc() { } //

      fast copy method called by GSL simuated annealing internally
      copy only the things which have been changed
      must be re-implemented by derived classes if needed
   virtual GSLSimAnFunc & FastCopy(const GSLSimAnFunc & f);

      clone method. Needs to be re-implemented by the derived classes for deep  copying
   virtual GSLSimAnFunc * Clone() const {
      return new GSLSimAnFunc(*this);

      evaluate the energy ( objective function value)
      re-implement by derived classes if needed to be modified
   virtual double Energy() const;

      change the x[i] value using a random value urndm generated between [0,1]
      up to a maximum value maxstep
      re-implement by derived classes if needed to be modified
   virtual void Step(const GSLRandomEngine & r, double maxstep);

      calculate the distance (metric) between  this one and another configuration
      Presently a cartesian metric is used.
      re-implement by derived classes if needed to be modified
   virtual double Distance(const GSLSimAnFunc & func) const;

      print the position in the standard output std::ostream
      GSL prints in addition n iteration, n function calls, temperature and energy
      re-implement by derived classes if necessary
   virtual void Print();

       change the x values (used by sim annealing to take a step)
   void SetX(const double * x) {
      std::copy(x, x+ fX.size(), fX.begin() );

   template <class IT>
   void SetX(IT begin, IT end) {
      std::copy(begin, end, fX.begin() );

   unsigned int NDim() const { return fX.size(); }

   double X(unsigned int i) const { return fX[i]; }

   const std::vector<double> &  X() const { return fX; }

   double Scale(unsigned int i) const { return fScale[i]; }

   void SetX(unsigned int i, double x) { fX[i] = x; }

   // use compiler generated  copy ctror and assignment operators


   std::vector<double>  fX;
   std::vector<double>  fScale;
   const ROOT::Math::IMultiGenFunction * fFunc;


    structure holding the simulated annealing parameters

   @ingroup MultiMin
struct GSLSimAnParams {

   // constructor with some default values
   GSLSimAnParams() {
      n_tries =    200;
      iters_fixed_T =  10;
      step_size =   10;
      // the following parameters are for the Boltzmann distribution */
      k = 1.0;
      t_initial =  0.002;
      mu =  1.005;
      t_min = 2.0E-6;

   int n_tries;            // number of points to try for each step
   int iters_fixed_T;      // number of iterations at each temperature
   double step_size;       // max step size used in random walk
   /// parameters for the Boltzman distribution
   double k;
   double t_initial;
   double mu;
   double t_min;

   GSLSimAnnealing class for performing  a simulated annealing search of
   a multidimensional function

   @ingroup MultiMin
class GSLSimAnnealing {


      Default constructor
   GSLSimAnnealing ();

      Destructor (no operations)
   ~GSLSimAnnealing ()  {}

   // usually copying is non trivial, so we make this unaccessible

      Copy constructor
   GSLSimAnnealing(const GSLSimAnnealing &) {}

      Assignment operator
   GSLSimAnnealing & operator = (const GSLSimAnnealing & rhs)  {
      if (this == &rhs) return *this;  // time saving self-test
      return *this;


      solve the simulated annealing given a multi-dim function, the initial vector parameters
      and a vector containing the scaling factors for the parameters
   int Solve(const ROOT::Math::IMultiGenFunction & func, const double * x0, const double * scale, double * xmin, bool debug = false);

      solve the simulated annealing given a GSLSimAnFunc object
      The object will contain the initial state at the beginning and the final minimum state at the end
   int Solve(GSLSimAnFunc & func, bool debug = false);

   GSLSimAnParams & Params() { return fParams; }
   const GSLSimAnParams & Params() const { return fParams; }



   GSLSimAnParams fParams; // parameters for GSLSimAnnealig


   } // end namespace Math

} // end namespace ROOT

#endif /* ROOT_Math_GSLSimAnnealing */