Coverage Report

Created: 2026-10-31 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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