/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 |