// @(#)root/mathmore:$Id$ // Author: L. Moneta Thu Jan 25 11:13:48 2007 /********************************************************************** * * * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT * * * * * **********************************************************************/ // Implementation file for class GSLSimAnnealing #include "Math/GSLSimAnnealing.h" #include "gsl/gsl_siman.h" #include "Math/IFunction.h" #include "Math/GSLRndmEngines.h" #include "GSLRngWrapper.h" #include #include #include #include namespace ROOT { namespace Math { // implementation of GSLSimAnFunc GSLSimAnFunc::GSLSimAnFunc(const ROOT::Math::IMultiGenFunction & func, const double * x) : fX( std::vector(x, x + func.NDim() ) ), fScale( std::vector(func.NDim() )), fFunc(&func) { // set scale factors to 1 fScale.assign(fScale.size(), 1.); } GSLSimAnFunc::GSLSimAnFunc(const ROOT::Math::IMultiGenFunction & func, const double * x, const double * scale) : fX( std::vector(x, x + func.NDim() ) ), fScale( std::vector(scale, scale + func.NDim() ) ), fFunc(&func) {} double GSLSimAnFunc::Energy() const { // evaluate the energy return (*fFunc)(&fX.front() ); } void GSLSimAnFunc::Step(const GSLRandomEngine & random, double maxstep) { // x -> x + Random[-step,step] for each coordinate unsigned int ndim = NDim(); for (unsigned int i = 0; i < ndim; ++i) { double urndm = random(); double sstep = maxstep * fScale[i]; fX[i] += 2 * sstep * urndm - sstep; } } double GSLSimAnFunc::Distance(const GSLSimAnFunc & f) const { // calculate the distance with respect onother configuration const std::vector & x = fX; const std::vector & y = f.X(); unsigned int n = x.size(); assert (n == y.size()); if (n > 1) { double d2 = 0; for (unsigned int i = 0; i < n; ++i) d2 += ( x[i] - y[i] ) * ( x[i] - y[i] ); return std::sqrt(d2); } else // avoid doing a sqrt for 1 dim return std::abs( x[0] - y[0] ); } void GSLSimAnFunc::Print() { // print the position x in standard ostream // GSL prints also niter- ntrials - temperature and then the energy and energy min value (from 1.10) std::cout << "\tx = ( "; unsigned n = NDim(); for (unsigned int i = 0; i < n-1; ++i) { std::cout << fX[i] << " , "; } std::cout << fX.back() << " )\t"; // energy us printed by GSL (and also end-line) std::cout << "E / E_best = "; // GSL print then E and E best } GSLSimAnFunc & GSLSimAnFunc::FastCopy(const GSLSimAnFunc & rhs) { // copy only the information which is changed during the process // in this case only the x values std::copy(rhs.fX.begin(), rhs.fX.end(), fX.begin() ); return *this; } // definition and implementations of the static functions required by GSL namespace GSLSimAn { double E( void * xp) { // evaluate the energy given a state xp GSLSimAnFunc * fx = reinterpret_cast (xp); assert (fx != 0); return fx->Energy(); } void Step( const gsl_rng * r, void * xp, double step_size) { // change xp according to the random step GSLSimAnFunc * fx = reinterpret_cast (xp); assert (fx != 0); // create GSLRandomEngine class // cast away constness (we make sure we don't delete (no call to Terminate() ) GSLRngWrapper rng(const_cast(r)); GSLRandomEngine random(&rng); // wrapper classes random and rng must exist during call to Step() fx->Step(random, step_size); } double Dist( void * xp, void * yp) { // calculate the distance between two configuration GSLSimAnFunc * fx = reinterpret_cast (xp); GSLSimAnFunc * fy = reinterpret_cast (yp); assert (fx != 0); assert (fy != 0); return fx->Distance(*fy); } void Print(void * xp) { // print the position xp // GSL prints also first niter- ntrials - temperature and then the energy GSLSimAnFunc * fx = reinterpret_cast (xp); assert (fx != 0); fx->Print(); } // static function to pass to GSL copy - create and destroy the object void Copy( void * source, void * dest) { GSLSimAnFunc * fx = reinterpret_cast (source); assert (fx != 0); GSLSimAnFunc * gx = reinterpret_cast (dest); assert (gx != 0); gx->FastCopy(*fx); } void * CopyCtor( void * xp) { GSLSimAnFunc * fx = reinterpret_cast (xp); assert (fx != 0); return static_cast ( fx->Clone() ); } void Destroy( void * xp) { GSLSimAnFunc * fx = reinterpret_cast (xp); assert (fx != 0); delete fx; } } // implementation of GSLSimAnnealing class GSLSimAnnealing::GSLSimAnnealing() { // Default constructor implementation. } // function for solving (from a Genfunction interface) int GSLSimAnnealing::Solve(const ROOT::Math::IMultiGenFunction & func, const double * x0, const double * scale, double * xmin, bool debug) { // solve the simulated annealing problem given starting point and objective function interface // initial conditions GSLSimAnFunc fx(func, x0, scale); int iret = Solve(fx, debug); if (iret == 0) { // copy value of the minimum in xmin std::copy(fx.X().begin(), fx.X().end(), xmin); } return iret; } int GSLSimAnnealing::Solve(GSLSimAnFunc & fx, bool debug) { // solve the simulated annealing problem given starting point and GSLSimAnfunc object gsl_rng * r = gsl_rng_alloc(gsl_rng_mt19937); gsl_siman_params_t simanParams; // parameters for the simulated annealing // copy them in GSL structure simanParams.n_tries = fParams.n_tries; /* how many points to try for each step */ simanParams.iters_fixed_T = fParams.iters_fixed_T; /* how many iterations at each temperature? */ simanParams.step_size = fParams.step_size; /* max step size in the random walk */ // the following parameters are for the Boltzmann distribution */ simanParams.k = fParams.k; simanParams.t_initial = fParams.t_initial; simanParams.mu_t = fParams.mu; simanParams.t_min = fParams.t_min; if (debug) gsl_siman_solve(r, &fx, &GSLSimAn::E, &GSLSimAn::Step, &GSLSimAn::Dist, &GSLSimAn::Print, &GSLSimAn::Copy, &GSLSimAn::CopyCtor , &GSLSimAn::Destroy, 0, simanParams ); else gsl_siman_solve(r, &fx, &GSLSimAn::E, &GSLSimAn::Step, &GSLSimAn::Dist, 0, &GSLSimAn::Copy, &GSLSimAn::CopyCtor , &GSLSimAn::Destroy, 0, simanParams ); return 0; } } // end namespace Math } // end namespace ROOT