Coverage Report

Created: 2025-08-11 06:28

/src/quantlib/ql/methods/finitedifferences/tridiagonaloperator.hpp
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) 2000, 2001, 2002, 2003 RiskMap srl
5
 Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl
6
 Copyright (C) 2011 Ferdinando Ametrano
7
8
 This file is part of QuantLib, a free-software/open-source library
9
 for financial quantitative analysts and developers - http://quantlib.org/
10
11
 QuantLib is free software: you can redistribute it and/or modify it
12
 under the terms of the QuantLib license.  You should have received a
13
 copy of the license along with this program; if not, please email
14
 <quantlib-dev@lists.sf.net>. The license is also available online at
15
 <http://quantlib.org/license.shtml>.
16
17
 This program is distributed in the hope that it will be useful, but WITHOUT
18
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 FOR A PARTICULAR PURPOSE.  See the license for more details.
20
*/
21
22
/*! \file tridiagonaloperator.hpp
23
    \brief tridiagonal operator
24
*/
25
26
#ifndef quantlib_tridiagonal_operator_hpp
27
#define quantlib_tridiagonal_operator_hpp
28
29
#include <ql/math/array.hpp>
30
#include <ql/math/comparison.hpp>
31
#include <ql/shared_ptr.hpp>
32
33
namespace QuantLib {
34
35
    //! Base implementation for tridiagonal operator
36
    /*! \warning to use real time-dependant algebra, you must overload
37
                 the corresponding operators in the inheriting
38
                 time-dependent class.
39
40
        \ingroup findiff
41
    */
42
    class TridiagonalOperator {
43
        // unary operators
44
        friend TridiagonalOperator operator+(const TridiagonalOperator&);
45
        friend TridiagonalOperator operator-(const TridiagonalOperator&);
46
        // binary operators
47
        friend TridiagonalOperator operator+(const TridiagonalOperator&,
48
                                             const TridiagonalOperator&);
49
        friend TridiagonalOperator operator-(const TridiagonalOperator&,
50
                                             const TridiagonalOperator&);
51
        friend TridiagonalOperator operator*(Real,
52
                                             const TridiagonalOperator&);
53
        friend TridiagonalOperator operator*(const TridiagonalOperator&,
54
                                             Real);
55
        friend TridiagonalOperator operator/(const TridiagonalOperator&,
56
                                             Real);
57
      public:
58
        typedef Array array_type;
59
        // constructors
60
        explicit TridiagonalOperator(Size size = 0);
61
        TridiagonalOperator(const Array& low,
62
                            const Array& mid,
63
                            const Array& high);
64
        TridiagonalOperator(const TridiagonalOperator&) = default;
65
        TridiagonalOperator(TridiagonalOperator&&) noexcept;
66
        TridiagonalOperator& operator=(const TridiagonalOperator&);
67
        TridiagonalOperator& operator=(TridiagonalOperator&&) noexcept;
68
0
        ~TridiagonalOperator() = default;
69
        //! \name Operator interface
70
        //@{
71
        //! apply operator to a given array
72
        Array applyTo(const Array& v) const;
73
        //! solve linear system for a given right-hand side
74
        Array solveFor(const Array& rhs) const;
75
        /*! solve linear system for a given right-hand side
76
            without result Array allocation. The rhs and result parameters
77
            can be the same Array, in which case rhs will be changed
78
        */
79
        void solveFor(const Array& rhs,
80
                      Array& result) const;
81
        //! solve linear system with SOR approach
82
        Array SOR(const Array& rhs,
83
                  Real tol) const;
84
        //! identity instance
85
        static TridiagonalOperator identity(Size size);
86
        //@}
87
        //! \name Inspectors
88
        //@{
89
0
        Size size() const { return n_; }
90
0
        bool isTimeDependent() const { return !!timeSetter_; }
91
0
        const Array& lowerDiagonal() const { return lowerDiagonal_; }
92
0
        const Array& diagonal() const { return diagonal_; }
93
0
        const Array& upperDiagonal() const { return upperDiagonal_; }
94
        //@}
95
        //! \name Modifiers
96
        //@{
97
        void setFirstRow(Real, Real);
98
        void setMidRow(Size, Real, Real, Real);
99
        void setMidRows(Real, Real, Real);
100
        void setLastRow(Real, Real);
101
        void setTime(Time t);
102
        //@}
103
        //! \name Utilities
104
        //@{
105
        void swap(TridiagonalOperator&) noexcept;
106
        //@}
107
        //! encapsulation of time-setting logic
108
        class TimeSetter {
109
          public:
110
            virtual ~TimeSetter() = default;
111
            virtual void setTime(Time t,
112
                                 TridiagonalOperator& L) const = 0;
113
        };
114
      protected:
115
        Size n_;
116
        Array diagonal_, lowerDiagonal_, upperDiagonal_;
117
        mutable Array temp_;
118
        ext::shared_ptr<TimeSetter> timeSetter_;
119
    };
120
121
    /* \relates TridiagonalOperator */
122
    void swap(TridiagonalOperator&, TridiagonalOperator&) noexcept;
123
124
125
    // inline definitions
126
127
0
    inline TridiagonalOperator::TridiagonalOperator(TridiagonalOperator&& from) noexcept : n_(0) {
128
0
        swap(from);
129
0
    }
130
131
    inline TridiagonalOperator& TridiagonalOperator::operator=(
132
0
                                const TridiagonalOperator& from) {
133
0
        TridiagonalOperator temp(from);
134
0
        swap(temp);
135
0
        return *this;
136
0
    }
137
138
    inline TridiagonalOperator&
139
0
    TridiagonalOperator::operator=(TridiagonalOperator&& from) noexcept {
140
0
        swap(from);
141
0
        return *this;
142
0
    }
143
144
    inline void TridiagonalOperator::setFirstRow(Real valB,
145
0
                                                 Real valC) {
146
0
        diagonal_[0]      = valB;
147
0
        upperDiagonal_[0] = valC;
148
0
    }
149
150
    inline void TridiagonalOperator::setMidRow(Size i,
151
                                               Real valA,
152
                                               Real valB,
153
0
                                               Real valC) {
154
0
        QL_REQUIRE(i>=1 && i<=n_-2,
155
0
                   "out of range in TridiagonalSystem::setMidRow");
156
0
        lowerDiagonal_[i-1] = valA;
157
0
        diagonal_[i]        = valB;
158
0
        upperDiagonal_[i]   = valC;
159
0
    }
Unexecuted instantiation: QuantLib::TridiagonalOperator::setMidRow(unsigned long, double, double, double)
Unexecuted instantiation: QuantLib::TridiagonalOperator::setMidRow(unsigned long, double, double, double)
160
161
    inline void TridiagonalOperator::setMidRows(Real valA,
162
                                                Real valB,
163
0
                                                Real valC) {
164
0
        for (Size i=1; i<=n_-2; i++) {
165
0
            lowerDiagonal_[i-1] = valA;
166
0
            diagonal_[i]        = valB;
167
0
            upperDiagonal_[i]   = valC;
168
0
        }
169
0
    }
170
171
    inline void TridiagonalOperator::setLastRow(Real valA,
172
0
                                                Real valB) {
173
0
        lowerDiagonal_[n_-2] = valA;
174
0
        diagonal_[n_-1]      = valB;
175
0
    }
176
177
0
    inline void TridiagonalOperator::setTime(Time t) {
178
0
        if (timeSetter_ != nullptr)
179
0
            timeSetter_->setTime(t, *this);
180
0
    }
181
182
0
    inline void TridiagonalOperator::swap(TridiagonalOperator& from) noexcept {
183
0
        std::swap(n_, from.n_);
184
0
        diagonal_.swap(from.diagonal_);
185
0
        lowerDiagonal_.swap(from.lowerDiagonal_);
186
0
        upperDiagonal_.swap(from.upperDiagonal_);
187
0
        temp_.swap(from.temp_);
188
0
        timeSetter_.swap(from.timeSetter_);
189
0
    }
190
191
192
    // Time constant algebra
193
194
0
    inline TridiagonalOperator operator+(const TridiagonalOperator& D) {
195
0
        TridiagonalOperator D1 = D;
196
0
        return D1;
197
0
    }
198
199
0
    inline TridiagonalOperator operator-(const TridiagonalOperator& D) {
200
0
        Array low = -D.lowerDiagonal_,
201
0
            mid = -D.diagonal_,
202
0
            high = -D.upperDiagonal_;
203
0
        TridiagonalOperator result(low, mid, high);
204
0
        return result;
205
0
    }
206
207
    inline TridiagonalOperator operator+(const TridiagonalOperator& D1,
208
0
                                         const TridiagonalOperator& D2) {
209
0
        Array low = D1.lowerDiagonal_ + D2.lowerDiagonal_,
210
0
            mid = D1.diagonal_ + D2.diagonal_,
211
0
            high = D1.upperDiagonal_ + D2.upperDiagonal_;
212
0
        TridiagonalOperator result(low, mid, high);
213
0
        return result;
214
0
    }
215
216
    inline TridiagonalOperator operator-(const TridiagonalOperator& D1,
217
0
                                         const TridiagonalOperator& D2) {
218
0
        Array low = D1.lowerDiagonal_ - D2.lowerDiagonal_,
219
0
            mid = D1.diagonal_ - D2.diagonal_,
220
0
            high = D1.upperDiagonal_ - D2.upperDiagonal_;
221
0
        TridiagonalOperator result(low, mid, high);
222
0
        return result;
223
0
    }
224
225
    inline TridiagonalOperator operator*(Real a,
226
0
                                         const TridiagonalOperator& D) {
227
0
        Array low = D.lowerDiagonal_ * a,
228
0
            mid = D.diagonal_ * a,
229
0
            high = D.upperDiagonal_ * a;
230
0
        TridiagonalOperator result(low, mid, high);
231
0
        return result;
232
0
    }
233
234
    inline TridiagonalOperator operator*(const TridiagonalOperator& D,
235
0
                                         Real a) {
236
0
        Array low = D.lowerDiagonal_ * a,
237
0
            mid = D.diagonal_ * a,
238
0
            high = D.upperDiagonal_ * a;
239
0
        TridiagonalOperator result(low, mid, high);
240
0
        return result;
241
0
    }
242
243
    inline TridiagonalOperator operator/(const TridiagonalOperator& D,
244
0
                                         Real a) {
245
0
        Array low = D.lowerDiagonal_ / a,
246
0
            mid = D.diagonal_ / a,
247
0
            high = D.upperDiagonal_ / a;
248
0
        TridiagonalOperator result(low, mid, high);
249
0
        return result;
250
0
    }
251
252
    inline void swap(TridiagonalOperator& L1,
253
0
                     TridiagonalOperator& L2) noexcept {
254
0
        L1.swap(L2);
255
0
    }
256
257
}
258
259
#endif