Skip to content

Commit 49dd75d

Browse files
authored
Avoid storing references in GSR and Markov-functional state processes (#2418)
2 parents f0a38c3 + 332e795 commit 49dd75d

File tree

10 files changed

+115
-49
lines changed

10 files changed

+115
-49
lines changed

ql/models/shortrate/onefactormodels/gsr.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,10 @@ namespace QuantLib {
9090
}
9191

9292
void Gsr::update() {
93-
if (stateProcess_ != nullptr)
93+
if (stateProcess_ != nullptr) {
9494
ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
95+
ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();
96+
}
9597
LazyObject::update();
9698
}
9799

@@ -110,21 +112,25 @@ void Gsr::updateTimes() const {
110112
<< volsteptimes_[j - 1] << "@" << (j - 1) << ", "
111113
<< volsteptimes_[j] << "@" << j << ")");
112114
}
113-
if (stateProcess_ != nullptr)
115+
if (stateProcess_ != nullptr) {
114116
ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
117+
ext::static_pointer_cast<GsrProcess>(stateProcess_)->setTimes(volsteptimesArray_);
118+
}
115119
}
116120

117121
void Gsr::updateVolatility() {
118122
for (Size i = 0; i < sigma_.size(); i++) {
119123
sigma_.setParam(i, volatilities_[i]->value());
120124
}
125+
ext::static_pointer_cast<GsrProcess>(stateProcess_)->setVols(sigma_.params());
121126
update();
122127
}
123128

124129
void Gsr::updateReversion() {
125130
for (Size i = 0; i < reversion_.size(); i++) {
126131
reversion_.setParam(i, reversions_[i]->value());
127132
}
133+
ext::static_pointer_cast<GsrProcess>(stateProcess_)->setReversions(reversion_.params());
128134
update();
129135
}
130136

@@ -186,8 +192,7 @@ Real Gsr::zerobondImpl(const Time T, const Time t, const Real y,
186192
return yts.empty() ? this->termStructure()->discount(T, true)
187193
: yts->discount(T, true);
188194

189-
ext::shared_ptr<GsrProcess> p =
190-
ext::dynamic_pointer_cast<GsrProcess>(stateProcess_);
195+
ext::shared_ptr<GsrProcess> p = ext::static_pointer_cast<GsrProcess>(stateProcess_);
191196

192197
Real x = y * stateProcess_->stdDeviation(0.0, 0.0, t) +
193198
stateProcess_->expectation(0.0, 0.0, t);
@@ -206,8 +211,7 @@ Real Gsr::numeraireImpl(const Time t, const Real y,
206211

207212
calculate();
208213

209-
ext::shared_ptr<GsrProcess> p =
210-
ext::dynamic_pointer_cast<GsrProcess>(stateProcess_);
214+
ext::shared_ptr<GsrProcess> p = ext::static_pointer_cast<GsrProcess>(stateProcess_);
211215

212216
if (t == 0)
213217
return yts.empty()

ql/models/shortrate/onefactormodels/gsr.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ class Gsr : public Gaussian1dModel, public CalibratedModel {
143143

144144
void generateArguments() override {
145145
ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
146+
ext::static_pointer_cast<GsrProcess>(stateProcess_)->setVols(sigma_.params());
147+
ext::static_pointer_cast<GsrProcess>(stateProcess_)->setReversions(reversion_.params());
146148
notifyObservers();
147149
}
148150

ql/models/shortrate/onefactormodels/markovfunctional.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ namespace QuantLib {
107107
<< volsteptimes_[j - 1] << "@" << (j - 1) << ", "
108108
<< volsteptimes_[j] << "@" << j << ")");
109109
}
110+
if (stateProcess_)
111+
ext::static_pointer_cast<MfStateProcess>(stateProcess_)->setTimes(volsteptimesArray_);
110112
}
111113

112114
void MarkovFunctional::updateTimes2() const {

ql/models/shortrate/onefactormodels/markovfunctional.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,11 @@ namespace QuantLib {
378378
zerobondImpl(Time T, Time t, Real y, const Handle<YieldTermStructure>& yts) const override;
379379

380380
void generateArguments() override {
381-
// if calculate triggers performCalculations, updateNumeraireTabulations
382-
// is called twice. If we can not check the lazy object status this seem
383-
// hard to avoid though.
384-
calculate();
385-
updateNumeraireTabulation();
381+
ext::static_pointer_cast<MfStateProcess>(stateProcess_)->setVols(sigma_.params());
382+
if(isCalculated())
383+
updateNumeraireTabulation();
384+
else
385+
calculate();
386386
notifyObservers();
387387
}
388388

ql/processes/gsrprocess.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323

2424
namespace QuantLib {
2525

26-
GsrProcess::GsrProcess(const Array& times,
27-
const Array& vols,
28-
const Array& reversions,
26+
GsrProcess::GsrProcess(Array times,
27+
Array vols,
28+
Array reversions,
2929
const Real T,
3030
const Date& referenceDate,
3131
DayCounter dc)
32-
: ForwardMeasureProcess1D(T), core_(times, vols, reversions, T), referenceDate_(referenceDate),
32+
: ForwardMeasureProcess1D(T), core_(std::move(times), std::move(vols), std::move(reversions), T), referenceDate_(referenceDate),
3333
dc_(std::move(dc)) {
3434
flushCache();
3535
}

ql/processes/gsrprocess.hpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ namespace QuantLib {
3939
/*! \ingroup processes */
4040
class GsrProcess : public ForwardMeasureProcess1D {
4141
public:
42-
GsrProcess(const Array& times,
43-
const Array& vols,
44-
const Array& reversions,
42+
GsrProcess(Array times,
43+
Array vols,
44+
Array reversions,
4545
Real T = 60.0,
4646
const Date& referenceDate = Date(),
4747
DayCounter dc = DayCounter());
@@ -56,19 +56,26 @@ namespace QuantLib {
5656
Real time(const Date& d) const override;
5757
//@}
5858
//! \name ForwardMeasureProcess1D interface
59+
//@{
5960
void setForwardMeasureTime(Time t) override;
6061
//@}
6162
//! additional inspectors
63+
//@{
6264
Real sigma(Time t) const;
6365
Real reversion(Time t) const;
6466
Real y(Time t) const;
6567
Real G(Time t, Time T, Real x) const;
68+
//@}
6669
//! reset cache
6770
void flushCache() const;
6871

6972
private:
73+
friend class Gsr;
74+
void setTimes(Array times) { core_.setTimes(std::move(times)); }
75+
void setVols(Array vols) { core_.setVols(std::move(vols)); }
76+
void setReversions(Array reversions) { core_.setReversions(std::move(reversions)); }
7077
void checkT(Time t) const;
71-
const detail::GsrProcessCore core_;
78+
detail::GsrProcessCore core_;
7279
Date referenceDate_;
7380
DayCounter dc_;
7481
};

ql/processes/gsrprocesscore.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,44 @@ using std::pow;
2525

2626
namespace QuantLib::detail {
2727

28-
GsrProcessCore::GsrProcessCore(const Array &times, const Array &vols,
29-
const Array &reversions, const Real T)
30-
: times_(times), vols_(vols), reversions_(reversions),
31-
T_(T), revZero_(reversions.size(), false) {
28+
GsrProcessCore::GsrProcessCore(Array times, Array vols,
29+
Array reversions, const Real T)
30+
: times_(std::move(times)), vols_(std::move(vols)), reversions_(std::move(reversions)),
31+
T_(T), revZero_(reversions_.size(), false) {
32+
flushCache();
33+
checkTimesVolsReversions();
34+
}
3235

33-
QL_REQUIRE(times.size() == vols.size() - 1,
36+
void GsrProcessCore::setTimes(Array times) {
37+
times_ = std::move(times);
38+
checkTimesVolsReversions();
39+
}
40+
41+
void GsrProcessCore::setVols(Array vols) {
42+
vols_ = std::move(vols);
43+
checkTimesVolsReversions();
44+
}
45+
46+
void GsrProcessCore::setReversions(Array reversions) {
47+
reversions_ = std::move(reversions);
48+
checkTimesVolsReversions();
49+
}
50+
51+
void GsrProcessCore::checkTimesVolsReversions() const {
52+
QL_REQUIRE(times_.size() == vols_.size() - 1,
3453
"number of volatilities ("
35-
<< vols.size() << ") compared to number of times ("
54+
<< vols_.size() << ") compared to number of times ("
3655
<< times_.size() << " must be bigger by one");
37-
QL_REQUIRE(times.size() == reversions.size() - 1 || reversions.size() == 1,
56+
QL_REQUIRE(times_.size() == reversions_.size() - 1 || reversions_.size() == 1,
3857
"number of reversions ("
39-
<< vols.size() << ") compared to number of times ("
58+
<< vols_.size() << ") compared to number of times ("
4059
<< times_.size() << " must be bigger by one, or exactly "
4160
"1 reversion must be given");
42-
for (int i = 0; i < ((int)times.size()) - 1; i++)
43-
QL_REQUIRE(times[i] < times[i + 1], "times must be increasing ("
44-
<< times[i] << "@" << i << " , "
45-
<< times[i + 1] << "@" << i + 1
61+
for (int i = 0; i < ((int)times_.size()) - 1; i++)
62+
QL_REQUIRE(times_[i] < times_[i + 1], "times must be increasing ("
63+
<< times_[i] << "@" << i << " , "
64+
<< times_[i + 1] << "@" << i + 1
4665
<< ")");
47-
flushCache();
4866
}
4967

5068
void GsrProcessCore::flushCache() const {

ql/processes/gsrprocesscore.hpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@
3232
#include <ql/math/comparison.hpp>
3333
#include <map>
3434

35-
namespace QuantLib::detail {
35+
namespace QuantLib {
36+
37+
class GsrProcess;
38+
39+
namespace detail {
3640

3741
class GsrProcessCore {
3842
public:
39-
GsrProcessCore(const Array& times, const Array& vols, const Array& reversions, Real T = 60.0);
43+
GsrProcessCore(Array times, Array vols, Array reversions, Real T = 60.0);
4044

4145
// conditional expectation, x0 dependent part
4246
Real expectation_x0dep_part(Time w, Real xw, Time dt) const;
@@ -68,9 +72,14 @@ class GsrProcessCore {
6872
void flushCache() const;
6973

7074
protected:
71-
const Array &times_, &vols_, &reversions_;
75+
Array times_, vols_, reversions_;
7276

7377
private:
78+
friend class QuantLib::GsrProcess;
79+
void setTimes(Array times);
80+
void setVols(Array vols);
81+
void setReversions(Array reversions);
82+
void checkTimesVolsReversions() const;
7483
int lowerIndex(Time t) const;
7584
int upperIndex(Time t) const;
7685
Real time2(Size index) const;
@@ -97,6 +106,7 @@ inline Real GsrProcessCore::reversion(const Time t) const {
97106
return rev(lowerIndex(t));
98107
}
99108

109+
} // namespace detail
100110
} // namespace QuantLib
101111

102112
#endif

ql/processes/mfstateprocess.cpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,38 @@
2121

2222
namespace QuantLib {
2323

24-
MfStateProcess::MfStateProcess(Real reversion, const Array& times, const Array& vols)
25-
: reversion_(reversion), times_(times), vols_(vols) {
24+
MfStateProcess::MfStateProcess(Real reversion, Array times, Array vols)
25+
: reversion_(reversion), times_(std::move(times)), vols_(std::move(vols)) {
2626
if (reversion_ < QL_EPSILON && -reversion_ < QL_EPSILON)
2727
reversionZero_ = true;
28-
QL_REQUIRE(times.size() == vols.size() - 1,
28+
checkTimesVols();
29+
}
30+
31+
void MfStateProcess::setTimes(Array times) {
32+
times_ = std::move(times);
33+
checkTimesVols();
34+
notifyObservers();
35+
}
36+
37+
void MfStateProcess::setVols(Array vols) {
38+
vols_ = std::move(vols);
39+
checkTimesVols();
40+
notifyObservers();
41+
}
42+
43+
void MfStateProcess::checkTimesVols() const {
44+
QL_REQUIRE(times_.size() == vols_.size() - 1,
2945
"number of volatilities ("
30-
<< vols.size() << ") compared to number of times ("
46+
<< vols_.size() << ") compared to number of times ("
3147
<< times_.size() << " must be bigger by one");
32-
for (int i = 0; i < ((int)times.size()) - 1; i++)
33-
QL_REQUIRE(times[i] < times[i + 1], "times must be increasing ("
34-
<< times[i] << "@" << i
35-
<< " , " << times[i + 1]
48+
for (int i = 0; i < ((int)times_.size()) - 1; i++)
49+
QL_REQUIRE(times_[i] < times_[i + 1], "times must be increasing ("
50+
<< times_[i] << "@" << i
51+
<< " , " << times_[i + 1]
3652
<< "@" << i + 1 << ")");
37-
for (Size i = 0; i < vols.size(); i++)
38-
QL_REQUIRE(vols[i] >= 0.0, "volatilities must be non negative ("
39-
<< vols[i] << "@" << i << ")");
53+
for (Size i = 0; i < vols_.size(); i++)
54+
QL_REQUIRE(vols_[i] >= 0.0, "volatilities must be non negative ("
55+
<< vols_[i] << "@" << i << ")");
4056
}
4157

4258
Real MfStateProcess::x0() const { return 0.0; }

ql/processes/mfstateprocess.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@
2828

2929
namespace QuantLib {
3030

31+
class MarkovFunctional;
32+
3133
//! Markov functional state process class
3234
/*! This class describes the process governed by
3335
\f[ dx = \sigma(t) e^{at} dW(t) \f]
3436
\ingroup processes
3537
*/
3638
class MfStateProcess : public StochasticProcess1D {
3739
public:
38-
MfStateProcess(Real reversion, const Array &times, const Array &vols);
40+
MfStateProcess(Real reversion, Array times, Array vols);
3941

4042
//! \name StochasticProcess interface
4143
//@{
@@ -46,11 +48,16 @@ namespace QuantLib {
4648
Real stdDeviation(Time t0, Real x0, Time dt) const override;
4749
Real variance(Time t0, Real x0, Time dt) const override;
4850
//@}
51+
4952
private:
53+
friend class MarkovFunctional;
54+
void setTimes(Array times);
55+
void setVols(Array vols);
56+
void checkTimesVols() const;
5057
Real reversion_;
5158
bool reversionZero_ = false;
52-
const Array &times_;
53-
const Array &vols_;
59+
Array times_;
60+
Array vols_;
5461
};
5562
}
5663

0 commit comments

Comments
 (0)