Coverage Report

Created: 2026-02-03 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/experimental/finitedifferences/fdmextoujumpop.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2011 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 fdmexpoujumpop.cpp
21
    \brief Ornstein Uhlenbeck process plus jumps (Kluge Model)
22
*/
23
24
#include <ql/experimental/finitedifferences/fdmextendedornsteinuhlenbeckop.hpp>
25
#include <ql/experimental/finitedifferences/fdmextoujumpop.hpp>
26
#include <ql/experimental/processes/extendedornsteinuhlenbeckprocess.hpp>
27
#include <ql/experimental/processes/extouwithjumpsprocess.hpp>
28
#include <ql/math/interpolations/linearinterpolation.hpp>
29
#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
30
#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
31
#include <ql/methods/finitedifferences/operators/secondderivativeop.hpp>
32
#include <ql/termstructures/yieldtermstructure.hpp>
33
34
#if defined(QL_PATCH_MSVC)
35
#pragma warning(push)
36
#pragma warning(disable:4180)
37
#endif
38
39
#include <boost/numeric/ublas/vector.hpp>
40
#include <boost/numeric/ublas/operation.hpp>
41
42
#if defined(QL_PATCH_MSVC)
43
#pragma warning(pop)
44
#endif
45
46
namespace QuantLib {
47
48
    FdmExtOUJumpOp::FdmExtOUJumpOp(
49
        const ext::shared_ptr<FdmMesher>& mesher,
50
        const ext::shared_ptr<ExtOUWithJumpsProcess>& process,
51
        const ext::shared_ptr<YieldTermStructure>& rTS,
52
        const FdmBoundaryConditionSet& bcSet,
53
        Size integroIntegrationOrder)
54
0
    : mesher_ (mesher),
55
0
      process_(process),
56
0
      rTS_    (rTS),
57
0
      bcSet_  (bcSet),
58
0
      gaussLaguerreIntegration_(integroIntegrationOrder),
59
0
      x_      (mesher->locations(0)),
60
0
      ouOp_   (new FdmExtendedOrnsteinUhlenbeckOp(
61
0
                   mesher,
62
0
                   process->getExtendedOrnsteinUhlenbeckProcess(), rTS, bcSet)),
63
0
      dyMap_  (FirstDerivativeOp(1, mesher)
64
0
                .mult(-process->beta()*mesher->locations(1)))
65
0
    {
66
0
        const Real eta     = process_->eta();
67
0
        const Real lambda  = process_->jumpIntensity();
68
69
0
        const Array yInt   = gaussLaguerreIntegration_.x();
70
0
        const Array weights= gaussLaguerreIntegration_.weights();
71
72
0
        integroPart_ = SparseMatrix(mesher_->layout()->size(),
73
0
                                    mesher_->layout()->size());
74
75
0
        Array yLoc(mesher_->layout()->dim()[1]);
76
0
        for (const auto& iter : *mesher_->layout()) {
77
0
            yLoc[iter.coordinates()[1]] = mesher_->location(iter, 1);
78
0
        }
79
80
0
        for (const auto& iter : *mesher_->layout()) {
81
0
            const Size diag = iter.index();
82
0
            integroPart_(diag, diag) -= lambda;
83
84
0
            const Real y = mesher_->location(iter, 1);
85
0
            const Integer yIndex = iter.coordinates()[1];
86
87
0
            for (Size i=0; i < yInt.size(); ++i) {
88
0
                const Real weight = std::exp(-yInt[i])*weights[i];
89
90
0
                const Real ys = y + yInt[i]/eta;
91
0
                const Integer l = (ys > yLoc.back()) ? yLoc.size()-2
92
0
                    : std::upper_bound(yLoc.begin(),
93
0
                                       yLoc.end()-1, ys) - yLoc.begin()-1;
94
95
0
                const Real s = (ys-yLoc[l])/(yLoc[l+1]-yLoc[l]);
96
0
                integroPart_(diag, mesher_->layout()->neighbourhood(iter, 1, l-yIndex))
97
0
                    += weight*lambda*(1-s);
98
0
                integroPart_(diag, mesher_->layout()->neighbourhood(iter, 1, l+1-yIndex))
99
0
                    += weight*lambda*s;
100
0
            }
101
0
        }
102
0
    }
103
104
0
    Size FdmExtOUJumpOp::size() const {
105
0
        return mesher_->layout()->dim().size();;
106
0
    }
107
108
0
    void FdmExtOUJumpOp::setTime(Time t1, Time t2) {
109
0
        ouOp_->setTime(t1, t2);
110
0
    }
111
112
0
    Array FdmExtOUJumpOp::apply(const Array& r) const {
113
0
        return ouOp_->apply(r) + dyMap_.apply(r) + integro(r);
114
0
    }
115
116
0
    Array FdmExtOUJumpOp::apply_mixed(const Array& r) const {
117
0
        return integro(r);
118
0
    }
119
120
    Array FdmExtOUJumpOp::apply_direction(Size direction,
121
0
                                          const Array& r) const {
122
0
        if (direction == 0)
123
0
            return ouOp_->apply_direction(direction, r);
124
0
        else if (direction == 1)
125
0
            return dyMap_.apply(r);
126
0
        else {
127
0
            return Array(r.size(), 0.0);
128
0
        }
129
0
    }
130
131
    Array FdmExtOUJumpOp::solve_splitting(Size direction,
132
0
                                          const Array& r, Real a) const {
133
0
        if (direction == 0) {
134
0
            return ouOp_->solve_splitting(direction, r, a);
135
0
        }
136
0
        else if (direction == 1) {
137
0
            return dyMap_.solve_splitting(r, a, 1.0);
138
0
        }
139
0
        else {
140
0
            return r;
141
0
        }
142
0
    }
143
144
0
    Array FdmExtOUJumpOp::preconditioner(const Array& r, Real dt) const {
145
0
        return ouOp_->solve_splitting(0, r, dt);
146
0
    }
147
148
0
    Array FdmExtOUJumpOp::integro(const Array& r) const {
149
0
        return prod(integroPart_, r);
150
0
    }
151
152
0
    std::vector<SparseMatrix> FdmExtOUJumpOp::toMatrixDecomp() const {
153
0
        QL_REQUIRE(bcSet_.empty(), "boundary conditions are not supported");
154
155
0
        std::vector<SparseMatrix> retVal(1, ouOp_->toMatrixDecomp().front());
156
0
        retVal.push_back(dyMap_.toMatrix());
157
0
        retVal.push_back(integroPart_);
158
159
0
        return retVal;
160
0
    }
161
162
}