bpp-core3  3.0.0
DownhillSimplexMethod.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 #include "../NumTools.h"
7 
8 using namespace bpp;
9 using namespace std;
10 
11 /******************************************************************************/
12 
14 {
15  const DownhillSimplexMethod* dsm = dynamic_cast<const DownhillSimplexMethod*>(optimizer_);
16  double rTol = 2.0 * NumTools::abs(dsm->y_[dsm->iHighest_] - dsm->y_[dsm->iLowest_]) /
17  (NumTools::abs(dsm->y_[dsm->iHighest_]) + NumTools::abs(dsm->y_[dsm->iLowest_]));
18  return rTol;
19 }
20 
21 /******************************************************************************/
22 
23 DownhillSimplexMethod::DownhillSimplexMethod(std::shared_ptr<FunctionInterface> function) :
24  AbstractOptimizer(function), simplex_(), y_(), pSum_(), iHighest_(0), iNextHighest_(0), iLowest_(0)
25 {
26  // Default values:
27  nbEvalMax_ = 5000;
28  setDefaultStopCondition_(make_shared<DSMStopCondition>(this));
30 }
31 
32 /******************************************************************************/
33 
35 {
36  size_t nDim = getParameters().size();
37  nbEval_ = 0;
38 
39  // Initialize the simplex:
40  simplex_.resize(nDim + 1);
41  y_.resize(nDim + 1);
42  double lambda = 0.2; // 20% of the parameter value.
43  for (unsigned int i = 1; i < nDim + 1; i++)
44  {
45  // Copy the vector...
46  simplex_[i] = getParameters();
47  // ... and set the initial values.
48  for (unsigned int j = 0; j < nDim; j++)
49  {
50  // Hummm... that does not work when the first point is 0!!! where does this come from???
51  // simplex_[i][j].setValue(getParameters()[j].getValue() * (1. + (j == i - 1 ? lambda : 0.)));
52  simplex_[i][j].setValue(getParameters()[j].getValue() + (j == i - 1 ? lambda : 0.));
53  }
54  // Compute the corresponding f value:
55  y_[i] = getFunction()->f(simplex_[i]);
56  nbEval_++;
57  }
58  // Last function evaluation, setting current value:
59  simplex_[0] = getParameters();
60  y_[0] = getFunction()->f(simplex_[0]);
61  nbEval_++;
62 
63  pSum_ = getPSum();
64 }
65 
66 /******************************************************************************/
67 
69 {
70  // The number of dimensions of the parameter space:
71  size_t nDim = simplex_.getDimension();
72  size_t mpts = nDim + 1;
73 
74  iLowest_ = 0;
75  // First we must determine which point is the highest (worst),
76  // next-highest, and lowest (best), by looping over the points
77  // in the simplex.
78  if (y_[0] > y_[1])
79  {
80  iHighest_ = 0;
81  iNextHighest_ = 1;
82  }
83  else
84  {
85  iHighest_ = 1;
86  iNextHighest_ = 0;
87  }
88 
89  for (unsigned int i = 0; i < mpts; i++)
90  {
91  if (y_[i] <= y_[iLowest_])
92  iLowest_ = i;
93  if (y_[i] > y_[iHighest_])
94  {
96  iHighest_ = i;
97  }
98  else if (y_[i] > y_[iNextHighest_] && i != iHighest_)
99  iNextHighest_ = i;
100  }
101 
102  // Set current best point:
104 
105  // Begin a new iteration.
106  // First extrapolate by a factor -1 through the face of the simplex
107  // across from high point, i.e., reflect the simplex from the high point.</p>
108 
109  double yTry = tryExtrapolation(-1.0);
110  if (yTry <= y_[iLowest_])
111  {
112  // Expansion.
113  yTry = tryExtrapolation(2.0);
114  }
115  else if (yTry >= y_[iNextHighest_])
116  {
117  // Contraction.
118  double ySave = y_[iHighest_];
119  yTry = tryExtrapolation(0.5);
120  if (yTry >= ySave)
121  {
122  for (size_t i = 0; i < mpts; i++)
123  {
124  if (i != iLowest_)
125  {
126  for (size_t j = 0; j < nDim; j++)
127  {
128  pSum_[j].setValue(0.5 * (simplex_[i][j].getValue() + simplex_[iLowest_][j].getValue()));
129  simplex_[i][j].setValue(pSum_[j].getValue());
130  }
131  y_[i] = getFunction()->f(pSum_);
132  nbEval_++;
133  }
134  }
135  nbEval_ += static_cast<unsigned int>(nDim);
136  pSum_ = getPSum();
137  }
138  }
139 
140  return y_[iLowest_];
141 }
142 
143 /******************************************************************************/
144 
146 {
148 
149  // set best shot:
150  return getFunction()->f(simplex_[iLowest_]);
151 }
152 
153 /******************************************************************************/
154 
156 {
157  size_t ndim = simplex_.getDimension();
158  size_t mpts = ndim + 1;
159 
160  // Get a copy...
161  ParameterList pSum = getParameters();
162  // ... and initializes it.
163  for (size_t j = 0; j < ndim; j++)
164  {
165  double sum = 0.;
166  for (size_t i = 0; i < mpts; i++)
167  {
168  sum += simplex_[i][j].getValue();
169  }
170  pSum[j].setValue(sum);
171  }
172  return pSum;
173 }
174 
175 /******************************************************************************/
176 
178 {
179  size_t ndim = simplex_.getDimension();
180  double fac1, fac2, yTry;
181 
182  fac1 = (1.0 - fac) / static_cast<double>(ndim);
183  fac2 = fac1 - fac;
184 
185  // Get a copy...
186  ParameterList pTry = getParameters();
187  // and initialize it:
188  for (size_t j = 0; j < ndim; j++)
189  {
190  pTry[j].setValue(pSum_[j].getValue() * fac1 - simplex_[iHighest_][j].getValue() * fac2);
191  }
192  // Now compute the function for this new set of parameters:
193  yTry = getFunction()->f(pTry);
194  nbEval_++;
195 
196  // Then test this new point:
197  if (yTry < y_[iHighest_])
198  {
199  y_[iHighest_] = yTry;
200  for (size_t j = 0; j < ndim; j++)
201  {
202  pSum_[j].setValue(pSum_[j].getValue() + pTry[j].getValue() - simplex_[iHighest_][j].getValue());
203  simplex_[iHighest_][j].setValue(pTry[j].getValue());
204  }
205  }
206  return yTry;
207 }
208 
209 /******************************************************************************/
double optimize() override
Basic implementation.
double optimize()
Multidimensional minimization of the function function_ by the downhill simplex method of Nelder and ...
ParameterList getPSum()
Update the pSum_ variable.
void doInit(const ParameterList &params)
This function is called by the init() method and contains all calculations.
size_t size() const
Definition: ParameterList.h:56
STL namespace.
void setDefaultStopCondition_(std::shared_ptr< OptimizationStopCondition > osc)
ParameterList & getParameters_()
const ParameterList & getParameters() const override
double getCurrentTolerance() const
Get the current tolerance.
The parameter list object.
Definition: ParameterList.h:27
double tryExtrapolation(double fac)
Extrapolates by a factor fac through the face of the simplex from the high point. Try the new point a...
double doStep()
This function is called by the step() method and contains all calculations.
DownhillSimplexMethod(std::shared_ptr< FunctionInterface > function)
Build a new Downhill Simplex optimizer.
unsigned int nbEvalMax_
The maximum number of function evaluations allowed.
unsigned int nbEval_
The current number of function evaluations achieved.
Partial implementation of the Optimizer interface.
std::shared_ptr< const FunctionInterface > getFunction() const override
Get the current function being optimized.
std::shared_ptr< OptimizationStopCondition > getDefaultStopCondition() override
Get the default stop condition of the optimization algorithm.
void setStopCondition(std::shared_ptr< OptimizationStopCondition > stopCondition) override
Set the stop condition of the optimization algorithm.
static T abs(T a)
Get the magnitude of a value.
Definition: NumTools.h:31
This implements the Downhill Simplex method in multidimensions.