ccgsl 2.7.2
C++wrappersforGnuScientificLibrary
siman.hpp
Go to the documentation of this file.
1/*
2 * $Id: siman.hpp 200 2012-08-05 19:11:27Z jdl3 $
3 * Copyright (C) 2012, 2016 John D Lamb
4 * Copyright (C) 2007 Brian Gough
5 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Mark Galassi
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef CCGSL_SIMAN_HPP
23#define CCGSL_SIMAN_HPP
24
25#include<cstring>
26#include<cmath>
27#include<gsl/gsl_machine.h>
28#include<gsl/gsl_siman.h>
29#include"rng.hpp"
30
31namespace gsl {
49 template<typename XP>
50 struct siman {
51 // Types for function pointes
55 typedef double (*Efunc_t)( XP& xp );
59 typedef void (*step_t)( rng& r, XP& xp, double step_size );
63 typedef double (*metric_t)( XP& xp, XP& yp );
67 typedef void (*print_t)( XP& xp );
71 typedef void (*copy_t)( XP& source, XP& dest );
75 typedef XP* (*copy_construct_t)( XP& xp );
79 typedef void (*destroy_t)( XP* xp );
83 typedef gsl_siman_params_t params_t;
101 inline static void solve( rng& r, XP& x0_p, Efunc_t Ef, step_t take_step,
102 metric_t distance, print_t print_position,
103 copy_t copyfunc, copy_construct_t copy_constructor,
104 destroy_t destructor, params_t& params ){
105 // This is adapted directly from the GSL. This isn't ideal. But it's the only
106 // current way to allow us to pass suitable function pointers.
107
108 // inline functions adapted as local functions
109 struct {
110 double operator()( double E, double new_E, double T, params_t& params ) const {
111 double x = -(new_E - E) / (params.k * T);
112 /* avoid underflow errors for large uphill steps */
113 return (x < GSL_LOG_DBL_MIN) ? 0.0 : std::exp(x);
114 }
115 } boltzmann;
116
117 struct {
118 void operator()( XP& src, XP& dst, size_t size, copy_t copyfunc ) const {
119 if (copyfunc) {
120 copyfunc(src, dst);
121 } else {
122 memcpy(reinterpret_cast<void*>( &dst ), reinterpret_cast<void*>( &src ), size);
123 }
124 }
125 } copy_state;
126
127 XP *x, *new_x, *best_x;
128 double E, new_E, best_E;
129 int i;
130 double T, T_factor;
131 int n_evals = 1, n_iter = 0, n_accepts, n_rejects, n_eless;
132
133 /* this function requires that either the dynamic functions (copy,
134 copy_constructor and destructor) are passed, or that an element
135 size is given */
136 size_t element_size = 0;
137 if( copyfunc == NULL ){
138 if( copy_constructor != NULL || destructor != NULL ){
139 std::cerr << "ccgsl::siman<XP>::solve(): "
140 << "this function requires that either the dynamic functions (copy, "
141 << "copy_constructor and destructor) are all passed, or that none are."
142 << std::endl;
143 std::exit( 1 );
144 }
145 element_size = sizeof( XP );
146 }
147
148 distance = 0 ; /* This parameter is not currently used */
149 E = Ef(x0_p);
150
151 if (copyfunc) {
152 x = copy_constructor(x0_p);
153 new_x = copy_constructor(x0_p);
154 best_x = copy_constructor(x0_p);
155 } else {
156 x = (XP *) malloc (element_size);
157 memcpy (x, reinterpret_cast<void*>( &x0_p ), element_size);
158
159 new_x = (XP *) malloc (element_size);
160 best_x = (XP *) malloc (element_size);
161 memcpy (best_x, reinterpret_cast<void*>( &x0_p ), element_size);
162 }
163
164 best_E = E;
165
166 T = params.t_initial;
167 T_factor = 1.0 / params.mu_t;
168
169 if (print_position) {
170 printf ("#-iter #-evals temperature position energy\n");
171 }
172
173 while (1) {
174
175 n_accepts = 0;
176 n_rejects = 0;
177 n_eless = 0;
178
179 for (i = 0; i < params.iters_fixed_T; ++i) {
180
181 copy_state(*x, *new_x, element_size, copyfunc);
182
183 take_step (r, *new_x, params.step_size);
184 new_E = Ef (*new_x);
185
186 if(new_E <= best_E){
187 if (copyfunc) {
188 copyfunc(*new_x,*best_x);
189 } else {
190 memcpy (best_x, new_x, element_size);
191 }
192 best_E=new_E;
193 }
194
195 ++n_evals; /* keep track of Ef() evaluations */
196 /* now take the crucial step: see if the new point is accepted
197 or not, as determined by the boltzmann probability */
198 if (new_E < E) {
199
200 if (new_E < best_E) {
201 copy_state(*new_x, *best_x, element_size, copyfunc);
202 best_E = new_E;
203 }
204
205 /* yay! take a step */
206 copy_state(*new_x, *x, element_size, copyfunc);
207 E = new_E;
208 ++n_eless;
209
210 } else if (r.uniform() < boltzmann(E, new_E, T, params)) {
211 /* yay! take a step */
212 copy_state(*new_x, *x, element_size, copyfunc);
213 E = new_E;
214 ++n_accepts;
215
216 } else {
217 ++n_rejects;
218 }
219 }
220
221 if (print_position) {
222 /* see if we need to print stuff as we go */
223 /* printf("%5d %12g %5d %3d %3d %3d", n_iter, T, n_evals, */
224 /* 100*n_eless/n_steps, 100*n_accepts/n_steps, */
225 /* 100*n_rejects/n_steps); */
226 printf ("%5d %7d %12g", n_iter, n_evals, T);
227 print_position (*x);
228 printf (" %12g %12g\n", E, best_E);
229 }
230
231 /* apply the cooling schedule to the temperature */
232 /* FIXME: I should also introduce a cooling schedule for the iters */
233 T *= T_factor;
234 ++n_iter;
235 if (T < params.t_min) {
236 break;
237 }
238 }
239
240 /* at the end, copy the result onto the initial point, so we pass it
241 back to the caller */
242 copy_state(*best_x, x0_p, element_size, copyfunc);
243
244 if (copyfunc) {
245 destructor(x);
246 destructor(new_x);
247 destructor(best_x);
248 } else {
249 free (x);
250 free (new_x);
251 free (best_x);
252 }
253 }
254
267 void solve_many( rng& r, XP& x0_p, Efunc_t Ef, step_t take_step, metric_t distance,
268 print_t print_position, params_t params ){
269 // This is adapted directly from the GSL. This isn't ideal. But it's the only
270 // current way to allow us to pass suitable function pointers.
271
272 // inline function adapted as local function
273 struct {
274 double operator()( double E, double new_E, double T, params_t& params ) const {
275 double x = -(new_E - E) / (params.k * T);
276 /* avoid underflow errors for large uphill steps */
277 return (x < GSL_LOG_DBL_MIN) ? 0.0 : std::exp(x);
278 }
279 } boltzmann;
280
281 size_t const element_size = sizeof( XP );
282
283 /* the new set of trial points, and their energies and probabilities */
284 void *x, *new_x;
285 double *energies, *probs, *sum_probs;
286 double Ex; /* energy of the chosen point */
287 double T, T_factor; /* the temperature and a step multiplier */
288 int i;
289 double u; /* throw the die to choose a new "x" */
290 int n_iter;
291
292 if (print_position) {
293 printf ("#-iter temperature position");
294 printf (" delta_pos energy\n");
295 }
296
297 x = (void *) malloc (params.n_tries * element_size);
298 new_x = (void *) malloc (params.n_tries * element_size);
299 energies = (double *) malloc (params.n_tries * sizeof (double));
300 probs = (double *) malloc (params.n_tries * sizeof (double));
301 sum_probs = (double *) malloc (params.n_tries * sizeof (double));
302
303 T = params.t_initial;
304 T_factor = 1.0 / params.mu_t;
305
306 memcpy (x, x0_p, element_size);
307
308 n_iter = 0;
309 while (1)
310 {
311 Ex = Ef (x);
312 for (i = 0; i < params.n_tries - 1; ++i)
313 { /* only go to N_TRIES-2 */
314 /* center the new_x[] around x, then pass it to take_step() */
315 sum_probs[i] = 0;
316 memcpy ((char *)new_x + i * element_size, x, element_size);
317 take_step (r, (char *)new_x + i * element_size, params.step_size);
318 energies[i] = Ef ((char *)new_x + i * element_size);
319 probs[i] = boltzmann(Ex, energies[i], T, &params);
320 }
321 /* now add in the old value of "x", so it is a contendor */
322 memcpy ((char *)new_x + (params.n_tries - 1) * element_size, x, element_size);
323 energies[params.n_tries - 1] = Ex;
324 probs[params.n_tries - 1] = boltzmann(Ex, energies[i], T, &params);
325
326 /* now throw biased die to see which new_x[i] we choose */
327 sum_probs[0] = probs[0];
328 for (i = 1; i < params.n_tries; ++i)
329 {
330 sum_probs[i] = sum_probs[i - 1] + probs[i];
331 }
332 u = r.uniform () * sum_probs[params.n_tries - 1];
333 for (i = 0; i < params.n_tries; ++i)
334 {
335 if (u < sum_probs[i])
336 {
337 memcpy (x, (char *) new_x + i * element_size, element_size);
338 break;
339 }
340 }
341 if (print_position)
342 {
343 printf ("%5d\t%12g\t", n_iter, T);
344 print_position (x);
345 printf ("\t%12g\t%12g\n", distance (x, x0_p), Ex);
346 }
347 T *= T_factor;
348 ++n_iter;
349 if (T < params.t_min)
350 {
351 break;
352 }
353 }
354
355 /* now return the value via x0_p */
356 memcpy (x0_p, x, element_size);
357
358 /* printf("the result is: %g (E=%g)\n", x, Ex); */
359
360 free (x);
361 free (new_x);
362 free (energies);
363 free (probs);
364 free (sum_probs);
365 }
366 };
367}
368#endif
Random number generator.
Definition: rng.hpp:31
double uniform() const
C++ version of gsl_rng_uniform().
Definition: rng.hpp:624
size_t size(series const &cs)
C++ version of gsl_cheb_size().
Definition: chebyshev.hpp:287
complex exp(complex const &a)
C++ version of gsl_complex_exp().
Definition: complex.hpp:963
double const E
e
Definition: math.hpp:36
The gsl package creates an interface to the GNU Scientific Library for C++.
Definition: blas.hpp:34
Simulated annealing.
Definition: siman.hpp:50
static void solve(rng &r, XP &x0_p, Efunc_t Ef, step_t take_step, metric_t distance, print_t print_position, copy_t copyfunc, copy_construct_t copy_constructor, destroy_t destructor, params_t &params)
C++ version of gsl_siman_solve().
Definition: siman.hpp:101
void(* destroy_t)(XP *xp)
Function to destruct a configuration.
Definition: siman.hpp:79
double(* Efunc_t)(XP &xp)
Function returning then energy of a configuration.
Definition: siman.hpp:55
void(* print_t)(XP &xp)
Function to print a configuration.
Definition: siman.hpp:67
void solve_many(rng &r, XP &x0_p, Efunc_t Ef, step_t take_step, metric_t distance, print_t print_position, params_t params)
C++ version of gsl_siman_solve_many().
Definition: siman.hpp:267
XP *(* copy_construct_t)(XP &xp)
Function to construct a configuration.
Definition: siman.hpp:75
void(* copy_t)(XP &source, XP &dest)
Function to copy configuration contents from source to dest.
Definition: siman.hpp:71
gsl_siman_params_t params_t
Parameters: same as gsl_siman_params_t.
Definition: siman.hpp:83
void(* step_t)(rng &r, XP &xp, double step_size)
Function to modify configuration with random number up to maximum step size.
Definition: siman.hpp:59
double(* metric_t)(XP &xp, XP &yp)
Function to find distance between two configurations.
Definition: siman.hpp:63