OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
Simplex.cpp
Go to the documentation of this file.
1 // ------------------------------------------------------------------------
2 // $RCSfile: Simplex.cpp,v $
3 // ------------------------------------------------------------------------
4 // $Revision: 1.2 $
5 // ------------------------------------------------------------------------
6 // Copyright: see Copyright.readme
7 // ------------------------------------------------------------------------
8 //
9 // Class: Simplex
10 // This class encapsulates a minimisation according to the SIMPLEX method
11 // taken from the MINUIT package.
12 //
13 // ------------------------------------------------------------------------
14 //
15 // $Date: 2001/08/13 15:10:01 $
16 // $Author: jowett $
17 //
18 // ------------------------------------------------------------------------
19 
20 #include "Match/Simplex.h"
21 #include "Algebra/Matrix.h"
22 #include "Algebra/Vector.h"
23 #include "Attributes/Attributes.h"
24 #include "Match/Match.h"
26 #include "Utilities/Round.h"
27 #include <cfloat>
28 #include <cmath>
29 #include <numeric>
30 
31 
32 // Class Simplex
33 // ------------------------------------------------------------------------
34 
35 namespace {
36  // The attributes of class Simplex.
37  enum {
38  TOLERANCE, // The desired tolerance.
39  CALLS, // The maximum number of calls to the matching functions.
40  SIZE
41  };
42 
43  // Auxiliary functions for returning the minimum or maximum.
44  inline double minfun(double x, double y)
45  { return x < y ? x : y; }
46 
47  inline double maxfun(double x, double y)
48  { return x > y ? x : y; }
49 }
50 
51 
53  Action(SIZE, "SIMPLEX",
54  "The \"SIMPLEX\" sub-command adjusts parameters according to the "
55  "\"SIMPLEX\" method taken from MINUIT.") {
56  itsAttr[TOLERANCE] = Attributes::makeReal
57  ("TOLERANCE", "The desired tolerance", 1.0e-6);
59  ("CALLS", "Maximum number of calls to the matching functions", 1000.);
60 
62 }
63 
64 
65 Simplex::Simplex(const std::string &name, Simplex *parent):
66  Action(name, parent)
67 {}
68 
69 
71 {}
72 
73 
74 Simplex *Simplex::clone(const std::string &name) {
75  return new Simplex(name, this);
76 }
77 
78 
80  // Built-in constants.
81  static const char method[] = "SIMPLEX";
82  static const double alpha = 1.0;
83  static const double beta = 0.5;
84  static const double gamma = 2.0;
85  static const double rhomin = 4.0;
86  static const double rhomax = 8.0;
87  static const double rho1 = 1.0 + alpha;
88  static const double rho2 = rho1 + alpha * gamma;
89 
90  // Working storage.
91 
92  /*
93  ada 15-6-2000
94 
95  double fnorm;
96 
97  else if ((fnorm = euclidean_norm(F)) <= tol) {
98 
99  */
100 
101 
102 
103  int n = Match::block->countVariables();
104  int m = Match::block->countFunctions();
105  Vector<double> X(n);
106  Vector<double> F(m);
107  double tol = std::max(Attributes::getReal(itsAttr[TOLERANCE]), DBL_EPSILON);
108  MatchState state = START;
109 
110  // Initial function evaluation.
112  if(! Match::block->evaluate(X, F)) {
113  state = FAILED;
114  } else if(euclidean_norm(F) <= tol) {
115  state = CONVERGED;
116  } else {
117  // Fetch command attributes.
118  int nfcnmax = int(Round(Attributes::getReal(itsAttr[CALLS])));
119 
120  // Set up the simplex.
121  Fsim = Array1D<double>(n + 1);
122  Xsim = Array1D< Vector<double> >(n + 1);
123 
124  Vector<double> dX(0.001 * X);
125  double Fmin = F * F;
126  state = START;
127 
128  // Outer loop: start/restart algorithm.
129  do {
130  // Keep initial point in Xbar/Fbar.
131  Vector<double> Xbar = X;
132  double Fbar = Fmin;
133 
134  for(int i = 0; i < n; ++i) {
135  double Xsave = X(i);
136  double Fsave = Fmin;
137  double step = dX(i);
138 
139  // Find proper initial direction and step.
140  int idir;
141  for(idir = 1; idir <= 12; ++idir) {
142  X(i) = Xsave + step;
143  if(Match::block->evaluate(X, F) && (Fmin = F * F) <= Fsave) break;
144  if(idir % 2 == 0) step *= 0.1;
145  step = - step;
146  }
147 
148  if(idir <= 12) {
149  // Improvement found; try increasing steps.
150  for(int ns = 1; ns <= 3; ++ns) {
151  Xsave = X(i);
152  Fsave = Fmin;
153  step *= 3.0;
154  X(i) += step;
155 
156  // If new point is not an improvement,
157  // restore previous best point and quit.
158  if(! Match::block->evaluate(X, F) || (Fmin = F * F) > Fsave) {
159  X(i) = Xsave;
160  Fmin = Fsave;
161  break;
162  }
163  }
164  }
165 
166  // Store local minimum in i'th direction as vertex i.
167  Fsim(i) = Fmin;
168  Xsim(i) = X;
169  }
170 
171  // Store initial point as vertex n.
172  jh = jl = n;
173  razzia(Fbar, Xbar);
174 
175  // Extract best point of simplex.
176  X = Xsim(jl);
177  Fmin = Fsim(jl);
179 
180  // Inner loop: perform algorithm on simplex.
181  bool restart = false;
182  while(Fmin > tol) {
183  // Iteration print-out.
184  Match::block->print(method, state);
185 
186  // Test for call limit.
187  if(Match::block->getCallCount() >= nfcnmax) {
188  state = CALL_LIMIT;
189  } else {
190  // Calculate Xbar and X*.
191  Xbar = std::accumulate
192  (Xsim.begin(), Xsim.end(), - Xsim(jh)) / double(n);
193  Vector<double> Xstar = Xbar + alpha * (Xbar - Xsim(jh));
194  double Fstar = 2.0 * Fsim(jh);
195  int jhold = jh;
196 
197  if(Match::block->evaluate(Xstar, F)) {
198  if((Fstar = F * F) < Fsim(jl)) {
199  // Point X* is better than previous best point;
200  // try expanded point X**.
201  Vector<double> Xstst = Xbar + gamma * (Xstar - Xbar);
202  double Fstst = 0.0;
203  double rho = 0.0;
204 
205  if(Match::block->evaluate(Xstst, F)) {
206  // Fit a parabola through Fsim(jh), f*, f**; minimum = rho.
207  Fstst = F * F;
208  double F1 = (Fstar - Fsim(jh)) * rho2;
209  double F2 = (Fstst - Fsim(jh)) * rho1;
210  rho = 0.5 * (rho2 * F1 - rho1 * F2) / (F1 - F2);
211  }
212 
213  if(rho < rhomin) {
214  // Minimum inexistent or too close to pbar;
215  // Use X** if it gives improvement; otherwise use X*.
216  if(Fstst < Fsim(jl)) {
217  razzia(Fstst, Xstst);
218  } else {
219  razzia(Fstar, Xstar);
220  }
221  } else {
222  // Usable minimum found.
223  if(rho > rhomax) rho = rhomax;
224 
225  Vector<double> Xrho = Xsim(jh) + rho * (Xbar - Xsim(jh));
226  double Frho;
227 
228  // Select farthest point which gives decent improvement.
229  if(Match::block->evaluate(Xrho, F) &&
230  (Frho = F * F) < Fsim(jl) &&
231  Frho < Fstst) {
232  razzia(Frho, Xrho);
233  } else if(Fstst < Fsim(jl)) {
234  razzia(Fstst, Xstst);
235  } else {
236  razzia(Fstar, Xstar);
237  }
238  }
239  } else {
240  // F* is higher than Fsim(jl).
241  if(Fstar < Fsim(jh)) razzia(Fstar, Xstar);
242 
243  // If F* is still highest value, try contraction,
244  // giving point X**.
245  if(jhold == jh) {
246  Vector<double> Xstst = Xbar + beta * (Xsim(jh) - Xbar);
247  double Fstst;
248 
249  if(Match::block->evaluate(Xstst, F) &&
250  (Fstst = F * F) < Fsim(jh)) {
251  razzia(Fstst, Xstst);
252  } else {
253  restart = true;
254  }
255  }
256  }
257  }
258 
259  // Extract best point as new minimum.
260  Fmin = Fsim(jl);
261  X = Xsim(jl);
263  }
264 
265  if(restart) break;
266  }
267 
268  // Test for convergence.
269  if(restart) {
270  // Main loop must be restarted.
271  state = (state == RESTART) ? FAILED : RESTART;
272  restart = false;
273  } else {
274  // Recompute step sizes.
275  if(Fmin >= 2.0 * (tol + DBL_EPSILON)) {
276  Vector<double> Xmin(Xsim(0));
277  Vector<double> Xmax(Xsim(0));
278 
279  for(int j = 1; j < n; ++j) {
280  std::transform(Xmin.begin(), Xmin.end(), Xsim(j).begin(),
281  Xmin.begin(), minfun);
282  std::transform(Xmax.begin(), Xmax.end(), Xsim(j).begin(),
283  Xmax.begin(), maxfun);
284  }
285 
286  dX = Xmax - Xmin;
287  } else {
288  state = CONVERGED;
289  }
290  }
291  } while(state < CONVERGED);
292  }
293 
294  // Final print-out.
295  Match::block->print(method, state);
296 }
297 
298 
299 void Simplex::razzia(double Fnew, Vector<double> &Xnew) {
300  // Replace vertex with highest function value.
301  Xsim(jh) = Xnew;
302  Fsim(jh) = Fnew;
303 
304  // Find indices of lowest and highest function value.
305  jl = 0;
306  jh = 0;
307  int n = Match::block->countVariables();
308  for(int j = 1; j <= n; ++j) {
309  if(Fsim(j) < Fsim(jl)) jl = j;
310  if(Fsim(j) > Fsim(jh)) jh = j;
311  }
312 }
double Round(double value)
Round the double argument.
Definition: Round.cpp:23
virtual void execute()
Execute the command.
Definition: Simplex.cpp:79
constexpr double e
The value of .
Definition: Physics.h:40
void razzia(double Fnew, Vector< double > &Xnew)
Definition: Simplex.cpp:299
Simplex()
Exemplar constructor.
Definition: Simplex.cpp:52
MatchState
The possible states of a matching process.
Definition: MatchState.h:29
int jh
Definition: Simplex.h:66
The base class for all OPAL actions.
Definition: Action.h:30
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
Definition: rbendmap.h:8
virtual ~Simplex()
Definition: Simplex.cpp:70
iterator end()
Get end of data.
Definition: Array1D.h:210
static Match * block
The block of match data.
Definition: Match.h:100
int countFunctions() const
Return total number of functions.
Definition: Match.cpp:140
std::vector< Attribute > itsAttr
The object attributes (see Attribute.hh).
Definition: Object.h:214
void setVariables(const Vector< double > &x)
Set values of matching variables.
Definition: Match.cpp:93
constexpr double alpha
The fine structure constant, no dimension.
Definition: Physics.h:79
void print(const char *method, MatchState state)
Print the results of minimisation.
Definition: Match.cpp:145
int countVariables() const
Get total number of variables.
Definition: Match.cpp:106
iterator begin()
Get beginning of data.
Definition: Array1D.h:204
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition: Object.cpp:194
Array1D< double > Fsim
Definition: Simplex.h:63
Array1D< Vector< double > > Xsim
Definition: Simplex.h:62
int jl
Definition: Simplex.h:66
virtual Simplex * clone(const std::string &name)
Make clone.
Definition: Simplex.cpp:74
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
const std::string name
double getReal(const Attribute &attr)
Return real value.
Definition: Attributes.cpp:217
void getVariables(Vector< double > &x) const
Get values of matching variables.
Definition: Match.cpp:82
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:205
The SIMPLEX command.
Definition: Simplex.h:34