| 1 |
;; Simulated Annealing |
|---|
| 2 |
;; Liam Healy Sun Feb 11 2007 - 17:23 |
|---|
| 3 |
;; Time-stamp: <2008-03-15 23:10:25EDT simulated-annealing.lisp> |
|---|
| 4 |
;; $Id$ |
|---|
| 5 |
|
|---|
| 6 |
(in-package :gsl) |
|---|
| 7 |
|
|---|
| 8 |
;;; This does not work. |
|---|
| 9 |
;;; Step size passed to the step function is incorrect. |
|---|
| 10 |
;;; Print function is ignored, but probably couldn't work if it weren't. |
|---|
| 11 |
;;; Does not converge. |
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
(cffi:defcstruct simulated-annealing-parameters |
|---|
| 15 |
(n-tries :int) ; how many points to try for each step |
|---|
| 16 |
(iterations-fixed-T :int) ; how many iterations at each temperature? |
|---|
| 17 |
(step-size :double) ; max step size in the random walk |
|---|
| 18 |
;; The following parameters are for the Boltzmann distribution |
|---|
| 19 |
(k :double) |
|---|
| 20 |
(t-initial :double) |
|---|
| 21 |
(mu-t :double) |
|---|
| 22 |
(t-min :double)) |
|---|
| 23 |
|
|---|
| 24 |
(defmacro with-simulated-annealing-parameters |
|---|
| 25 |
((name number-of-tries iterations-per-temperature |
|---|
| 26 |
step-size &optional k t-initial mu-t t-min) |
|---|
| 27 |
&body body) |
|---|
| 28 |
`(cffi:with-foreign-object (,name 'simulated-annealing-parameters) |
|---|
| 29 |
(setf |
|---|
| 30 |
(cffi:foreign-slot-value |
|---|
| 31 |
,name 'simulated-annealing-parameters 'n-tries) |
|---|
| 32 |
,number-of-tries |
|---|
| 33 |
(cffi:foreign-slot-value |
|---|
| 34 |
,name 'simulated-annealing-parameters 'iterations-fixed-T) |
|---|
| 35 |
,iterations-per-temperature |
|---|
| 36 |
(cffi:foreign-slot-value |
|---|
| 37 |
,name 'simulated-annealing-parameters 'step-size) |
|---|
| 38 |
,step-size |
|---|
| 39 |
;; The following parameters are for the Boltzmann distribution |
|---|
| 40 |
(cffi:foreign-slot-value |
|---|
| 41 |
,name 'simulated-annealing-parameters 'k) |
|---|
| 42 |
,k |
|---|
| 43 |
(cffi:foreign-slot-value |
|---|
| 44 |
,name 'simulated-annealing-parameters 't-initial) |
|---|
| 45 |
,t-initial |
|---|
| 46 |
(cffi:foreign-slot-value |
|---|
| 47 |
,name 'simulated-annealing-parameters 'mu-t) |
|---|
| 48 |
,mu-t |
|---|
| 49 |
(cffi:foreign-slot-value |
|---|
| 50 |
,name 'simulated-annealing-parameters 't-min) |
|---|
| 51 |
,t-min) |
|---|
| 52 |
,@body)) |
|---|
| 53 |
|
|---|
| 54 |
(defmfun simulated-annealing |
|---|
| 55 |
(generator x0-p |
|---|
| 56 |
Ef take-step distance-function |
|---|
| 57 |
print-position |
|---|
| 58 |
;; copy-function copy-constructor destructor |
|---|
| 59 |
element-size parameters) |
|---|
| 60 |
"gsl_siman_solve" |
|---|
| 61 |
(((generator generator) :pointer) (x0-p :pointer) |
|---|
| 62 |
((cffi:get-callback Ef) :pointer) |
|---|
| 63 |
((cffi:get-callback take-step) :pointer) |
|---|
| 64 |
((cffi:get-callback distance-function) :pointer) |
|---|
| 65 |
((cffi:get-callback print-position) :pointer) |
|---|
| 66 |
((cffi:null-pointer) :pointer) |
|---|
| 67 |
((cffi:null-pointer) :pointer) |
|---|
| 68 |
((cffi:null-pointer) :pointer) |
|---|
| 69 |
;;((cffi:get-callback copy-function) :pointer) |
|---|
| 70 |
;;((cffi:get-callback copy-constructor) :pointer) |
|---|
| 71 |
;;((cffi:get-callback destructor) :pointer) |
|---|
| 72 |
(element-size size) (parameters simulated-annealing-parameters)) |
|---|
| 73 |
:c-return :void |
|---|
| 74 |
:documentation ; FDL |
|---|
| 75 |
"Perform a simulated annealing search through a given |
|---|
| 76 |
space. The space is specified by providing the functions Ef and |
|---|
| 77 |
distance. The simulated annealing steps are generated using the |
|---|
| 78 |
random number generator r and the function take-step. |
|---|
| 79 |
|
|---|
| 80 |
The starting configuration of the system should be given by x0-p |
|---|
| 81 |
The routine offers two modes for updating configurations, a fixed-size |
|---|
| 82 |
mode and a variable-size mode. In the fixed-size mode the configuration |
|---|
| 83 |
is stored as a single block of memory of size element-size |
|---|
| 84 |
The functions copy-function, |
|---|
| 85 |
copy-constructor and destructor should be NIL in |
|---|
| 86 |
fixed-size mode. In the variable-size mode the functions |
|---|
| 87 |
copy-function, copy-constructor and destructor are used to |
|---|
| 88 |
create, copy and destroy configurations internally. The variable |
|---|
| 89 |
element-size should be zero in the variable-size mode. |
|---|
| 90 |
|
|---|
| 91 |
The parameters structure (described below) controls the run by |
|---|
| 92 |
providing the temperature schedule and other tunable parameters to the |
|---|
| 93 |
algorithm. |
|---|
| 94 |
|
|---|
| 95 |
On exit the best result achieved during the search is placed in |
|---|
| 96 |
x0-p. If the annealing process has been successful this |
|---|
| 97 |
should be a good approximation to the optimal point in the space. |
|---|
| 98 |
|
|---|
| 99 |
If the function pointer print-position is not null, a debugging |
|---|
| 100 |
log will be printed to standard output with the following columns: |
|---|
| 101 |
number_of_iterations temperature x x-x0p Ef(x) |
|---|
| 102 |
and the output of the function print-position itself. If |
|---|
| 103 |
print-position is null then no information is printed. |
|---|
| 104 |
The simulated annealing routines require several user-specified |
|---|
| 105 |
functions to define the configuration space and energy function.") |
|---|
| 106 |
|
|---|
| 107 |
(defmacro def-energy-function (name) |
|---|
| 108 |
"Define an energy or distance fuction for simulated annealing." |
|---|
| 109 |
`(def-single-function ,name :double :pointer nil)) |
|---|
| 110 |
|
|---|
| 111 |
(defmacro def-step-function (name) |
|---|
| 112 |
"Define a step fuction for simulated annealing." |
|---|
| 113 |
(let ((generator (gensym "GEN")) |
|---|
| 114 |
(arguments (gensym "ARGS")) |
|---|
| 115 |
(step-size (gensym "SS"))) |
|---|
| 116 |
`(cffi:defcallback ,name :void |
|---|
| 117 |
((,generator :pointer) (,arguments :pointer) (,step-size :double)) |
|---|
| 118 |
(,name ,generator ,arguments ,step-size)))) |
|---|
| 119 |
|
|---|
| 120 |
(defmacro def-distance-function (name) |
|---|
| 121 |
"Define a metric distance fuction for simulated annealing." |
|---|
| 122 |
(let ((x (gensym "X")) |
|---|
| 123 |
(y (gensym "Y"))) |
|---|
| 124 |
`(cffi:defcallback ,name :double |
|---|
| 125 |
((,x :pointer) (,y :pointer)) |
|---|
| 126 |
(,name ,x ,y)))) |
|---|
| 127 |
|
|---|
| 128 |
(defmacro def-print-function (name) |
|---|
| 129 |
"Define a print function for simulated annealing." |
|---|
| 130 |
`(def-single-function ,name :int :pointer nil)) |
|---|
| 131 |
|
|---|
| 132 |
;;;;**************************************************************************** |
|---|
| 133 |
;;;; Example |
|---|
| 134 |
;;;;**************************************************************************** |
|---|
| 135 |
|
|---|
| 136 |
;;; Trivial example, Sec. 24.3.1 |
|---|
| 137 |
;;; This does not work. |
|---|
| 138 |
|
|---|
| 139 |
(defun M2 (cx cy) |
|---|
| 140 |
(with-c-double (cx x) |
|---|
| 141 |
(with-c-double (cy y) |
|---|
| 142 |
(abs (- x y))))) |
|---|
| 143 |
|
|---|
| 144 |
(defvar *sa-function-calls*) |
|---|
| 145 |
|
|---|
| 146 |
(defun E2 (arg) |
|---|
| 147 |
(with-c-double (arg x) |
|---|
| 148 |
(incf *sa-function-calls*) |
|---|
| 149 |
(when (> *sa-function-calls* 100) |
|---|
| 150 |
(error "too much")) |
|---|
| 151 |
(* (exp (- (expt (1- x) 2))) (sin (* 8 x))))) |
|---|
| 152 |
|
|---|
| 153 |
(defun S2 (generator parameters step-size) |
|---|
| 154 |
(with-c-double (parameters x) |
|---|
| 155 |
;;(format t "~&~d ~d" x step-size) |
|---|
| 156 |
(let ((step-size 10.0d0)) ; this is coming in wrong, so we fix it |
|---|
| 157 |
(let ((rand (uniform generator))) |
|---|
| 158 |
(setf x (+ x (- (* 2 rand step-size) step-size))))))) |
|---|
| 159 |
|
|---|
| 160 |
(defparameter *sa-example-print* nil) |
|---|
| 161 |
|
|---|
| 162 |
;;; Print functions are a problem because it is likely that the C |
|---|
| 163 |
;;; stdout and the CL *standard-output* are not the same stream. |
|---|
| 164 |
;;; Also, it seems to ignore that a function is supplied, and avoids |
|---|
| 165 |
;;; printing anything. |
|---|
| 166 |
(defun P2 (arg) |
|---|
| 167 |
(with-c-double (arg x) |
|---|
| 168 |
(when *sa-example-print* |
|---|
| 169 |
(format T "~&from P2: ~a" x)))) |
|---|
| 170 |
|
|---|
| 171 |
(def-energy-function E2) |
|---|
| 172 |
(def-distance-function M2) |
|---|
| 173 |
(def-step-function S2) |
|---|
| 174 |
(def-print-function P2) |
|---|
| 175 |
|
|---|
| 176 |
(defun simulated-annealing-example () |
|---|
| 177 |
(let ((*sa-function-calls* 0)) |
|---|
| 178 |
(rng-environment-setup) |
|---|
| 179 |
(cffi:with-foreign-object (initial :double) |
|---|
| 180 |
(setf (dcref initial) 15.5d0) |
|---|
| 181 |
(with-simulated-annealing-parameters |
|---|
| 182 |
(params 200 10 10.0d0 1.0d0 0.002d0 1.005d0 2.0d-6) |
|---|
| 183 |
(simulated-annealing |
|---|
| 184 |
(make-random-number-generator) initial |
|---|
| 185 |
'E2 'S2 'M2 'P2 |
|---|
| 186 |
(cffi:foreign-type-size :double) |
|---|
| 187 |
params))))) |
|---|
| 188 |
|
|---|