bpp-core3  3.0.0
ThreePointsNumericalDerivative.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
6 
7 using namespace bpp;
8 using namespace std;
9 
11 {
12  if (computeD1_ && variables_.size() > 0)
13  {
14  if (function1_)
15  function1_->enableFirstOrderDerivatives(false);
16  if (function2_)
17  function2_->enableSecondOrderDerivatives(false);
18  function_->setParameters(parameters);
19  f2_ = function_->getValue();
20  if ((abs(f2_) >= NumConstants::VERY_BIG()) || std::isnan(f2_))
21  {
22  for (size_t i = 0; i < variables_.size(); ++i)
23  {
24  der1_[i] = log(-1);
25  der2_[i] = log(-1);
26  }
27  return;
28  }
29 
30  string lastVar;
31  bool functionChanged = false;
32  ParameterList p;
33  bool start = true;
34  for (size_t i = 0; i < variables_.size(); ++i)
35  {
36  string var = variables_[i];
37  if (!parameters.hasParameter(var))
38  continue;
39  if (!start)
40  {
41  vector<string> vars(2);
42  vars[0] = var;
43  vars[1] = lastVar;
44  p = parameters.createSubList(vars);
45  }
46  else
47  {
48  p = parameters.createSubList(var);
49  start = false;
50  }
51  lastVar = var;
52  functionChanged = true;
53  double value = function_->getParameterValue(var);
54  double h = -(1. + std::abs(value)) * h_;
55  if (abs(h) < p[0].getPrecision())
56  h = h < 0 ? -p[0].getPrecision() : p[0].getPrecision();
57  double hf1(0), hf3(0);
58  unsigned int nbtry = 0;
59 
60  // Compute f1_
61  while (hf1 == 0)
62  {
63  try
64  {
65  p[0].setValue(value + h);
66  function_->setParameters(p); // also reset previous parameter...
67 
68  p = p.createSubList(0);
69  f1_ = function_->getValue();
70  if ((abs(f1_) >= NumConstants::VERY_BIG()) || std::isnan(f1_))
71  throw ConstraintException("f1_ too large", &p[0], f1_);
72  else
73  hf1 = h;
74  }
75  catch (ConstraintException& ce)
76  {
77  if (++nbtry == 10) // no possibility to compute derivatives
78  break;
79  else if (h < 0)
80  h = -h; // try on the right
81  else
82  h /= -2; // try again on the left with smaller interval
83  }
84  }
85 
86  if (hf1 != 0)
87  {
88  // Compute f3_
89  if (h < 0)
90  h = -h; // on the right
91  else
92  h /= 2; // on the left with smaller interval
93 
94  nbtry = 0;
95  while (hf3 == 0)
96  {
97  try
98  {
99  p[0].setValue(value + h);
100  function_->setParameters(p); // also reset previous parameter...
101 
102  p = p.createSubList(0);
103  f3_ = function_->getValue();
104  if ((abs(f3_) >= NumConstants::VERY_BIG()) || std::isnan(f3_))
105  throw ConstraintException("f3_ too large", &p[0], f3_);
106  else
107  hf3 = h;
108  }
109  catch (ConstraintException& ce)
110  {
111  if (++nbtry == 10) // no possibility to compute derivatives
112  break;
113  else if (h < 0)
114  h = -h; // try on the right
115  else
116  h /= -2; // try again on the left with smaller interval
117  }
118  }
119  }
120 
121  if (hf3 == 0)
122  {
123  der1_[i] = log(-1);
124  der2_[i] = log(-1);
125  }
126  else
127  {
128  der1_[i] = (f1_ - f3_) / (hf1 - hf3);
129  der2_[i] = ((f1_ - f2_) / hf1 - (f3_ - f2_) / hf3) * 2 / (hf1 - hf3);
130  }
131  }
132 
133 
134  if (computeCrossD2_)
135  {
136  string lastVar1, lastVar2;
137  for (unsigned int i = 0; i < variables_.size(); i++)
138  {
139  string var1 = variables_[i];
140  if (!parameters.hasParameter(var1))
141  continue;
142  for (unsigned int j = 0; j < variables_.size(); j++)
143  {
144  if (j == i)
145  {
146  crossDer2_(i, j) = der2_[i];
147  continue;
148  }
149  string var2 = variables_[j];
150  if (!parameters.hasParameter(var2))
151  continue;
152 
153  vector<string> vars(2);
154  vars[0] = var1;
155  vars[1] = var2;
156  if (i > 0 && j > 0)
157  {
158  if (lastVar1 != var1 && lastVar1 != var2)
159  vars.push_back(lastVar1);
160  if (lastVar2 != var1 && lastVar2 != var2)
161  vars.push_back(lastVar2);
162  }
163  p = parameters.createSubList(vars);
164 
165  double value1 = function_->getParameterValue(var1);
166  double value2 = function_->getParameterValue(var2);
167  double h1 = (1. + std::abs(value1)) * h_;
168  double h2 = (1. + std::abs(value2)) * h_;
169 
170  // Compute 4 additional points:
171  try
172  {
173  p[0].setValue(value1 - h1);
174  p[1].setValue(value2 - h2);
175  function_->setParameters(p); // also reset previous parameter...
176  vector<size_t> tmp(2);
177  tmp[0] = 0;
178  tmp[1] = 1;
179  p = p.createSubList(tmp); // removed the previous parameters.
180  f11_ = function_->getValue();
181 
182  p[1].setValue(value2 + h2);
183  function_->setParameters(p.createSubList(1));
184  f12_ = function_->getValue();
185 
186  p[0].setValue(value1 + h1);
187  function_->setParameters(p.createSubList(0));
188  f22_ = function_->getValue();
189 
190  p[1].setValue(value2 - h2);
191  function_->setParameters(p.createSubList(1));
192  f21_ = function_->getValue();
193 
194  crossDer2_(i, j) = ((f22_ - f21_) - (f12_ - f11_)) / (4 * h1 * h2);
195  }
196  catch (ConstraintException& ce)
197  {
198  throw Exception("ThreePointsNumericalDerivative::setParameters. Could not compute cross derivatives at limit.");
199  }
200 
201  lastVar1 = var1;
202  lastVar2 = var2;
203  }
204  }
205  }
206 
207  // Reset last parameter and compute analytical derivatives if any.
208  if (function1_)
209  function1_->enableFirstOrderDerivatives(computeD1_);
210  if (function2_)
211  function2_->enableSecondOrderDerivatives(computeD2_);
212  if (functionChanged)
213  function_->setParameters(parameters.createSubList(lastVar));
214  }
215  else
216  {
217  // Reset initial value and compute analytical derivatives if any.
218  if (function1_)
219  function1_->enableFirstOrderDerivatives(computeD1_);
220  if (function2_)
221  function2_->enableSecondOrderDerivatives(computeD2_);
222  function_->setParameters(parameters);
223  // Just in case derivatives are not computed:
224  f2_ = function_->getValue();
225  }
226 }
virtual ParameterList createSubList(const std::vector< std::string > &names) const
Get given parameters as a sublist.
virtual double getParameterValue(const std::string &name) const
Get the value of the parameter with name name.
void updateDerivatives(const ParameterList &parameters) override
Compute derivatives.
STL namespace.
The parameter list object.
Definition: ParameterList.h:27
virtual bool hasParameter(const std::string &name) const
static double VERY_BIG()
Definition: NumConstants.h:48
virtual void setParameters(const ParameterList &params)
Update the parameters from params.
Exception base class. Overload exception constructor (to control the exceptions mechanism). Destructor is already virtual (from std::exception)
Definition: Exceptions.h:20
Exception thrown when a value do not match a given constraint.