/src/quantlib/ql/methods/finitedifferences/finitedifferencemodel.hpp
Line | Count | Source |
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 | | |
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 finitedifferencemodel.hpp |
21 | | \brief generic finite difference model |
22 | | */ |
23 | | |
24 | | #ifndef quantlib_finite_difference_model_hpp |
25 | | #define quantlib_finite_difference_model_hpp |
26 | | |
27 | | #include <ql/methods/finitedifferences/boundarycondition.hpp> |
28 | | #include <ql/methods/finitedifferences/operatortraits.hpp> |
29 | | #include <ql/methods/finitedifferences/stepcondition.hpp> |
30 | | #include <utility> |
31 | | |
32 | | namespace QuantLib { |
33 | | |
34 | | //! Generic finite difference model |
35 | | /*! \ingroup findiff */ |
36 | | template<class Evolver> |
37 | | class FiniteDifferenceModel { |
38 | | public: |
39 | | typedef typename Evolver::traits traits; |
40 | | typedef typename traits::operator_type operator_type; |
41 | | typedef typename traits::array_type array_type; |
42 | | typedef typename traits::bc_set bc_set; |
43 | | typedef typename traits::condition_type condition_type; |
44 | | // constructors |
45 | | FiniteDifferenceModel(const operator_type& L, |
46 | | const bc_set& bcs, |
47 | | std::vector<Time> stoppingTimes = std::vector<Time>()) |
48 | | : evolver_(L, bcs), stoppingTimes_(std::move(stoppingTimes)) { |
49 | | std::sort(stoppingTimes_.begin(), stoppingTimes_.end()); |
50 | | auto last = std::unique(stoppingTimes_.begin(), stoppingTimes_.end()); |
51 | | stoppingTimes_.erase(last, stoppingTimes_.end()); |
52 | | } |
53 | | FiniteDifferenceModel(Evolver evolver, |
54 | | std::vector<Time> stoppingTimes = std::vector<Time>()) |
55 | 3.15k | : evolver_(std::move(evolver)), stoppingTimes_(std::move(stoppingTimes)) { |
56 | 3.15k | std::sort(stoppingTimes_.begin(), stoppingTimes_.end()); |
57 | 3.15k | auto last = std::unique(stoppingTimes_.begin(), stoppingTimes_.end()); |
58 | 3.15k | stoppingTimes_.erase(last, stoppingTimes_.end()); |
59 | 3.15k | } Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ImplicitEulerScheme>::FiniteDifferenceModel(QuantLib::ImplicitEulerScheme, std::__1::vector<double, std::__1::allocator<double> >) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::HundsdorferScheme>::FiniteDifferenceModel(QuantLib::HundsdorferScheme, std::__1::vector<double, std::__1::allocator<double> >) QuantLib::FiniteDifferenceModel<QuantLib::DouglasScheme>::FiniteDifferenceModel(QuantLib::DouglasScheme, std::__1::vector<double, std::__1::allocator<double> >) Line | Count | Source | 55 | 3.15k | : evolver_(std::move(evolver)), stoppingTimes_(std::move(stoppingTimes)) { | 56 | 3.15k | std::sort(stoppingTimes_.begin(), stoppingTimes_.end()); | 57 | 3.15k | auto last = std::unique(stoppingTimes_.begin(), stoppingTimes_.end()); | 58 | 3.15k | stoppingTimes_.erase(last, stoppingTimes_.end()); | 59 | 3.15k | } |
Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::CrankNicolsonScheme>::FiniteDifferenceModel(QuantLib::CrankNicolsonScheme, std::__1::vector<double, std::__1::allocator<double> >) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::CraigSneydScheme>::FiniteDifferenceModel(QuantLib::CraigSneydScheme, std::__1::vector<double, std::__1::allocator<double> >) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ModifiedCraigSneydScheme>::FiniteDifferenceModel(QuantLib::ModifiedCraigSneydScheme, std::__1::vector<double, std::__1::allocator<double> >) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ExplicitEulerScheme>::FiniteDifferenceModel(QuantLib::ExplicitEulerScheme, std::__1::vector<double, std::__1::allocator<double> >) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::MethodOfLinesScheme>::FiniteDifferenceModel(QuantLib::MethodOfLinesScheme, std::__1::vector<double, std::__1::allocator<double> >) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::TrBDF2Scheme<QuantLib::CraigSneydScheme> >::FiniteDifferenceModel(QuantLib::TrBDF2Scheme<QuantLib::CraigSneydScheme>, std::__1::vector<double, std::__1::allocator<double> >) |
60 | | // methods |
61 | | // array_type grid() const { return evolver.xGrid(); } |
62 | | const Evolver& evolver() const{ return evolver_; } |
63 | | /*! solves the problem between the given times. |
64 | | \warning being this a rollback, <tt>from</tt> must be a later |
65 | | time than <tt>to</tt>. |
66 | | */ |
67 | | void rollback(array_type& a, |
68 | | Time from, |
69 | | Time to, |
70 | | Size steps) { |
71 | | rollbackImpl(a, from, to, steps, |
72 | | static_cast<const condition_type*>(nullptr)); |
73 | | } |
74 | | /*! solves the problem between the given times, |
75 | | applying a condition at every step. |
76 | | \warning being this a rollback, <tt>from</tt> must be a later |
77 | | time than <tt>to</tt>. |
78 | | */ |
79 | | void rollback(array_type& a, |
80 | | Time from, |
81 | | Time to, |
82 | | Size steps, |
83 | 3.15k | const condition_type& condition) { |
84 | 3.15k | rollbackImpl(a,from,to,steps,&condition); |
85 | 3.15k | } Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ImplicitEulerScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::HundsdorferScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) QuantLib::FiniteDifferenceModel<QuantLib::DouglasScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Line | Count | Source | 83 | 3.15k | const condition_type& condition) { | 84 | 3.15k | rollbackImpl(a,from,to,steps,&condition); | 85 | 3.15k | } |
Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::CrankNicolsonScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::CraigSneydScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ModifiedCraigSneydScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ExplicitEulerScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::MethodOfLinesScheme>::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::TrBDF2Scheme<QuantLib::CraigSneydScheme> >::rollback(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const&) |
86 | | private: |
87 | | void rollbackImpl(array_type& a, |
88 | | Time from, |
89 | | Time to, |
90 | | Size steps, |
91 | 3.15k | const condition_type* condition) { |
92 | | |
93 | 3.15k | QL_REQUIRE(from >= to, |
94 | 3.15k | "trying to roll back from " << from << " to " << to); |
95 | | |
96 | 3.15k | Time dt = (from-to)/steps, t = from; |
97 | 3.15k | evolver_.setStep(dt); |
98 | | |
99 | 3.15k | if(!stoppingTimes_.empty() && stoppingTimes_.back() == from) { |
100 | 0 | if (condition) |
101 | 0 | condition->applyTo(a,from); |
102 | 0 | } |
103 | 238k | for (Size i=0; i<steps; ++i, t -= dt) { |
104 | 235k | Time now = t; |
105 | | // make sure last step ends exactly on "to" in order to not |
106 | | // miss a stopping time at "to" due to numerical issues |
107 | 235k | Time next = (i < steps -1)? t-dt : to; |
108 | | |
109 | 235k | if (std::fabs(to-next) < std::sqrt(QL_EPSILON)) next = to; |
110 | 235k | bool hit = false; |
111 | 470k | for (Integer j = static_cast<Integer>(stoppingTimes_.size())-1; j >= 0 ; --j) { |
112 | 235k | if (next <= stoppingTimes_[j] && stoppingTimes_[j] < now) { |
113 | | // a stopping time was hit |
114 | 3.15k | hit = true; |
115 | | |
116 | | // perform a small step to stoppingTimes_[j]... |
117 | 3.15k | evolver_.setStep(now-stoppingTimes_[j]); |
118 | 3.15k | evolver_.step(a,now); |
119 | 3.15k | if (condition) |
120 | 3.15k | condition->applyTo(a,stoppingTimes_[j]); |
121 | | // ...and continue the cycle |
122 | 3.15k | now = stoppingTimes_[j]; |
123 | 3.15k | } |
124 | 235k | } |
125 | | // if we did hit... |
126 | 235k | if (hit) { |
127 | | // ...we might have to make a small step to |
128 | | // complete the big one... |
129 | 3.15k | if (now > next) { |
130 | 3.15k | evolver_.setStep(now - next); |
131 | 3.15k | evolver_.step(a,now); |
132 | 3.15k | if (condition) |
133 | 3.15k | condition->applyTo(a,next); |
134 | 3.15k | } |
135 | | // ...and in any case, we have to reset the |
136 | | // evolver to the default step. |
137 | 3.15k | evolver_.setStep(dt); |
138 | 232k | } else { |
139 | | // if we didn't, the evolver is already set to the |
140 | | // default step, which is ok for us. |
141 | 232k | evolver_.step(a,now); |
142 | 232k | if (condition) |
143 | 232k | condition->applyTo(a, next); |
144 | 232k | } |
145 | 235k | } |
146 | 3.15k | } Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ImplicitEulerScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::HundsdorferScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) QuantLib::FiniteDifferenceModel<QuantLib::DouglasScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Line | Count | Source | 91 | 3.15k | const condition_type* condition) { | 92 | | | 93 | 3.15k | QL_REQUIRE(from >= to, | 94 | 3.15k | "trying to roll back from " << from << " to " << to); | 95 | | | 96 | 3.15k | Time dt = (from-to)/steps, t = from; | 97 | 3.15k | evolver_.setStep(dt); | 98 | | | 99 | 3.15k | if(!stoppingTimes_.empty() && stoppingTimes_.back() == from) { | 100 | 0 | if (condition) | 101 | 0 | condition->applyTo(a,from); | 102 | 0 | } | 103 | 238k | for (Size i=0; i<steps; ++i, t -= dt) { | 104 | 235k | Time now = t; | 105 | | // make sure last step ends exactly on "to" in order to not | 106 | | // miss a stopping time at "to" due to numerical issues | 107 | 235k | Time next = (i < steps -1)? t-dt : to; | 108 | | | 109 | 235k | if (std::fabs(to-next) < std::sqrt(QL_EPSILON)) next = to; | 110 | 235k | bool hit = false; | 111 | 470k | for (Integer j = static_cast<Integer>(stoppingTimes_.size())-1; j >= 0 ; --j) { | 112 | 235k | if (next <= stoppingTimes_[j] && stoppingTimes_[j] < now) { | 113 | | // a stopping time was hit | 114 | 3.15k | hit = true; | 115 | | | 116 | | // perform a small step to stoppingTimes_[j]... | 117 | 3.15k | evolver_.setStep(now-stoppingTimes_[j]); | 118 | 3.15k | evolver_.step(a,now); | 119 | 3.15k | if (condition) | 120 | 3.15k | condition->applyTo(a,stoppingTimes_[j]); | 121 | | // ...and continue the cycle | 122 | 3.15k | now = stoppingTimes_[j]; | 123 | 3.15k | } | 124 | 235k | } | 125 | | // if we did hit... | 126 | 235k | if (hit) { | 127 | | // ...we might have to make a small step to | 128 | | // complete the big one... | 129 | 3.15k | if (now > next) { | 130 | 3.15k | evolver_.setStep(now - next); | 131 | 3.15k | evolver_.step(a,now); | 132 | 3.15k | if (condition) | 133 | 3.15k | condition->applyTo(a,next); | 134 | 3.15k | } | 135 | | // ...and in any case, we have to reset the | 136 | | // evolver to the default step. | 137 | 3.15k | evolver_.setStep(dt); | 138 | 232k | } else { | 139 | | // if we didn't, the evolver is already set to the | 140 | | // default step, which is ok for us. | 141 | 232k | evolver_.step(a,now); | 142 | 232k | if (condition) | 143 | 232k | condition->applyTo(a, next); | 144 | 232k | } | 145 | 235k | } | 146 | 3.15k | } |
Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::CrankNicolsonScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::CraigSneydScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ModifiedCraigSneydScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::ExplicitEulerScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::MethodOfLinesScheme>::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) Unexecuted instantiation: QuantLib::FiniteDifferenceModel<QuantLib::TrBDF2Scheme<QuantLib::CraigSneydScheme> >::rollbackImpl(QuantLib::Array&, double, double, unsigned long, QuantLib::StepCondition<QuantLib::Array> const*) |
147 | | Evolver evolver_; |
148 | | std::vector<Time> stoppingTimes_; |
149 | | }; |
150 | | |
151 | | } |
152 | | |
153 | | |
154 | | #endif |