QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
levenbergmarquardt.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) 2006 Klaus Spanderen
5 Copyright (C) 2015 Peter Caspers
6
7 This file is part of QuantLib, a free-software/open-source library
8 for financial quantitative analysts and developers - http://quantlib.org/
9
10 QuantLib is free software: you can redistribute it and/or modify it
11 under the terms of the QuantLib license. You should have received a
12 copy of the license along with this program; if not, please email
13 <quantlib-dev@lists.sf.net>. The license is also available online at
14 <http://quantlib.org/license.shtml>.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
24#include <ql/functional.hpp>
25#include <memory>
26
27namespace QuantLib {
28
30 Real xtol,
31 Real gtol,
32 bool useCostFunctionsJacobian)
33 : epsfcn_(epsfcn), xtol_(xtol), gtol_(gtol),
34 useCostFunctionsJacobian_(useCostFunctionsJacobian) {}
35
37 const EndCriteria& endCriteria) {
38 P.reset();
39 const Array& initX = P.currentValue();
40 currentProblem_ = &P;
42 int m = initCostValues_.size();
43 int n = initX.size();
47 }
48 Array xx = initX;
49 std::unique_ptr<Real[]> fvec(new Real[m]);
50 std::unique_ptr<Real[]> diag(new Real[n]);
51 int mode = 1;
52 // magic number recommended by the documentation
53 Real factor = 100;
54 // lmdif() evaluates cost function n+1 times for each iteration (technically, 2n+1
55 // times if useCostFunctionsJacobian is true, but lmdif() doesn't account for that)
56 int maxfev = endCriteria.maxIterations() * (n + 1);
57 int nprint = 0;
58 int info = 0;
59 int nfev = 0;
60 std::unique_ptr<Real[]> fjac(new Real[m*n]);
61 int ldfjac = m;
62 std::unique_ptr<int[]> ipvt(new int[n]);
63 std::unique_ptr<Real[]> qtf(new Real[n]);
64 std::unique_ptr<Real[]> wa1(new Real[n]);
65 std::unique_ptr<Real[]> wa2(new Real[n]);
66 std::unique_ptr<Real[]> wa3(new Real[n]);
67 std::unique_ptr<Real[]> wa4(new Real[m]);
68 // requirements; check here to get more detailed error messages.
69 QL_REQUIRE(n > 0, "no variables given");
70 QL_REQUIRE(m >= n,
71 "less functions (" << m <<
72 ") than available variables (" << n << ")");
73 QL_REQUIRE(endCriteria.functionEpsilon() >= 0.0,
74 "negative f tolerance");
75 QL_REQUIRE(xtol_ >= 0.0, "negative x tolerance");
76 QL_REQUIRE(gtol_ >= 0.0, "negative g tolerance");
77 QL_REQUIRE(maxfev > 0, "null number of evaluations");
78
79 // call lmdif to minimize the sum of the squares of m functions
80 // in n variables by the Levenberg-Marquardt algorithm.
81 MINPACK::LmdifCostFunction lmdifCostFunction =
82 [this](const auto m, const auto n, const auto x, const auto fvec, const auto iflag) {
83 this->fcn(m, n, x, fvec);
84 };
85 MINPACK::LmdifCostFunction lmdifJacFunction =
87 ? [this](const auto m, const auto n, const auto x, const auto fjac, const auto iflag) {
88 this->jacFcn(m, n, x, fjac);
89 }
91 MINPACK::lmdif(m, n, xx.begin(), fvec.get(),
92 endCriteria.functionEpsilon(),
93 xtol_,
94 gtol_,
95 maxfev,
96 epsfcn_,
97 diag.get(), mode, factor,
98 nprint, &info, &nfev, fjac.get(),
99 ldfjac, ipvt.get(), qtf.get(),
100 wa1.get(), wa2.get(), wa3.get(), wa4.get(),
101 lmdifCostFunction,
102 lmdifJacFunction);
103 // for the time being
104 info_ = info;
105 // check requirements & endCriteria evaluation
106 QL_REQUIRE(info != 0, "MINPACK: improper input parameters");
107 QL_REQUIRE(info != 7, "MINPACK: xtol is too small. no further "
108 "improvement in the approximate "
109 "solution x is possible.");
110 QL_REQUIRE(info != 8, "MINPACK: gtol is too small. fvec is "
111 "orthogonal to the columns of the "
112 "jacobian to machine precision.");
113
115 switch (info) {
116 case 1:
117 case 2:
118 case 3:
119 case 4:
120 // 2 and 3 should be StationaryPoint, 4 a new gradient-related value,
121 // but we keep StationaryFunctionValue for backwards compatibility.
123 break;
124 case 5:
126 break;
127 case 6:
129 break;
130 default:
131 QL_FAIL("unknown MINPACK result: " << info);
132 }
133 // set problem
134 P.setCurrentValue(std::move(xx));
136
137 return ecType;
138 }
139
140 void LevenbergMarquardt::fcn(int, int n, Real* x, Real* fvec) {
141 Array xt(n);
142 std::copy(x, x+n, xt.begin());
143 // constraint handling needs some improvement in the future:
144 // starting point should not be close to a constraint violation
145 if (currentProblem_->constraint().test(xt)) {
146 const Array& tmp = currentProblem_->values(xt);
147 std::copy(tmp.begin(), tmp.end(), fvec);
148 } else {
149 std::copy(initCostValues_.begin(), initCostValues_.end(), fvec);
150 }
151 }
152
153 void LevenbergMarquardt::jacFcn(int m, int n, Real* x, Real* fjac) {
154 Array xt(n);
155 std::copy(x, x+n, xt.begin());
156 // constraint handling needs some improvement in the future:
157 // starting point should not be close to a constraint violation
158 if (currentProblem_->constraint().test(xt)) {
159 Matrix tmp(m,n);
161 Matrix tmpT = transpose(tmp);
162 std::copy(tmpT.begin(), tmpT.end(), fjac);
163 } else {
165 std::copy(tmpT.begin(), tmpT.end(), fjac);
166 }
167 }
168
169}
1-D array used in linear algebra.
Definition: array.hpp:52
const_iterator end() const
Definition: array.hpp:499
Size size() const
dimension of the array
Definition: array.hpp:483
const_iterator begin() const
Definition: array.hpp:491
bool test(const Array &p) const
Definition: constraint.hpp:57
virtual Array values(const Array &x) const =0
method to overload to compute the cost function values in x
virtual Real value(const Array &x) const
method to overload to compute the cost function value in x
virtual void jacobian(Matrix &jac, const Array &x) const
method to overload to compute J_f, the jacobian of
Criteria to end optimization process:
Definition: endcriteria.hpp:40
Real functionEpsilon() const
Size maxIterations() const
void fcn(int m, int n, Real *x, Real *fvec, int *)
LevenbergMarquardt(Real epsfcn=1.0e-8, Real xtol=1.0e-8, Real gtol=1.0e-8, bool useCostFunctionsJacobian=false)
void jacFcn(int m, int n, Real *x, Real *fjac, int *)
EndCriteria::Type minimize(Problem &P, const EndCriteria &endCriteria) override
minimize the optimization problem P
Matrix used in linear algebra.
Definition: matrix.hpp:41
const_iterator begin() const
Definition: matrix.hpp:327
const_iterator end() const
Definition: matrix.hpp:335
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
Array values(const Array &x)
call cost values computation and increment evaluation counter
Definition: problem.hpp:121
void setFunctionValue(Real functionValue)
Definition: problem.hpp:83
CostFunction & costFunction() const
Cost function.
Definition: problem.hpp:74
Abstract constraint class.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Maps function, bind and cref to either the boost or std implementation.
QL_REAL Real
real number
Definition: types.hpp:50
Levenberg-Marquardt optimization method.
wrapper for MINPACK minimization routine
void lmdif(int m, int n, Real *x, Real *fvec, Real ftol, Real xtol, Real gtol, int maxfev, Real epsfcn, Real *diag, int mode, Real factor, int nprint, int *info, int *nfev, Real *fjac, int ldfjac, int *ipvt, Real *qtf, Real *wa1, Real *wa2, Real *wa3, Real *wa4, const QuantLib::MINPACK::LmdifCostFunction &fcn, const QuantLib::MINPACK::LmdifCostFunction &jacFcn)
Definition: lmdif.cpp:1130
std::function< void(int, int, Real *, Real *, int *)> LmdifCostFunction
Definition: lmdif.hpp:36
Definition: any.hpp:37
Matrix transpose(const Matrix &m)
Definition: matrix.hpp:700