| Bsoft 2.0.5 Bernard's software package

simplex.cpp
Go to the documentation of this file.
1
11 #include "simplex.h"
12 #include "random_numbers.h"
13 #include "utilities.h"
14
15 // Declaration of global variables
16 extern int verbose; // Level of output to the screen
17
18
33 Bsimplex::Bsimplex(long nv, long np, long nc, long n, vector<double>& ax, vector<double>& ay)
34 {
35 if ( np < 1 ) {
36 error_show("Error in Bsimplex::Bsimplex: Zero parameters!", __FILE__, __LINE__);
37 return;
38 }
39
40 nvar = nv;
41 nparam = np;
42 nconstant = nc;
43 npoint = n;
44
45 if ( nparam && nvar ) x = ax;
46
47 if ( npoint ) fx = ay;
48
49 param.resize(nparam, 0);
50 lo.resize(nparam, 0);
51 hi.resize(nparam, 0);
52
53 if ( nconstant ) c.resize(nconstant, 0);
54 }
55
76 double Bsimplex::run(long maxcycles, double tolerance, double (funk)(Bsimplex&))
77 {
78 long i, j, k, npnt(nparam + 1), cycle(0);
79 long converged(0), ilo(0), inhi(1), ihi(2);
80 long rand_max = get_rand_max(); // My own random maximum due to system differences
81 double r, Rtry, Rsave, reltol(tolerance/10);
82
83 if ( maxcycles < 100 ) maxcycles = 100;
84
85 random_seed();
86
87 if ( verbose & VERB_DEBUG )
88 for ( i=0; i<10; i++ )
89 cout << "DEBUG Bsimplex::run: Random: " <<
90 rand_max << " " << random() << " " << exp(random()*4.0/rand_max-2.0) << endl;
91
92 // Initialize the R's
93 vector<double> R(npnt, 0);
94 // for ( i=0; i<npnt; i++ ) R[i] = 0;
95 R[ihi] = 1e30;
96
97 for ( j=0; j<nparam; j++ ) {
98 if ( param[j] < lo[j] ) param[j] = lo[j];
99 if ( param[j] > hi[j] ) param[j] = hi[j];
100 }
101
102 // Initialize the simplex multiple point parameter array
103 vector<double> mp(npnt*nparam);
104 for ( j=0; j<nparam; j++ ) mp[j] = param[j]; // Set up the first point
105 for ( i=1; i<npnt; i++ ) { // Set up the other points
106 for ( j=0; j<nparam; j++ ) {
107 k = i*nparam+j;
108 r = random()*1.0/rand_max;
109 if ( lo.size() && hi.size() ) { // Stay within limits
110 mp[k] = lo[j] + (hi[j] - lo[j])*(0.25 + 0.5*r);
111 } else { // No limits are specified
112 if ( param[j] == 0 )
113 mp[k] = 2.0*r - 1.0;
114 else
115 mp[k] = param[j]*exp(4.0*r-2.0);
116 }
117 }
118 }
119
120 if ( verbose & VERB_FULL ) {
121 cout << "Cycle";
122 for ( j=0; j<nparam; j++ ) cout << "\tp" << j;
123 cout << "\tR" << endl;
124 }
125
126 while ( !converged ) {
127 for ( i=0; i<npnt; i++ ) { // Set up simplex points
128 for ( j=0; j<nparam; j++ ) param[j] = mp[i*nparam+j];
129 R[i] = (funk)(*this);
130 }
131 ilo = ihi = inhi = 0; // Rank the points
132 for ( i=0; i<npnt; i++ ) {
133 if ( R[i] <= R[ilo] ) ilo = inhi = i;
134 if ( R[i] > R[ihi] ) ihi = i;
135 }
136 for ( i=0; i<npnt; i++ )
137 if ( R[i] >= R[inhi] && i != ihi ) inhi = i;
138
139 // Exit here if the process converged
140 if ( cycle >= maxcycles || R[ihi] < tolerance ) {
141 converged = 1;
142 } else if ( (R[ihi]-R[ilo])/R[ilo] < reltol ) {
143 // Set the first point to the lowest
144 for ( j=0; j<nparam; j++ ) mp[j] = mp[ilo*nparam+j];
145 for ( i=1; i<npnt; i++ ) { // Randomize other points
146 for ( j=0; j<nparam; j++ ) {
147 k = i*nparam+j;
148 r = random()*1.0/rand_max;
149 if ( lo.size() && hi.size() ) { // Stay within limits
150 mp[k] = lo[j] + (hi[j] - lo[j])*(0.25 + 0.5*r);
151 } else { // If no limits are specified
152 if ( mp[k] == 0 )
153 mp[k] = 2.0*r - 1.0;
154 else
155 mp[k] = mp[k]*exp(4.0*r-2.0);
156 }
157 }
158 }
159 } else {
160 // Reflect the simplex opposite the highest point
161 Rtry = amotry(mp, R, ihi, -1.0, funk);
162 // If it is better, try an additional extrapolation
163 if ( Rtry <= R[ilo] )
164 Rtry = amotry(mp, R, ihi, 2.0, funk);
165 // If it is worse, contract around the lowest point
166 else if ( Rtry >= R[inhi] ) {
167 Rsave = R[ihi];
168 Rtry = amotry(mp, R, ihi, 0.5, funk);
169 if ( Rtry >= Rsave ) {
170 for ( i=0; i<npnt; i++ ) {
171 for ( j=0; j<nparam; j++ ) {
172 k = i*nparam+j;
173 param[j] = 0.5*(mp[k] + mp[ilo*nparam+j]);
174 mp[k] = param[j];
175 }
176 R[i] = (funk)(*this);
177 }
178 }
179 }
180 }
181 if ( verbose & VERB_FULL ) {
182 if ( cycle%1000 == 0 ) {
183 cout << cycle;
184 for ( j=0; j<nparam; j++ ) cout << tab << mp[ilo*nparam+j];
185 cout << tab << R[ilo] << endl;
186 }
187 }
188 if ( ! isfinite(R[ilo]) ) bexit(-1);
189 cycle++;
190 }
191
192 if ( verbose & VERB_DEBUG ) {
193 cout << "DEBUG Bsimplex::run: End conditions: " << cycle << " " << R[ihi] << " " << (R[ihi]-R[ilo])/(R[ihi]+R[ilo]) << endl;
194 for ( i=0; i<npnt; i++ ) { // Show simplex points
195 cout << "DEBUG Bsimplex::run: Final: ";
196 for ( j=0; j<nparam; j++ ) cout << " " << mp[i*nparam+j];
197 cout << " %g" << R[i] << endl;
198 }
199 }
200
201 for ( j=0; j<nparam; j++ ) param[j] = mp[ilo*nparam+j];
202
203 Rsave = R[ilo];
204
205 if ( verbose & VERB_FULL ) {
206 cout << "Simplex cycles used: " << cycle << endl;
207 cout << "Tolerance: " << tolerance << endl << endl;
208 }
209
210 return Rsave;
211 }
212
213 /*
214 @brief Generates new points in parameter space for the simplex function.
215 @param *mp multiple point matrix.
216 @param *R R vector.
217 @param ihi index of highest R.
218 @param fac direction and magnitude of simplex modification.
219 @fn (funk)(Bsimplex *) evaluation function returning an R value.
220 @return double an R value.
221
222 Downhill simplex method of Nelder and Mead.
223 Reference: Press W.H. et al (1992) Numerical Recipes in C.
224
225 **/
226 double Bsimplex::amotry(vector<double>& mp, vector<double>& R, long ihi, double fac,
227 double (funk)(Bsimplex&))
228 {
229 long i, j, npnt(nparam + 1);
230 double psum, pnew, Rtry;
231 double fac1((1 - fac)/nparam);
232 double fac2(fac1 - fac);
233
234 for ( j=0; j<nparam; j++ ) {
235 psum = 0;
236 for ( i=0; i<npnt; i++ ) psum += mp[i*nparam+j];
237 param[j] = mp[ihi*nparam+j];
238 pnew = psum*fac1 - mp[ihi*nparam+j]*fac2;
239 if ( lo.size() ) if ( pnew < lo[j] ) pnew = param[j];
240 if ( hi.size() ) if ( pnew > hi[j] ) pnew = param[j];
241 param[j] = pnew;
242 }
243
244 Rtry = (funk)(*this);
245
246 if ( Rtry <= R[ihi] ) {
247 R[ihi] = Rtry;
248 for ( j=0; j<nparam; j++ ) mp[ihi*nparam+j] = param[j];
249 }
250
251 return Rtry;
252 }
253
random_seed
long random_seed()
Gets a random seed and sets the flag.
Definition: random_numbers.cpp:41
utilities.h
Header file for general utilities.
Bsimplex
Structure used in the downhill simplex method.
Definition: simplex.h:42
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
Bsimplex::Bsimplex
Bsimplex()
Definition: simplex.h:55
Bsimplex::run
double run(long maxcycles, double tolerance, double(funk)(Bsimplex &))
Definition: simplex.cpp:76
Bsimplex::amotry
double amotry(vector< double > &mp, vector< double > &R, long ihi, double fac, double(funk)(Bsimplex &))
Definition: simplex.cpp:226
isfinite
bool isfinite(complex< T > &value)
get_rand_max
long get_rand_max()
Finds the maximum random number for a system.
Definition: random_numbers.cpp:22
random_numbers.h
Header file for functions for creating random images.
simplex.h
Nelder and Mead downhill simplex method for generalized parameter fitting.
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
bexit
int bexit(int value)
Exit function for cleanup and debugging.
Definition: utilities.cpp:273
verbose
int verbose
error_show
int error_show(string message, string file, int line)
Displays the error with file and line reference.
Definition: utilities.cpp:755
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21