Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
randomvariable_ops.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2023 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#include <ql/math/comparison.hpp>
22
23#include <boost/math/distributions/normal.hpp>
24
25namespace QuantExt {
26
27std::vector<RandomVariableOp> getRandomVariableOps(const Size size, const Size regressionOrder,
28 QuantLib::LsmBasisSystem::PolynomialType polynomType,
29 const double eps, QuantLib::Real regressionVarianceCutoff) {
30 std::vector<RandomVariableOp> ops;
31
32 // None = 0
33 ops.push_back([](const std::vector<const RandomVariable*>& args) { return RandomVariable(); });
34
35 // Add = 1
36 ops.push_back([](const std::vector<const RandomVariable*>& args) { return *args[0] + (*args[1]); });
37
38 // Subtract = 2
39 ops.push_back([](const std::vector<const RandomVariable*>& args) { return *args[0] - (*args[1]); });
40
41 // Negative = 3
42 ops.push_back([](const std::vector<const RandomVariable*>& args) { return -(*args[0]); });
43
44 // Mult = 4
45 ops.push_back([](const std::vector<const RandomVariable*>& args) { return *args[0] * (*args[1]); });
46
47 // Div = 5
48 ops.push_back([](const std::vector<const RandomVariable*>& args) { return *args[0] / (*args[1]); });
49
50 // ConditionalExpectation = 6
51 ops.push_back([size, regressionOrder, polynomType,
52 regressionVarianceCutoff](const std::vector<const RandomVariable*>& args) {
53 std::vector<const RandomVariable*> regressor;
54 for (auto r = std::next(args.begin(), 2); r != args.end(); ++r) {
55 if ((*r)->initialised() && !(*r)->deterministic())
56 regressor.push_back(*r);
57 }
58 std::vector<RandomVariable> transformedRegressor;
59 Matrix coordinateTransform;
60 if (regressionVarianceCutoff != Null<Real>()) {
61 coordinateTransform = pcaCoordinateTransform(regressor, regressionVarianceCutoff);
62 transformedRegressor = applyCoordinateTransform(regressor, coordinateTransform);
63 regressor = vec2vecptr(transformedRegressor);
64 }
65 if (regressor.empty())
66 return expectation(*args[0]);
67 else {
68 auto tmp = multiPathBasisSystem(regressor.size(), regressionOrder, polynomType, size);
69 return conditionalExpectation(*args[0], regressor, tmp, !close_enough(*args[1], RandomVariable(size, 0.0)));
70 }
71 });
72
73 // IndicatorEq = 7
74 ops.push_back([](const std::vector<const RandomVariable*>& args) { return indicatorEq(*args[0], *args[1]); });
75
76 // IndicatorGt = 8
77 ops.push_back([eps](const std::vector<const RandomVariable*>& args) {
78 return indicatorGt(*args[0], *args[1], 1.0, 0.0, eps);
79 });
80
81 // IndicatorGeq = 9
82 ops.push_back([eps](const std::vector<const RandomVariable*>& args) {
83 return indicatorGeq(*args[0], *args[1], 1.0, 0.0, eps);
84 });
85
86 // Min = 10
87 if (eps == 0.0) {
88 ops.push_back(
89 [](const std::vector<const RandomVariable*>& args) { return QuantExt::min(*args[0], *args[1]); });
90 } else {
91 ops.push_back([eps](const std::vector<const RandomVariable*>& args) {
92 return indicatorGt(*args[0], *args[1], 1.0, 0.0, eps) * (*args[1] - *args[0]) + *args[0];
93 });
94 }
95
96 // Max = 11
97 if (eps == 0.0) {
98 ops.push_back(
99 [](const std::vector<const RandomVariable*>& args) { return QuantExt::max(*args[0], *args[1]); });
100 } else {
101 ops.push_back([eps](const std::vector<const RandomVariable*>& args) {
102 return indicatorGt(*args[0], *args[1], 1.0, 0.0, eps) * (*args[0] - *args[1]) + *args[1];
103 });
104 }
105
106 // Abs = 12
107 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::abs(*args[0]); });
108
109 // Exp = 13
110 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::exp(*args[0]); });
111
112 // Sqrt = 14
113 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::sqrt(*args[0]); });
114
115 // Log = 15
116 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::log(*args[0]); });
117
118 // Pow = 16
119 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::pow(*args[0], *args[1]); });
120
121 // NormalCdf = 17
122 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::normalCdf(*args[0]); });
123
124 // NormalPdf = 18
125 ops.push_back([](const std::vector<const RandomVariable*>& args) { return QuantExt::normalPdf(*args[0]); });
126
127 return ops;
128}
129
130std::vector<RandomVariableGrad> getRandomVariableGradients(const Size size, const Size regressionOrder,
131 const QuantLib::LsmBasisSystem::PolynomialType polynomType,
132 const double eps, const Real regressionVarianceCutoff) {
133
134 std::vector<RandomVariableGrad> grads;
135
136 // None = 0
137 grads.push_back([](const std::vector<const RandomVariable*>& args,
138 const RandomVariable* v) -> std::vector<RandomVariable> { return {RandomVariable()}; });
139
140 // Add = 1
141 grads.push_back(
142 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
143 return {RandomVariable(size, 1.0), RandomVariable(size, 1.0)};
144 });
145
146 // Subtract = 2
147 grads.push_back(
148 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
149 return {RandomVariable(size, 1.0), RandomVariable(size, -1.0)};
150 });
151
152 // Negative = 3
153 grads.push_back(
154 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
155 return {RandomVariable(size, -1.0)};
156 });
157
158 // Mult = 4
159 grads.push_back(
160 [](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
161 return {*args[1], *args[0]};
162 });
163
164 // Div = 5
165 grads.push_back(
166 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
167 return {RandomVariable(size, 1.0) / *args[1], -*args[0] / (*args[1] * *args[1])};
168 });
169
170 // ConditionalExpectation = 6
171 grads.push_back(
172 [](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
173 QL_FAIL("gradient of conditional expectation not implemented");
174 });
175
176 // IndicatorEq = 7
177 grads.push_back(
178 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
179 return {RandomVariable(size, 0.0), RandomVariable(size, 0.0)};
180 });
181
182 // IndicatorGt = 8
183 grads.push_back(
184 [eps](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
185 RandomVariable tmp = indicatorDerivative(*args[0] - *args[1], eps);
186 return {tmp, -tmp};
187 });
188
189 // IndicatorGeq = 9
190 grads.push_back(grads.back());
191
192 // Min = 10
193 grads.push_back([eps](const std::vector<const RandomVariable*>& args,
194 const RandomVariable* v) -> std::vector<RandomVariable> {
195 return {
196 indicatorDerivative(*args[1] - *args[0], eps) * (*args[1] - *args[0]) + indicatorGeq(*args[1], *args[0]),
197 indicatorDerivative(*args[0] - *args[1], eps) * (*args[0] - *args[1]) + indicatorGeq(*args[0], *args[1])};
198 });
199
200 // Max = 11
201 grads.push_back([eps](const std::vector<const RandomVariable*>& args,
202 const RandomVariable* v) -> std::vector<RandomVariable> {
203 return {
204 indicatorDerivative(*args[0] - *args[1], eps) * (*args[0] - *args[1]) + indicatorGeq(*args[0], *args[1]),
205 indicatorDerivative(*args[1] - *args[0], eps) * (*args[1] - *args[0]) + indicatorGeq(*args[1], *args[0])};
206 });
207
208 // Abs = 12
209 grads.push_back(
210 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
211 return {indicatorGeq(*args[0], RandomVariable(size, 0.0), 1.0, -1.0)};
212 });
213
214 // Exp = 13
215 grads.push_back([](const std::vector<const RandomVariable*>& args,
216 const RandomVariable* v) -> std::vector<RandomVariable> { return {*v}; });
217
218 // Sqrt = 14
219 grads.push_back(
220 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
221 return {RandomVariable(size, 0.5) / *v};
222 });
223
224 // Log = 15
225 grads.push_back(
226 [size](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
227 return {RandomVariable(size, 1.0) / *args[0]};
228 });
229
230 // Pow = 16
231 grads.push_back(
232 [](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
233 return {*args[1] / *args[0] * (*v), QuantExt::log(*args[0]) * (*v)};
234 });
235
236 // NormalCdf = 17
237 grads.push_back(
238 [](const std::vector<const RandomVariable*>& args, const RandomVariable* v) -> std::vector<RandomVariable> {
239 return {QuantExt::normalPdf(*args[0])};
240 });
241
242 // NormalPdf = 18
243 grads.push_back([](const std::vector<const RandomVariable*>& args,
244 const RandomVariable* v) -> std::vector<RandomVariable> { return {-(*args[0]) * *v}; });
245
246 return grads;
247}
248
249std::vector<RandomVariableOpNodeRequirements> getRandomVariableOpNodeRequirements() {
250 std::vector<RandomVariableOpNodeRequirements> res;
251
252 // None = 0
253 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), false); });
254
255 // Add = 1
256 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), false); });
257
258 // Subtract = 1
259 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), false); });
260
261 // Negative = 3
262 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), false); });
263
264 // Mult = 4
265 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
266
267 // Div = 5
268 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
269
270 // ConditionalExpectation = 6
271 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), true); });
272
273 // IndicatorEq = 7
274 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), false); });
275
276 // IndicatorGt = 8
277 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
278
279 // IndicatorGeq = 9
280 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
281
282 // Min = 10
283 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
284
285 // Max = 11
286 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
287
288 // Abs = 12
289 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
290
291 // Exp = 13
292 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), true); });
293
294 // Sqrt = 14
295 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, false), true); });
296
297 // Log = 15
298 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
299
300 // Pow = 16
301 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), true); });
302
303 // NormalCdf = 17
304 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), false); });
305
306 // NormalCdf = 18
307 res.push_back([](const std::size_t nArgs) { return std::make_pair(std::vector<bool>(nArgs, true), true); });
308
309 return res;
310}
311
312} // namespace QuantExt
std::vector< RandomVariableGrad > getRandomVariableGradients(const Size size, const Size regressionOrder, const QuantLib::LsmBasisSystem::PolynomialType polynomType, const double eps, const Real regressionVarianceCutoff)
std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > multiPathBasisSystem(Size dim, Size order, QuantLib::LsmBasisSystem::PolynomialType type, Size basisSystemSizeBound)
RandomVariable sqrt(RandomVariable x)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
CompiledFormula exp(CompiledFormula x)
CompiledFormula min(CompiledFormula x, const CompiledFormula &y)
RandomVariable indicatorDerivative(const RandomVariable &x, const double eps)
std::vector< RandomVariableOpNodeRequirements > getRandomVariableOpNodeRequirements()
CompiledFormula pow(CompiledFormula x, const CompiledFormula &y)
std::vector< const RandomVariable * > vec2vecptr(const std::vector< RandomVariable > &values)
RandomVariable expectation(const RandomVariable &r)
RandomVariable normalCdf(RandomVariable x)
RandomVariable conditionalExpectation(const std::vector< const RandomVariable * > &regressor, const std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > &basisFn, const Array &coefficients)
RandomVariable indicatorGeq(RandomVariable x, const RandomVariable &y, const Real trueVal, const Real falseVal, const Real eps)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)
CompiledFormula abs(CompiledFormula x)
RandomVariable indicatorEq(RandomVariable x, const RandomVariable &y, const Real trueVal, const Real falseVal)
RandomVariable normalPdf(RandomVariable x)
Matrix pcaCoordinateTransform(const std::vector< const RandomVariable * > &regressor, const Real varianceCutoff)
CompiledFormula log(CompiledFormula x)
std::vector< RandomVariableOp > getRandomVariableOps(const Size size, const Size regressionOrder, QuantLib::LsmBasisSystem::PolynomialType polynomType, const double eps, QuantLib::Real regressionVarianceCutoff)
RandomVariable indicatorGt(RandomVariable x, const RandomVariable &y, const Real trueVal, const Real falseVal, const Real eps)
std::vector< RandomVariable > applyCoordinateTransform(const std::vector< const RandomVariable * > &regressor, const Matrix &transform)
ops for type randomvariable