summaryrefslogtreecommitdiff
path: root/gsl-1.9/siman/siman.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/siman/siman.c')
-rw-r--r--gsl-1.9/siman/siman.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/gsl-1.9/siman/siman.c b/gsl-1.9/siman/siman.c
new file mode 100644
index 0000000..051c235
--- /dev/null
+++ b/gsl-1.9/siman/siman.c
@@ -0,0 +1,266 @@
+/* siman/siman.c
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000 Mark Galassi
+ *
+ * This program 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 program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <gsl/gsl_machine.h>
+#include <gsl/gsl_rng.h>
+#include <gsl/gsl_siman.h>
+
+static inline
+double safe_exp (double x) /* avoid underflow errors for large uphill steps */
+{
+ return (x < GSL_LOG_DBL_MIN) ? 0.0 : exp(x);
+}
+
+/* implementation of a basic simulated annealing algorithm */
+
+void
+gsl_siman_solve (const gsl_rng * r, void *x0_p, gsl_siman_Efunc_t Ef,
+ gsl_siman_step_t take_step,
+ gsl_siman_metric_t distance,
+ gsl_siman_print_t print_position,
+ gsl_siman_copy_t copyfunc,
+ gsl_siman_copy_construct_t copy_constructor,
+ gsl_siman_destroy_t destructor,
+ size_t element_size,
+ gsl_siman_params_t params)
+{
+ void *x, *new_x, *best_x;
+ double E, new_E, best_E;
+ int i, done;
+ double T;
+ int n_evals = 1, n_iter = 0, n_accepts, n_rejects, n_eless;
+
+ /* this function requires that either the dynamic functions (copy,
+ copy_constructor and destrcutor) are passed, or that an element
+ size is given */
+ assert((copyfunc != NULL && copy_constructor != NULL && destructor != NULL)
+ || (element_size != 0));
+
+ distance = 0 ; /* This parameter is not currently used */
+ E = Ef(x0_p);
+
+ if (copyfunc) {
+ x = copy_constructor(x0_p);
+ new_x = copy_constructor(x0_p);
+ best_x = copy_constructor(x0_p);
+ } else {
+ x = (void *) malloc (element_size);
+ memcpy (x, x0_p, element_size);
+ new_x = (void *) malloc (element_size);
+ best_x = (void *) malloc (element_size);
+ memcpy (best_x, x0_p, element_size);
+ }
+
+ best_E = E;
+
+ T = params.t_initial;
+ done = 0;
+
+ if (print_position) {
+ printf ("#-iter #-evals temperature position energy\n");
+ }
+
+ while (!done) {
+
+ n_accepts = 0;
+ n_rejects = 0;
+ n_eless = 0;
+ for (i = 0; i < params.iters_fixed_T; ++i) {
+ if (copyfunc) {
+ copyfunc(x, new_x);
+ } else {
+ memcpy (new_x, x, element_size);
+ }
+
+ take_step (r, new_x, params.step_size);
+ new_E = Ef (new_x);
+
+ if(new_E <= best_E){
+ if (copyfunc) {
+ copyfunc(new_x,best_x);
+ } else {
+ memcpy (best_x, new_x, element_size);
+ }
+ best_E=new_E;
+ }
+
+ ++n_evals; /* keep track of Ef() evaluations */
+ /* now take the crucial step: see if the new point is accepted
+ or not, as determined by the boltzman probability */
+ if (new_E < E) {
+ /* yay! take a step */
+ if (copyfunc) {
+ copyfunc(new_x, x);
+ } else {
+ memcpy (x, new_x, element_size);
+ }
+ E = new_E;
+ ++n_eless;
+ } else if (gsl_rng_uniform(r) < safe_exp (-(new_E - E)/(params.k * T)) ) {
+ /* yay! take a step */
+ if (copyfunc) {
+ copyfunc(new_x, x);
+ } else {
+ memcpy(x, new_x, element_size);
+ }
+ E = new_E;
+ ++n_accepts;
+ } else {
+ ++n_rejects;
+ }
+ }
+
+ if (print_position) {
+ /* see if we need to print stuff as we go */
+ /* printf("%5d %12g %5d %3d %3d %3d", n_iter, T, n_evals, */
+ /* 100*n_eless/n_steps, 100*n_accepts/n_steps, */
+ /* 100*n_rejects/n_steps); */
+ printf ("%5d %7d %12g", n_iter, n_evals, T);
+ print_position (x);
+ printf (" %12g\n", E);
+ }
+
+ /* apply the cooling schedule to the temperature */
+ /* FIXME: I should also introduce a cooling schedule for the iters */
+ T /= params.mu_t;
+ ++n_iter;
+ if (T < params.t_min) {
+ done = 1;
+ }
+ }
+
+ /* at the end, copy the result onto the initial point, so we pass it
+ back to the caller */
+ if (copyfunc) {
+ copyfunc(best_x, x0_p);
+ } else {
+ memcpy (x0_p, best_x, element_size);
+ }
+
+ if (copyfunc) {
+ destructor(x);
+ destructor(new_x);
+ destructor(best_x);
+ } else {
+ free (x);
+ free (new_x);
+ free (best_x);
+ }
+}
+
+/* implementation of a simulated annealing algorithm with many tries */
+
+void
+gsl_siman_solve_many (const gsl_rng * r, void *x0_p, gsl_siman_Efunc_t Ef,
+ gsl_siman_step_t take_step,
+ gsl_siman_metric_t distance,
+ gsl_siman_print_t print_position,
+ size_t element_size,
+ gsl_siman_params_t params)
+{
+ /* the new set of trial points, and their energies and probabilities */
+ void *x, *new_x;
+ double *energies, *probs, *sum_probs;
+ double Ex; /* energy of the chosen point */
+ double T; /* the temperature */
+ int i, done;
+ double u; /* throw the die to choose a new "x" */
+ int n_iter;
+
+ if (print_position) {
+ printf ("#-iter temperature position");
+ printf (" delta_pos energy\n");
+ }
+
+ x = (void *) malloc (params.n_tries * element_size);
+ new_x = (void *) malloc (params.n_tries * element_size);
+ energies = (double *) malloc (params.n_tries * sizeof (double));
+ probs = (double *) malloc (params.n_tries * sizeof (double));
+ sum_probs = (double *) malloc (params.n_tries * sizeof (double));
+
+ T = params.t_initial;
+/* memcpy (x, x0_p, element_size); */
+ memcpy (x, x0_p, element_size);
+ done = 0;
+
+ n_iter = 0;
+ while (!done)
+ {
+ Ex = Ef (x);
+ for (i = 0; i < params.n_tries - 1; ++i)
+ { /* only go to N_TRIES-2 */
+ /* center the new_x[] around x, then pass it to take_step() */
+ sum_probs[i] = 0;
+ memcpy ((char *)new_x + i * element_size, x, element_size);
+ take_step (r, (char *)new_x + i * element_size, params.step_size);
+ energies[i] = Ef ((char *)new_x + i * element_size);
+ probs[i] = safe_exp (-(energies[i] - Ex) / (params.k * T));
+ }
+ /* now add in the old value of "x", so it is a contendor */
+ memcpy ((char *)new_x + (params.n_tries - 1) * element_size, x, element_size);
+ energies[params.n_tries - 1] = Ex;
+ probs[params.n_tries - 1] = safe_exp (-(energies[i] - Ex) / (params.k * T));
+
+ /* now throw biased die to see which new_x[i] we choose */
+ sum_probs[0] = probs[0];
+ for (i = 1; i < params.n_tries; ++i)
+ {
+ sum_probs[i] = sum_probs[i - 1] + probs[i];
+ }
+ u = gsl_rng_uniform (r) * sum_probs[params.n_tries - 1];
+ for (i = 0; i < params.n_tries; ++i)
+ {
+ if (u < sum_probs[i])
+ {
+ memcpy (x, (char *)new_x + i * element_size, element_size);
+ break;
+ }
+ }
+ if (print_position)
+ {
+ printf ("%5d\t%12g\t", n_iter, T);
+ print_position (x);
+ printf ("\t%12g\t%12g\n", distance (x, x0_p), Ex);
+ }
+ T /= params.mu_t;
+ ++n_iter;
+ if (T < params.t_min)
+ {
+ done = 1;
+ }
+ }
+
+ /* now return the value via x0_p */
+ memcpy (x0_p, x, element_size);
+
+ /* printf("the result is: %g (E=%g)\n", x, Ex); */
+
+ free (x);
+ free (new_x);
+ free (energies);
+ free (probs);
+ free (sum_probs);
+}