Coverage Report

Created: 2025-08-11 06:28

/src/quantlib/ql/math/optimization/bfgs.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
 /*
4
 Copyright (C) 2009 Frédéric Degraeve
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy 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
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19
20
#include <ql/math/optimization/bfgs.hpp>
21
#include <ql/math/optimization/problem.hpp>
22
#include <ql/math/optimization/linesearch.hpp>
23
24
namespace QuantLib {
25
26
    Array BFGS::getUpdatedDirection(const Problem& P,
27
                                    Real,
28
0
                                    const Array& oldGradient) {
29
0
        if (inverseHessian_.rows() == 0)
30
0
        {
31
            // first time in this update, we create needed structures
32
0
            inverseHessian_ = Matrix(P.currentValue().size(),
33
0
                                     P.currentValue().size(), 0.);
34
0
            for (Size i = 0; i < P.currentValue().size(); ++i)
35
0
                inverseHessian_[i][i] = 1.;
36
0
        }
37
38
0
        Array diffGradient;
39
0
        Array diffGradientWithHessianApplied(P.currentValue().size(), 0.);
40
41
0
        diffGradient = lineSearch_->lastGradient() - oldGradient;
42
0
        for (Size i = 0; i < P.currentValue().size(); ++i)
43
0
            for (Size j = 0; j < P.currentValue().size(); ++j)
44
0
                diffGradientWithHessianApplied[i] += inverseHessian_[i][j] * diffGradient[j];
45
46
0
        Real fac, fae, fad;
47
0
        Real sumdg, sumxi;
48
49
0
        fac = fae = sumdg = sumxi = 0.;
50
0
        for (Size i = 0; i < P.currentValue().size(); ++i)
51
0
        {
52
0
            fac += diffGradient[i] * lineSearch_->searchDirection()[i];
53
0
            fae += diffGradient[i] * diffGradientWithHessianApplied[i];
54
0
            sumdg += std::pow(diffGradient[i], 2.);
55
0
            sumxi += std::pow(lineSearch_->searchDirection()[i], 2.);
56
0
        }
57
58
0
        if (fac > std::sqrt(1e-8 * sumdg * sumxi))  // skip update if fac not sufficiently positive
59
0
        {
60
0
            fac = 1.0 / fac;
61
0
            fad = 1.0 / fae;
62
63
0
            for (Size i = 0; i < P.currentValue().size(); ++i)
64
0
                diffGradient[i] = fac * lineSearch_->searchDirection()[i] - fad * diffGradientWithHessianApplied[i];
65
66
0
            for (Size i = 0; i < P.currentValue().size(); ++i)
67
0
                for (Size j = 0; j < P.currentValue().size(); ++j)
68
0
                {
69
0
                    inverseHessian_[i][j] += fac * lineSearch_->searchDirection()[i] * lineSearch_->searchDirection()[j];
70
0
                    inverseHessian_[i][j] -= fad * diffGradientWithHessianApplied[i] * diffGradientWithHessianApplied[j];
71
0
                    inverseHessian_[i][j] += fae * diffGradient[i] * diffGradient[j];
72
0
                }
73
0
        }
74
        //else
75
        //  throw "BFGS: FAC not sufficiently positive";
76
77
78
0
        Array direction(P.currentValue().size());
79
0
        for (Size i = 0; i < P.currentValue().size(); ++i)
80
0
        {
81
0
            direction[i] = 0.0;
82
0
            for (Size j = 0; j < P.currentValue().size(); ++j)
83
0
                direction[i] -= inverseHessian_[i][j] * lineSearch_->lastGradient()[j];
84
0
        }
85
86
0
        return direction;
87
0
    }
88
89
}