bpp-core3  3.0.0
BfgsMultiDimensions.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 "BfgsMultiDimensions.h"
7 
8 using namespace bpp;
9 
10 /******************************************************************************/
11 
12 BfgsMultiDimensions::BfgsMultiDimensions(std::shared_ptr<FirstOrderDerivable> function) :
13  AbstractOptimizer(function),
14  // gtol_(gtol),
15  slope_(0),
16  Up_(),
17  Lo_(),
18  p_(),
19  gradient_(),
20  xi_(),
21  dg_(),
22  hdg_(),
23  hessian_(),
24  f1dim_(new DirectionFunction(function))
25 {
26  setDefaultStopCondition_(make_shared<FunctionStopCondition>(this));
29 }
30 
31 /******************************************************************************/
32 
34 {
35  size_t nbParams = params.size();
36  p_.resize(nbParams);
37  gradient_.resize(nbParams);
38  xi_.resize(nbParams);
39  dg_.resize(nbParams);
40  hdg_.resize(nbParams);
41  Up_.resize(nbParams);
42  Lo_.resize(nbParams);
43 
44  hessian_.resize(nbParams);
45  for (size_t i = 0; i < nbParams; i++)
46  {
47  hessian_[i].resize(nbParams);
48  }
49 
50  for (size_t i = 0; i < nbParams; i++)
51  {
52  auto cp = params[i].getConstraint();
53  if (!cp)
54  {
57  }
58  else
59  {
60  Up_[i] = cp->getAcceptedLimit(NumConstants::VERY_BIG()) - NumConstants::TINY();
61  Lo_[i] = cp->getAcceptedLimit(-NumConstants::VERY_BIG()) + NumConstants::TINY();
62  }
63  }
64 
66  function().setParameters(params);
67 
69 
70  for (size_t i = 0; i < nbParams; ++i)
71  {
72  p_[i] = getParameters()[i].getValue();
73 
74  for (size_t j = 0; j < nbParams; ++j)
75  {
76  hessian_[i][j] = 0.0;
77  }
78  hessian_[i][i] = 1.0;
79  }
80 
81 
82  // jdutheil 01/09/22: what is this for?
83  // double sum = 0;
84  // for (size_t i = 0; i < nbParams; i++)
85  // {
86  // sum += p_[i] * p_[i];
87  // }
88 }
89 
90 /******************************************************************************/
91 
93 {
94  double f;
95  size_t n = getParameters().size();
96  // Loop over iterations.
97 
98  unsigned int i;
99 
100  for (i = 0; i < n; ++i)
101  {
102  p_[i] = getParameters()[i].getValue();
103  }
104 
105  setDirection();
106 
109  getParameters_(), xi_,
110  gradient_,
111  // getStopCondition()->getTolerance(),
112  0, 0,
113  getVerbose() > 0 ? getVerbose() - 1 : 0);
115 
116  for (i = 0; i < n; ++i)
117  {
118  xi_[i] = getParameters_()[i].getValue() - p_[i];
119  }
120 
121  f = getFunction()->f(getParameters());
122  if (f > currentValue_)
123  {
124  printMessage("!!! Function increase !!!");
125  printMessage("!!! Optimization might have failed. Try to reparametrize your function to remove constraints.");
126  tolIsReached_ = true;
127  return f;
128  }
129 
130  if (tolIsReached_)
131  {
132  return f;
133  }
134 
135  // double temp, test = 0.0;
136  // for (i = 0; i < n; i++)
137  // {
138  // temp = xi_[i];
139  // if (p_[i] > 1.0)
140  // temp /= p_[i];
141  // if (temp > test)
142  // test = temp;
143  // }
144 
145  // if (test < 1e-7)
146  // {
147  // tolIsReached_ = true;
148  // return f;
149  // }
150 
151  for (i = 0; i < n; i++)
152  {
153  dg_[i] = gradient_[i];
154  }
155 
157  // test = 0.0;
158 
159  // for (i = 0; i < n; i++)
160  // {
161  // temp = abs(gradient_[i]);
162  // if (abs(p_[i]) > 1.0)
163  // temp /= p_[i];
164  // if (temp > test)
165  // test = temp;
166  // }
167 
168  // if (f > 1.0)
169  // test /= f;
170 
171  // if (test < gtol_)
172  // {
173  // tolIsReached_ = true;
174  // return f;
175  // }
176 
177  for (i = 0; i < n; i++)
178  {
179  dg_[i] = gradient_[i] - dg_[i];
180  }
181 
182  for (i = 0; i < n; i++)
183  {
184  hdg_[i] = 0;
185  for (unsigned int j = 0; j < n; j++)
186  {
187  hdg_[i] += hessian_[i][j] * dg_[j];
188  }
189  }
190 
191  double fae(0), fac(0), sumdg(0), sumxi(0);
192 
193  for (i = 0; i < n; i++)
194  {
195  fac += dg_[i] * xi_[i];
196  fae += dg_[i] * hdg_[i];
197  sumdg += dg_[i] * dg_[i];
198  sumxi += xi_[i] * xi_[i];
199  }
200 
201  if (fac > sqrt(1e-7 * sumdg * sumxi))
202  {
203  fac = 1.0 / fac;
204  double fad = 1.0 / fae;
205  for (i = 0; i < n; i++)
206  {
207  dg_[i] = fac * xi_[i] - fad * hdg_[i];
208  }
209  for (i = 0; i < n; i++)
210  {
211  for (unsigned int j = i; j < n; j++)
212  {
213  hessian_[i][j] += fac * xi_[i] * xi_[j] - fad * hdg_[i] * hdg_[j] + fae * dg_[i] * dg_[j];
214  hessian_[j][i] = hessian_[i][j];
215  }
216  }
217  }
218 
219  return f;
220 }
221 
222 /******************************************************************************/
223 
224 void BfgsMultiDimensions::getGradient(std::vector<double>& gradient) const
225 {
226  for (unsigned int i = 0; i < gradient.size(); i++)
227  {
228  gradient[i] = firstOrderDerivableFunction().getFirstOrderDerivative(getParameters()[i].getName());
229  }
230 }
231 
232 /******************************************************************************/
233 
235 {
236  size_t nbParams = getParameters().size();
237 
238  for (size_t i = 0; i < nbParams; ++i)
239  {
240  xi_[i] = 0;
241  for (size_t j = 0; j < nbParams; ++j)
242  {
243  xi_[i] -= hessian_[i][j] * gradient_[j];
244  }
245  }
246 
247  double v = 1, alpmax = 1;
248  for (size_t i = 0; i < nbParams; ++i)
249  {
250  if ((xi_[i] > 0) && (p_[i] + NumConstants::TINY() * xi_[i] < Up_[i]))
251  v = (Up_[i] - p_[i]) / xi_[i];
252  else if ((xi_[i] < 0) && (p_[i] + NumConstants::TINY() * xi_[i] > Lo_[i]))
253  v = (Lo_[i] - p_[i]) / xi_[i];
254  if (v < alpmax)
255  alpmax = v;
256  }
257 
258  for (size_t i = 0; i < nbParams; i++)
259  {
260  if (p_[i] + NumConstants::TINY() * xi_[i] >= Up_[i])
261  xi_[i] = Up_[i] - p_[i];
262  else if (p_[i] + NumConstants::TINY() * xi_[i] <= Lo_[i])
263  xi_[i] = Lo_[i] - p_[i];
264  else
265  xi_[i] *= alpmax;
266  }
267 }
const FirstOrderDerivable & firstOrderDerivableFunction() const
BfgsMultiDimensions(std::shared_ptr< FirstOrderDerivable > function)
virtual void enableFirstOrderDerivatives(bool yn)=0
Tell if derivatives must be computed.
size_t size() const
Definition: ParameterList.h:56
void setDefaultStopCondition_(std::shared_ptr< OptimizationStopCondition > osc)
ParameterList & getParameters_()
const ParameterList & getParameters() const override
void doInit(const ParameterList &params) override
This function is called by the init() method and contains all calculations.
The parameter list object.
Definition: ParameterList.h:27
bool tolIsReached_
Tell if the tolerance level has been reached.
virtual double getFirstOrderDerivative(const std::string &variable) const =0
Get the derivative of the function at the current point.
std::shared_ptr< DirectionFunction > f1dim_
void setOptimizationProgressCharacter(const std::string &c)
Set the character to be displayed during optimization.
unsigned int getVerbose() const override
Get the verbose level.
double doStep() override
This function is called by the step() method and contains all calculations.
static double TINY()
Definition: NumConstants.h:46
static double VERY_BIG()
Definition: NumConstants.h:48
unsigned int nbEval_
The current number of function evaluations achieved.
Partial implementation of the Optimizer interface.
double currentValue_
The current value of the function.
void getGradient(std::vector< double > &gradient) const
static unsigned int lineSearch(std::shared_ptr< DirectionFunction > f1dim, ParameterList &parameters, std::vector< double > &xi, std::vector< double > &gradient, std::shared_ptr< OutputStream > profiler=nullptr, std::shared_ptr< OutputStream > messenger=nullptr, unsigned int verbose=2)
Search a &#39;sufficiently low&#39; value for a function in a given direction.
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 printMessage(const std::string &message)
Give a message to print to the message handler.
void setStopCondition(std::shared_ptr< OptimizationStopCondition > stopCondition) override
Set the stop condition of the optimization algorithm.