Coverage Report

Created: 2026-01-25 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/methods/finitedifferences/operators/fdmsabrop.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2018 Klaus Spanderen
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
 <https://www.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
/*! \file fdmsabrop.cpp
21
    \brief FDM operator for the SABR model
22
*/
23
24
#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
25
#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
26
#include <ql/methods/finitedifferences/operators/fdmsabrop.hpp>
27
#include <ql/methods/finitedifferences/operators/firstderivativeop.hpp>
28
#include <ql/methods/finitedifferences/operators/secondderivativeop.hpp>
29
#include <ql/methods/finitedifferences/operators/secondordermixedderivativeop.hpp>
30
#include <ql/termstructures/yieldtermstructure.hpp>
31
#include <utility>
32
33
namespace QuantLib {
34
    FdmSabrOp::FdmSabrOp(const ext::shared_ptr<FdmMesher>& mesher,
35
                         ext::shared_ptr<YieldTermStructure> rTS,
36
                         Real f0,
37
                         Real alpha,
38
                         Real beta,
39
                         Real nu,
40
                         Real rho)
41
0
    : rTS_(std::move(rTS)),
42
0
      dffMap_(SecondDerivativeOp(0, mesher).mult(0.5 * Exp(2.0 * mesher->locations(1)) *
43
0
                                                 Pow(mesher->locations(0), 2.0 * beta))),
44
0
      dxMap_(FirstDerivativeOp(1, mesher).mult(Array(mesher->layout()->size(), -0.5 * nu * nu))),
45
0
      dxxMap_(SecondDerivativeOp(1, mesher).mult(Array(mesher->layout()->size(), 0.5 * nu * nu))),
46
      correlationMap_(
47
0
          SecondOrderMixedDerivativeOp(0, 1, mesher)
48
0
              .mult(rho * nu * Exp(mesher->locations(1)) * Pow(mesher->locations(0), beta))),
49
0
      mapF_(0, mesher), mapA_(1, mesher) {}
50
51
0
    void FdmSabrOp::setTime(Time t1, Time t2) {
52
0
        const Rate r = rTS_->forwardRate(t1, t2, Continuous).rate();
53
54
0
        mapF_.axpyb(Array(), dffMap_, dffMap_, Array(1, -0.5*r));
55
0
        mapA_.axpyb(Array(1, 1.0), dxMap_, dxxMap_, Array(1, -0.5*r));
56
0
    }
57
58
0
    Size FdmSabrOp::size() const {
59
0
        return 2;
60
0
    }
61
62
0
    Array FdmSabrOp::apply(const Array& u) const {
63
0
        return mapF_.apply(u) + mapA_.apply(u) + correlationMap_.apply(u);
64
0
    }
65
66
0
    Array FdmSabrOp::apply_mixed(const Array& r) const {
67
0
        return correlationMap_.apply(r);
68
0
    }
69
70
    Array FdmSabrOp::apply_direction(
71
0
        Size direction, const Array& r) const {
72
0
        if (direction == 0)
73
0
            return mapF_.apply(r);
74
0
        else if (direction == 1)
75
0
            return mapA_.apply(r);
76
0
        else
77
0
            QL_FAIL("direction too large");
78
0
    }
79
80
    Array FdmSabrOp::solve_splitting(
81
0
       Size direction, const Array& r, Real a) const {
82
83
0
        if (direction == 0) {
84
0
            return mapF_.solve_splitting(r, a, 1.0);
85
0
        }
86
0
        else if (direction == 1) {
87
0
            return mapA_.solve_splitting(r, a, 1.0);
88
0
        }
89
0
        else
90
0
            QL_FAIL("direction too large");
91
0
    }
92
93
    Array FdmSabrOp::preconditioner(
94
0
        const Array& r, Real dt) const {
95
96
0
        return solve_splitting(1, solve_splitting(0, r, dt), dt) ;
97
0
    }
98
99
0
    std::vector<SparseMatrix> FdmSabrOp::toMatrixDecomp() const {
100
0
        return {
101
0
            mapA_.toMatrix(),
102
0
            mapF_.toMatrix(),
103
0
            correlationMap_.toMatrix()
104
0
        };
105
0
    }
106
107
}