QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
hybridsimulatedannealingfunctors.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4Copyright (C) 2015 Andres Hernandez
5
6This file is part of QuantLib, a free-software/open-source library
7for financial quantitative analysts and developers - http://quantlib.org/
8
9QuantLib is free software: you can redistribute it and/or modify it
10under the terms of the QuantLib license. You should have received a
11copy of the license along with this program; if not, please email
12<quantlib-dev@lists.sf.net>. The license is also available online at
13<http://quantlib.org/license.shtml>.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
24#ifndef HYBRIDSIMULATEDANNEALINGFUNCTORS_H
25#define HYBRIDSIMULATEDANNEALINGFUNCTORS_H
26
27#include <ql/math/array.hpp>
28#include <ql/math/randomnumbers/seedgenerator.hpp>
29#include <ql/math/optimization/problem.hpp>
30
31#include <algorithm>
32#include <cmath>
33#include <random>
34#include <utility>
35#include <vector>
36
37namespace QuantLib
38{
40
44 {
45 public:
46 explicit SamplerLogNormal(unsigned long seed = SeedGenerator::instance().get()) :
47 generator_(seed), distribution_(0.0, 1.0) {};
48
49 inline void operator()(Array &newPoint, const Array &currentPoint, const Array &temp) {
50 QL_REQUIRE(newPoint.size() == currentPoint.size(), "Incompatible input");
51 QL_REQUIRE(newPoint.size() == temp.size(), "Incompatible input");
52 for (Size i = 0; i < currentPoint.size(); i++)
53 newPoint[i] = currentPoint[i] * exp(sqrt(temp[i]) * distribution_(generator_));
54 };
55 private:
56 std::mt19937 generator_;
57 std::normal_distribution<Real> distribution_;
58 };
59
61
65 {
66 public:
67 explicit SamplerGaussian(unsigned long seed = SeedGenerator::instance().get()) :
68 generator_(seed), distribution_(0.0, 1.0) {};
69
70 inline void operator()(Array &newPoint, const Array &currentPoint, const Array &temp) {
71 QL_REQUIRE(newPoint.size() == currentPoint.size(), "Incompatible input");
72 QL_REQUIRE(newPoint.size() == temp.size(), "Incompatible input");
73 for (Size i = 0; i < currentPoint.size(); i++)
74 newPoint[i] = currentPoint[i] + std::sqrt(temp[i]) * distribution_(generator_);
75 };
76 private:
77 std::mt19937 generator_;
78 std::normal_distribution<Real> distribution_;
79 };
80
82
87 {
88 public:
90 Array upper,
91 unsigned long seed = SeedGenerator::instance().get())
92 : generator_(seed), distribution_(0.0, 1.0),
93 lower_(std::move(lower)), upper_(std::move(upper)){};
94
95 inline void operator()(Array &newPoint, const Array &currentPoint, const Array &temp) {
96 QL_REQUIRE(newPoint.size() == currentPoint.size(), "Incompatible input");
97 QL_REQUIRE(newPoint.size() == temp.size(), "Incompatible input");
98 for (Size i = 0; i < currentPoint.size(); i++){
99 newPoint[i] = currentPoint[i] + std::sqrt(temp[i]) * distribution_(generator_);
100 while(newPoint[i] < lower_[i] || newPoint[i] > upper_[i]){
101 if(newPoint[i] < lower_[i]){
102 newPoint[i] = upper_[i] + newPoint[i] - lower_[i];
103 } else {
104 newPoint[i] = lower_[i] + newPoint[i] - upper_[i];
105 }
106 }
107 }
108 };
109 private:
110 std::mt19937 generator_;
111 std::normal_distribution<Real> distribution_;
113 };
114
116
121 {
122 public:
124 Array upper,
125 unsigned long seed = SeedGenerator::instance().get())
126 : generator_(seed), distribution_(0.0, 1.0),
127 lower_(std::move(lower)), upper_(std::move(upper)){};
128
129 inline void operator()(Array &newPoint, const Array &currentPoint, const Array &temp) {
130 QL_REQUIRE(newPoint.size() == currentPoint.size(), "Incompatible input");
131 QL_REQUIRE(newPoint.size() == temp.size(), "Incompatible input");
132 for (Size i = 0; i < currentPoint.size(); i++){
133 newPoint[i] = currentPoint[i] + std::sqrt(temp[i]) * distribution_(generator_);
134 while(newPoint[i] < lower_[i] || newPoint[i] > upper_[i]){
135 if(newPoint[i] < lower_[i]){
136 newPoint[i] = lower_[i] + lower_[i] - newPoint[i];
137 } else {
138 newPoint[i] = upper_[i] + upper_[i] - newPoint[i];
139 }
140 }
141 }
142 };
143 private:
144 std::mt19937 generator_;
145 std::normal_distribution<Real> distribution_;
147 };
148
150
156 {
157 public:
158 explicit SamplerCauchy(unsigned long seed = SeedGenerator::instance().get()) :
159 generator_(seed), distribution_(0.0, 1.0) {};
160
161 inline void operator()(Array &newPoint, const Array &currentPoint, const Array &temp) {
162 QL_REQUIRE(newPoint.size() == currentPoint.size(), "Incompatible input");
163 QL_REQUIRE(newPoint.size() == temp.size(), "Incompatible input");
164 for (Size i = 0; i < currentPoint.size(); i++)
165 newPoint[i] = currentPoint[i] + temp[i] * distribution_(generator_);
166 };
167 protected:
168 std::mt19937 generator_;
169 std::cauchy_distribution<Real> distribution_;
170 };
171
173
177 {
178 public:
180 Array upper,
181 unsigned long seed = SeedGenerator::instance().get())
182 : lower_(std::move(lower)), upper_(std::move(upper)), generator_(seed) {
183 QL_REQUIRE(lower_.size() == upper_.size(), "Incompatible input");
184 };
185
186 inline void operator()(Array &newPoint, const Array &currentPoint, const Array &temp) {
187 QL_REQUIRE(newPoint.size() == currentPoint.size(), "Incompatible input");
188 QL_REQUIRE(newPoint.size() == lower_.size(), "Incompatible input");
189 QL_REQUIRE(newPoint.size() == temp.size(), "Incompatible input");
190 for (Size i = 0; i < currentPoint.size(); i++) {
191 newPoint[i] = lower_[i] - 1.0;
192 while (newPoint[i] < lower_[i] || newPoint[i] > upper_[i]) {
194 Real sign = static_cast<int>(0.5 < draw) - static_cast<int>(draw < 0.5);
195 Real y = sign*temp[i] * (std::pow(1.0 + 1.0 / temp[i],
196 std::abs(2 * draw - 1.0)) - 1.0);
197 newPoint[i] = currentPoint[i] + y*(upper_[i] - lower_[i]);
198 }
199 }
200 };
201 private:
203 std::mt19937 generator_;
204 std::uniform_real_distribution<Real> distribution_;
205 };
206
208
213 inline bool operator()(Real currentValue, Real newValue, const Array &temp) {
214 return currentValue > newValue; //return true if new value is lower than old value
215 }
216 };
217
219
224 public:
225 explicit ProbabilityBoltzmann(unsigned long seed = SeedGenerator::instance().get()) : generator_(seed) {};
226
227 inline bool operator()(Real currentValue, Real newValue, const Array &temp) {
228 Real temperature = *std::max_element(temp.begin(), temp.end());
229 return (1.0 / (1.0 + exp((newValue - currentValue) / temperature))) > distribution_(generator_);
230 }
231 private:
232 std::mt19937 generator_;
233 std::uniform_real_distribution<Real> distribution_;
234 };
236
240 {
241 public:
242 explicit ProbabilityBoltzmannDownhill(unsigned long seed = SeedGenerator::instance().get()) : generator_(seed) {};
243
244 inline bool operator()(Real currentValue, Real newValue, const Array &temp) {
245 if (newValue < currentValue)
246 return true;
247 Real mTemperature = *std::max_element(temp.begin(), temp.end());
248 return (1.0 / (1.0 + exp((newValue - currentValue) / mTemperature))) > distribution_(generator_);
249 }
250 private:
251 std::mt19937 generator_;
252 std::uniform_real_distribution<Real> distribution_;
253 };
255
258 public:
259 TemperatureBoltzmann(Real initialTemp, Size dimension)
260 : initialTemp_(dimension, initialTemp) {}
261 inline void operator()(Array &newTemp, const Array &currTemp, const Array &steps) {
262 QL_REQUIRE(currTemp.size() == initialTemp_.size(), "Incompatible input");
263 QL_REQUIRE(currTemp.size() == newTemp.size(), "Incompatible input");
264 for (Size i = 0; i < initialTemp_.size(); i++)
265 newTemp[i] = initialTemp_[i] / std::log(steps[i]);
266 }
267 private:
269 };
271
274 public:
275 TemperatureCauchy(Real initialTemp, Size dimension)
276 : initialTemp_(dimension, initialTemp) {}
277 inline void operator()(Array &newTemp, const Array &currTemp, const Array &steps) {
278 QL_REQUIRE(currTemp.size() == initialTemp_.size(), "Incompatible input");
279 QL_REQUIRE(currTemp.size() == newTemp.size(), "Incompatible input");
280 for (Size i = 0; i < initialTemp_.size(); i++)
281 newTemp[i] = initialTemp_[i] / steps[i];
282 }
283 private:
285 };
286
288 public:
289 TemperatureCauchy1D(Real initialTemp, Size dimension) :
290 inverseN_(1.0 / dimension),
291 initialTemp_(dimension, initialTemp) {}
292 inline void operator()(Array &newTemp, const Array &currTemp, const Array &steps) {
293 QL_REQUIRE(currTemp.size() == initialTemp_.size(), "Incompatible input");
294 QL_REQUIRE(currTemp.size() == newTemp.size(), "Incompatible input");
295 for (Size i = 0; i < initialTemp_.size(); i++)
296 newTemp[i] = initialTemp_[i] / std::pow(steps[i], inverseN_);
297 }
298 private:
301 };
302
304 public:
305 TemperatureExponential(Real initialTemp, Size dimension, Real power = 0.95)
306 : initialTemp_(dimension, initialTemp), power_(power) {}
307 inline void operator()(Array &newTemp, const Array &currTemp, const Array &steps) {
308 QL_REQUIRE(currTemp.size() == initialTemp_.size(), "Incompatible input");
309 QL_REQUIRE(currTemp.size() == newTemp.size(), "Incompatible input");
310 for (Size i = 0; i < initialTemp_.size(); i++)
311 newTemp[i] = initialTemp_[i] * std::pow(power_, steps[i]);
312 }
313 private:
316 };
318
321 public:
322 TemperatureVeryFastAnnealing(Real initialTemp, Real finalTemp, Real maxSteps, Size dimension)
323 :inverseN_(1.0 / dimension), initialTemp_(dimension, initialTemp),
324 finalTemp_(dimension, finalTemp), exponent_(dimension, 0.0) {
325 Real coeff = std::pow(maxSteps, -inverseN_);
326 for (Size i = 0; i < initialTemp_.size(); i++)
327 exponent_[i] = -std::log(finalTemp_[i] / initialTemp_[i])*coeff;
328 }
329 inline void operator()(Array &newTemp, const Array &currTemp, const Array &steps) {
330 QL_REQUIRE(currTemp.size() == initialTemp_.size(), "Incompatible input");
331 QL_REQUIRE(currTemp.size() == newTemp.size(), "Incompatible input");
332 for (Size i = 0; i < initialTemp_.size(); i++)
333 newTemp[i] = initialTemp_[i] * exp(-exponent_[i] * std::pow(steps[i], inverseN_));
334 }
335 private:
338 };
340
344 ;
345 inline void setProblem(Problem &P) {};
346 inline void operator()(Array & steps, const Array &currentPoint,
347 Real aCurrentValue, const Array & currTemp) {};
348 };
350
358 public:
360 Size dimension,
361 const Array& lower = Array(),
362 const Array& upper = Array(),
363 Real stepSize = 1e-7,
364 Real minSize = 1e-10,
365 Real functionTol = 1e-10)
366 : stepSize_(stepSize), minSize_(minSize), functionTol_(functionTol), N_(dimension),
367 lower_(lower), upper_(upper), initialTemp_(dimension, initialTemp),
368 bounded_(dimension, 1.0) {
369 if (!lower.empty() && !upper.empty()) {
370 QL_REQUIRE(lower.size() == N_, "Incompatible input");
371 QL_REQUIRE(upper.size() == N_, "Incompatible input");
372 bound_ = true;
373 for (Size i = 0; i < N_; i++) {
374 bounded_[i] = upper[i] - lower[i];
375 }
376 }
377 }
378 inline void setProblem(Problem &P) { problem_ = &P; };
379 inline void operator()(Array & steps, const Array &currentPoint,
380 Real currentValue, const Array & currTemp) {
381 QL_REQUIRE(currTemp.size() == N_, "Incompatible input");
382 QL_REQUIRE(steps.size() == N_, "Incompatible input");
383
384 Array finiteDiffs(N_, 0.0);
385 Real finiteDiffMax = 0.0;
386 Array ofssetPoint(currentPoint);
387 for (Size i = 0; i < N_; i++) {
388 ofssetPoint[i] += stepSize_;
389 finiteDiffs[i] = bounded_[i] * std::abs((problem_->value(ofssetPoint) - currentValue) / stepSize_);
390 ofssetPoint[i] -= stepSize_;
391 if (finiteDiffs[i] < minSize_)
392 finiteDiffs[i] = minSize_;
393 if (finiteDiffs[i] > finiteDiffMax)
394 finiteDiffMax = finiteDiffs[i];
395 }
396 for (Size i = 0; i < N_; i++) {
397 Real tRatio = initialTemp_[i] / currTemp[i];
398 Real sRatio = finiteDiffMax / finiteDiffs[i];
399 if (sRatio*tRatio < functionTol_)
400 steps[i] = std::pow(std::fabs(std::log(functionTol_)),
401 Integer(N_));
402 else
403 steps[i] = std::pow(std::fabs(std::log(sRatio*tRatio)),
404 Integer(N_));
405 }
406 }
407 private:
411 bool bound_ = false;
413 };
414}
415#endif // HYBRIDSIMULATEDANNEALINGFUNCTORS_H
1-D array used in linear algebra.
Definition: array.hpp:52
bool empty() const
whether the array is empty
Definition: array.hpp:499
const_iterator end() const
Definition: array.hpp:511
Size size() const
dimension of the array
Definition: array.hpp:495
const_iterator begin() const
Definition: array.hpp:503
std::uniform_real_distribution< Real > distribution_
bool operator()(Real currentValue, Real newValue, const Array &temp)
ProbabilityBoltzmannDownhill(unsigned long seed=SeedGenerator::instance().get())
std::uniform_real_distribution< Real > distribution_
bool operator()(Real currentValue, Real newValue, const Array &temp)
ProbabilityBoltzmann(unsigned long seed=SeedGenerator::instance().get())
Constrained optimization problem.
Definition: problem.hpp:42
Real value(const Array &x)
call cost function computation and increment evaluation counter
Definition: problem.hpp:116
ReannealingFiniteDifferences(Real initialTemp, Size dimension, const Array &lower=Array(), const Array &upper=Array(), Real stepSize=1e-7, Real minSize=1e-10, Real functionTol=1e-10)
void operator()(Array &steps, const Array &currentPoint, Real currentValue, const Array &currTemp)
SamplerCauchy(unsigned long seed=SeedGenerator::instance().get())
void operator()(Array &newPoint, const Array &currentPoint, const Array &temp)
std::cauchy_distribution< Real > distribution_
std::normal_distribution< Real > distribution_
void operator()(Array &newPoint, const Array &currentPoint, const Array &temp)
SamplerGaussian(unsigned long seed=SeedGenerator::instance().get())
SamplerLogNormal(unsigned long seed=SeedGenerator::instance().get())
std::normal_distribution< Real > distribution_
void operator()(Array &newPoint, const Array &currentPoint, const Array &temp)
SamplerMirrorGaussian(Array lower, Array upper, unsigned long seed=SeedGenerator::instance().get())
std::normal_distribution< Real > distribution_
void operator()(Array &newPoint, const Array &currentPoint, const Array &temp)
std::normal_distribution< Real > distribution_
SamplerRingGaussian(Array lower, Array upper, unsigned long seed=SeedGenerator::instance().get())
void operator()(Array &newPoint, const Array &currentPoint, const Array &temp)
std::uniform_real_distribution< Real > distribution_
SamplerVeryFastAnnealing(Array lower, Array upper, unsigned long seed=SeedGenerator::instance().get())
void operator()(Array &newPoint, const Array &currentPoint, const Array &temp)
static SeedGenerator & instance()
access to the unique instance
Definition: singleton.hpp:104
void operator()(Array &newTemp, const Array &currTemp, const Array &steps)
TemperatureBoltzmann(Real initialTemp, Size dimension)
void operator()(Array &newTemp, const Array &currTemp, const Array &steps)
TemperatureCauchy1D(Real initialTemp, Size dimension)
void operator()(Array &newTemp, const Array &currTemp, const Array &steps)
TemperatureCauchy(Real initialTemp, Size dimension)
void operator()(Array &newTemp, const Array &currTemp, const Array &steps)
TemperatureExponential(Real initialTemp, Size dimension, Real power=0.95)
void operator()(Array &newTemp, const Array &currTemp, const Array &steps)
TemperatureVeryFastAnnealing(Real initialTemp, Real finalTemp, Real maxSteps, Size dimension)
QL_REAL Real
real number
Definition: types.hpp:50
QL_INTEGER Integer
integer number
Definition: types.hpp:35
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
STL namespace.
bool operator()(Real currentValue, Real newValue, const Array &temp)
void operator()(Array &steps, const Array &currentPoint, Real aCurrentValue, const Array &currTemp)