QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
simplex.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb
5 Copyright (C) 2006 Ferdinando Ametrano
6 Copyright (C) 2007 Marco Bianchetti
7 Copyright (C) 2007 François du Vignaud
8
9 This file is part of QuantLib, a free-software/open-source library
10 for financial quantitative analysts and developers - http://quantlib.org/
11
12 QuantLib is free software: you can redistribute it and/or modify it
13 under the terms of the QuantLib license. You should have received a
14 copy of the license along with this program; if not, please email
15 <quantlib-dev@lists.sf.net>. The license is also available online at
16 <http://quantlib.org/license.shtml>.
17
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the license for more details.
21*/
22
23/* The implementation of the algorithm was highly inspired by
24 * "Numerical Recipes in C", 2nd edition, Press, Teukolsky, Vetterling,
25 * Flannery, chapter 10.
26 * Modified may 2007: end criteria set on x instead on fx,
27 * inspired by bad behaviour found with test function fx=x*x+x+1,
28 * xStart = -100, lambda = 1.0, ftol = 1.e-16
29 * (it reports x=0 as the minimum!)
30 * and by GSL implementation, v. 1.9 (http://www.gnu.org/software/gsl/)
31 */
32
35
36namespace QuantLib {
37
38 namespace {
39 // Computes the size of the simplex
40 Real computeSimplexSize (const std::vector<Array>& vertices) {
41 Array center(vertices.front().size(),0);
42 for (const auto& vertice : vertices)
43 center += vertice;
44 center *=1/Real(vertices.size());
45 Real result = 0;
46 for (const auto& vertice : vertices) {
47 Array temp = vertice - center;
48 result += Norm2(temp);
49 }
50 return result/Real(vertices.size());
51 }
52 }
53
55 Size iHighest,
56 Real &factor) const {
57
58 Array pTry;
59 do {
60 Size dimensions = values_.size() - 1;
61 Real factor1 = (1.0 - factor)/dimensions;
62 Real factor2 = factor1 - factor;
63 pTry = sum_*factor1 - vertices_[iHighest]*factor2;
64 factor *= 0.5;
65 } while (!P.constraint().test(pTry) && std::fabs(factor) > QL_EPSILON);
66 if (std::fabs(factor) <= QL_EPSILON) {
67 return values_[iHighest];
68 }
69 factor *= 2.0;
70 Real vTry = P.value(pTry);
71 if (vTry < values_[iHighest]) {
72 values_[iHighest] = vTry;
73 sum_ += pTry - vertices_[iHighest];
74 vertices_[iHighest] = pTry;
75 }
76 return vTry;
77
78 }
79
80
82 const EndCriteria& endCriteria) {
83 // set up of the problem
84 //Real ftol = endCriteria.functionEpsilon(); // end criteria on f(x) (see Numerical Recipes in C++, p.410)
85 Real xtol = endCriteria.rootEpsilon(); // end criteria on x (see GSL v. 1.9, http://www.gnu.org/software/gsl/)
86 Size maxStationaryStateIterations_
87 = endCriteria.maxStationaryStateIterations();
89 P.reset();
90
91 Array x_ = P.currentValue();
92 if (!P.constraint().test(x_))
93 QL_FAIL("Initial guess " << x_ << " is not in the feasible region.");
94
95 Integer iterationNumber_=0;
96
97 // Initialize vertices of the simplex
98 Size n = x_.size();
99 vertices_ = std::vector<Array>(n+1, x_);
100 for (Size i=0; i<n; ++i) {
101 Array direction(n, 0.0);
102 direction[i] = 1.0;
103 P.constraint().update(vertices_[i+1], direction, lambda_);
104 }
105 // Initialize function values at the vertices of the simplex
106 values_ = Array(n+1, 0.0);
107 for (Size i=0; i<=n; ++i)
108 values_[i] = P.value(vertices_[i]);
109 // Loop looking for minimum
110 do {
111 sum_ = Array(n, 0.0);
112 Size i;
113 for (i=0; i<=n; i++)
114 sum_ += vertices_[i];
115 // Determine the best (iLowest), worst (iHighest)
116 // and 2nd worst (iNextHighest) vertices
117 Size iLowest = 0;
118 Size iHighest, iNextHighest;
119 if (values_[0]<values_[1]) {
120 iHighest = 1;
121 iNextHighest = 0;
122 } else {
123 iHighest = 0;
124 iNextHighest = 1;
125 }
126 for (i=1;i<=n; i++) {
127 if (values_[i]>values_[iHighest]) {
128 iNextHighest = iHighest;
129 iHighest = i;
130 } else {
131 if ((values_[i]>values_[iNextHighest]) && i!=iHighest)
132 iNextHighest = i;
133 }
134 if (values_[i]<values_[iLowest])
135 iLowest = i;
136 }
137 // Now compute accuracy, update iteration number and check end criteria
138 //// Numerical Recipes exit strategy on fx (see NR in C++, p.410)
139 //Real low = values_[iLowest];
140 //Real high = values_[iHighest];
141 //Real rtol = 2.0*std::fabs(high - low)/
142 // (std::fabs(high) + std::fabs(low) + QL_EPSILON);
143 //++iterationNumber_;
144 //if (rtol < ftol ||
145 // endCriteria.checkMaxIterations(iterationNumber_, ecType)) {
146 // GSL exit strategy on x (see GSL v. 1.9, http://www.gnu.org/software/gsl
147 Real simplexSize = computeSimplexSize(vertices_);
148 ++iterationNumber_;
149 if (simplexSize < xtol ||
150 endCriteria.checkMaxIterations(iterationNumber_, ecType)) {
151 endCriteria.checkStationaryPoint(0.0, 0.0,
152 maxStationaryStateIterations_, ecType);
153 endCriteria.checkMaxIterations(iterationNumber_, ecType);
154 x_ = vertices_[iLowest];
155 Real low = values_[iLowest];
156 P.setFunctionValue(low);
158 return ecType;
159 }
160 // If end criteria is not met, continue
161 Real factor = -1.0;
162 Real vTry = extrapolate(P, iHighest, factor);
163 if ((vTry <= values_[iLowest]) && (factor == -1.0)) {
164 factor = 2.0;
165 extrapolate(P, iHighest, factor);
166 } else if (std::fabs(factor) > QL_EPSILON) {
167 if (vTry >= values_[iNextHighest]) {
168 Real vSave = values_[iHighest];
169 factor = 0.5;
170 vTry = extrapolate(P, iHighest, factor);
171 if (vTry >= vSave && std::fabs(factor) > QL_EPSILON) {
172 for (Size i=0; i<=n; i++) {
173 if (i!=iLowest) {
174 vertices_[i] =
175 0.5*(vertices_[i] + vertices_[iLowest]);
176 values_[i] = P.value(vertices_[i]);
177 }
178 }
179 }
180 }
181 }
182 // If can't extrapolate given the constraints, exit
183 if (std::fabs(factor) <= QL_EPSILON) {
184 x_ = vertices_[iLowest];
185 Real low = values_[iLowest];
186 P.setFunctionValue(low);
189 }
190 } while (true);
191 QL_FAIL("optimization failed: unexpected behaviour");
192 }
193}
1-D array used in linear algebra.
Definition: array.hpp:52
Size size() const
dimension of the array
Definition: array.hpp:483
bool test(const Array &p) const
Definition: constraint.hpp:57
Real update(Array &p, const Array &direction, Real beta) const
Definition: constraint.cpp:27
Criteria to end optimization process:
Definition: endcriteria.hpp:40
bool checkStationaryPoint(Real xOld, Real xNew, Size &statStateIterations, EndCriteria::Type &ecType) const
Definition: endcriteria.cpp:64
Real rootEpsilon() const
Size maxStationaryStateIterations() const
bool checkMaxIterations(Size iteration, EndCriteria::Type &ecType) const
Definition: endcriteria.cpp:56
Constrained optimization problem.
Definition: problem.hpp:42
const Array & currentValue() const
current value of the local minimum
Definition: problem.hpp:81
void setCurrentValue(Array currentValue)
Definition: problem.hpp:76
Constraint & constraint() const
Constraint.
Definition: problem.hpp:71
Real value(const Array &x)
call cost function computation and increment evaluation counter
Definition: problem.hpp:116
void setFunctionValue(Real functionValue)
Definition: problem.hpp:83
std::vector< Array > vertices_
Definition: simplex.hpp:70
Real extrapolate(Problem &P, Size iHighest, Real &factor) const
Definition: simplex.cpp:54
EndCriteria::Type minimize(Problem &P, const EndCriteria &endCriteria) override
minimize the optimization problem P
Definition: simplex.cpp:81
Abstract constraint class.
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
#define QL_EPSILON
Definition: qldefines.hpp:178
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:37
Real Norm2(const Array &v)
Definition: array.hpp:548
Simplex optimization method.
std::uint64_t x_