Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/methods/finitedifferences/operators/fdmbatesop.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) 2010 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
 <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
/*! \file fdmbatesop.cpp
21
    \brief Bates linear operator
22
*/
23
24
#include <ql/math/interpolations/linearinterpolation.hpp>
25
#include <ql/math/matrix.hpp>
26
#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
27
#include <ql/methods/finitedifferences/operators/fdmbatesop.hpp>
28
#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
29
#include <ql/methods/finitedifferences/utilities/fdmdirichletboundary.hpp>
30
#include <ql/processes/batesprocess.hpp>
31
#include <ql/quotes/simplequote.hpp>
32
#include <ql/termstructures/yield/zerospreadedtermstructure.hpp>
33
#include <utility>
34
35
namespace QuantLib {
36
37
    FdmBatesOp::FdmBatesOp(const ext::shared_ptr<FdmMesher>& mesher,
38
                           const ext::shared_ptr<BatesProcess>& batesProcess,
39
                           FdmBoundaryConditionSet bcSet,
40
                           const Size integroIntegrationOrder,
41
                           const ext::shared_ptr<FdmQuantoHelper>& quantoHelper)
42
0
    : lambda_(batesProcess->lambda()), delta_(batesProcess->delta()), nu_(batesProcess->nu()),
43
0
      m_(std::exp(nu_ + 0.5 * delta_ * delta_) - 1.0),
44
0
      gaussHermiteIntegration_(integroIntegrationOrder), mesher_(mesher), bcSet_(std::move(bcSet)),
45
0
      hestonOp_(new FdmHestonOp(
46
0
          mesher,
47
0
          ext::make_shared<HestonProcess>(
48
0
              batesProcess->riskFreeRate(),
49
0
              Handle<YieldTermStructure>(ext::make_shared<ZeroSpreadedTermStructure>(
50
0
                  batesProcess->dividendYield(),
51
0
                  Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(lambda_ * m_))),
52
0
                  Continuous,
53
0
                  NoFrequency,
54
0
                  batesProcess->dividendYield()->dayCounter())),
55
0
              batesProcess->s0(),
56
0
              batesProcess->v0(),
57
0
              batesProcess->kappa(),
58
0
              batesProcess->theta(),
59
0
              batesProcess->sigma(),
60
0
              batesProcess->rho()),
61
0
          quantoHelper)) {}
62
63
    FdmBatesOp::IntegroIntegrand::IntegroIntegrand(
64
                    const ext::shared_ptr<LinearInterpolation>& interpl,
65
                    const FdmBoundaryConditionSet& bcSet,
66
                    Real x, Real delta, Real nu)
67
0
    : x_(x), delta_(delta), nu_(nu), 
68
0
      bcSet_(bcSet), interpl_(interpl) { }
69
                    
70
0
    Real FdmBatesOp::IntegroIntegrand::operator()(Real y) const {
71
0
        const Real x = x_ + M_SQRT2*delta_*y + nu_;
72
0
        Real valueOfDerivative = (*interpl_)(x, true);
73
74
0
        for (auto iter = bcSet_.begin(); iter < bcSet_.end(); ++iter) {
75
76
0
            const ext::shared_ptr<FdmDirichletBoundary> dirichlet
77
0
                = ext::dynamic_pointer_cast<FdmDirichletBoundary>(*iter);
78
79
0
            QL_REQUIRE(dirichlet, "FdmBatesOp can only deal with Dirichlet "
80
0
                                  "boundary conditions.");
81
82
0
            valueOfDerivative
83
0
                = dirichlet->applyAfterApplying(x, valueOfDerivative);
84
0
        }
85
86
0
        return std::exp(-y*y)*valueOfDerivative;
87
0
    }
88
    
89
0
    Array FdmBatesOp::integro(const Array& r) const {
90
0
        QL_REQUIRE(mesher_->layout()->dim().size() == 2, "invalid layout dimension");
91
92
0
        Array x(mesher_->layout()->dim()[0]);
93
0
        Matrix f(mesher_->layout()->dim()[1], mesher_->layout()->dim()[0]);
94
        
95
0
        for (const auto& iter : *mesher_->layout()) {
96
0
            const Size i = iter.coordinates()[0];
97
0
            const Size j = iter.coordinates()[1];
98
            
99
0
            x[i]    = mesher_->location(iter, 0);
100
0
            f[j][i] = r[iter.index()];
101
            
102
0
        }
103
0
        std::vector<ext::shared_ptr<LinearInterpolation> > interpl(f.rows());
104
0
        for (Size i=0; i < f.rows(); ++i) {
105
0
            interpl[i] = ext::make_shared<LinearInterpolation>(
106
0
                x.begin(), x.end(), f.row_begin(i));
107
0
        }
108
        
109
0
        Array integral(r.size());
110
0
        for (const auto& iter : *mesher_->layout()) {
111
0
            const Size i = iter.coordinates()[0];
112
0
            const Size j = iter.coordinates()[1];
113
114
0
            integral[iter.index()] = M_1_SQRTPI* 
115
0
                gaussHermiteIntegration_(
116
0
                      IntegroIntegrand(interpl[j], bcSet_, x[i], delta_, nu_));
117
0
        }
118
119
0
        return lambda_*(integral-r);
120
0
    }
121
122
0
    std::vector<SparseMatrix> FdmBatesOp::toMatrixDecomp() const {
123
0
        QL_FAIL("not implemented");
124
0
    }
125
126
}