22#include <ql/experimental/math/moorepenroseinverse.hpp>
23#include <ql/math/comparison.hpp>
24#include <ql/math/generallinearleastsquares.hpp>
25#include <ql/math/matrixutilities/qrdecomposition.hpp>
26#include <ql/math/matrixutilities/symmetricschurdecomposition.hpp>
28#include <boost/math/distributions/normal.hpp>
30#include <boost/accumulators/accumulators.hpp>
31#include <boost/accumulators/statistics/covariance.hpp>
32#include <boost/accumulators/statistics/mean.hpp>
33#include <boost/accumulators/statistics/stats.hpp>
34#include <boost/accumulators/statistics/variance.hpp>
35#include <boost/accumulators/statistics/variates/covariate.hpp>
47#ifdef ENABLE_RANDOMVARIABLE_STATS
49inline void resumeDataStats() {
50 if (RandomVariableStats::instance().enabled)
51 RandomVariableStats::instance().data_timer.resume();
54inline void stopDataStats(
const std::size_t n) {
55 if (RandomVariableStats::instance().enabled) {
56 RandomVariableStats::instance().data_timer.stop();
57 RandomVariableStats::instance().data_ops += n;
61inline void resumeCalcStats() {
62 if (RandomVariableStats::instance().enabled)
63 RandomVariableStats::instance().calc_timer.resume();
66inline void stopCalcStats(
const std::size_t n) {
67 if (RandomVariableStats::instance().enabled) {
68 RandomVariableStats::instance().calc_timer.stop();
69 RandomVariableStats::instance().calc_ops += n;
75inline void resumeDataStats() {}
76inline void stopDataStats(
const std::size_t n) {}
77inline void resumeCalcStats() {}
78inline void stopCalcStats(
const std::size_t n) {}
82double getDelta(
const RandomVariable& x,
const Real eps) {
84 for (Size i = 0; i < x.size(); ++i) {
87 return std::sqrt(
sum /
static_cast<Real
>(x.size())) * eps / 2.0;
94Filter::Filter() : n_(0), constantData_(false), data_(nullptr), deterministic_(false) {}
162Filter::Filter(
const Size n,
const bool value) : n_(n), constantData_(value), data_(nullptr), deterministic_(n != 0) {}
178 for (Size i = 0; i <
n_; ++i) {
189 QL_REQUIRE(
n_ > 0,
"Filter::setAll(): dimension is zero");
199 QL_REQUIRE(
deterministic_,
"Filter::resetSize(): only possible for deterministic variables.");
220 for (Size j = 0; j < a.
size(); ++j)
225 stopCalcStats(a.
size());
234 "RandomVariable: x && y: x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
247 for (Size i = 0; i < x.
size(); ++i) {
250 stopCalcStats(x.
size());
257 "RandomVariable: x || y: x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
270 for (Size i = 0; i < x.
size(); ++i) {
273 stopCalcStats(x.
size());
282 "RandomVariable: equal(x,y): x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
289 for (Size i = 0; i < x.
size(); ++i) {
292 stopCalcStats(x.
size());
302 for (Size i = 0; i < x.
size(); ++i) {
305 stopCalcStats(x.
size());
313 : n_(0), constantData_(0.0), data_(nullptr), deterministic_(false), time_(Null<Real>()) {}
386 : n_(n), constantData_(value), data_(nullptr), deterministic_(n != 0), time_(time) {}
397 setAll(f.
at(0) ? valueTrue : valueFalse);
403 for (Size i = 0; i <
n_; ++i)
404 set(i, f[i] ? valueTrue : valueFalse);
434 std::fill(m.column_begin(j), std::next(m.column_end(j),
n_),
constantData_);
461 time_ = Null<Real>();
467 for (Size i = 0; i <
n_; ++i) {
479 QL_REQUIRE(
n_ > 0,
"RandomVariable::setAll(): dimension is zero");
489 QL_REQUIRE(
deterministic_,
"RandomVariable::resetSize(): only possible for deterministic variables.");
504 QL_REQUIRE((
time_ == Null<Real>() || t == Null<Real>()) || QuantLib::close_enough(
time_, t),
505 "RandomVariable: inconsistent times " <<
time_ <<
" and " << t);
506 if (
time_ == Null<Real>())
511 QL_REQUIRE((x.
time() == Null<Real>() || y.
time() == Null<Real>()) || QuantLib::close_enough(x.
time(), y.
time()),
512 "got inconsistent random variable times (" << x.
time() <<
", " << y.
time() <<
")");
522 for (Size j = 0; j < a.
size(); ++j)
528 return QuantLib::close_enough(a.
time(), b.
time());
539 "RandomVariable: x += y: x size (" <<
size() <<
") must be equal to y size (" << y.
size() <<
")");
549 for (Size i = 0; i <
n_; ++i) {
563 "RandomVariable: x -= y: x size (" <<
size() <<
") must be equal to y size (" << y.
size() <<
")");
573 for (Size i = 0; i <
n_; ++i) {
587 "RandomVariable: x *= y: x size (" <<
size() <<
") must be equal to y size (" << y.
size() <<
")");
597 for (Size i = 0; i <
n_; ++i) {
611 "RandomVariable: x /= y: x size (" <<
size() <<
") must be equal to y size (" << y.
size() <<
")");
621 for (Size i = 0; i <
n_; ++i) {
661 "RandomVariable: max(x,y): x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
669 for (Size i = 0; i < x.
size(); ++i) {
672 stopCalcStats(x.
size());
681 "RandomVariable: min(x,y): x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
689 for (Size i = 0; i < x.
size(); ++i) {
692 stopCalcStats(x.
size());
701 "RandomVariable: pow(x,y): x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
711 for (Size i = 0; i < x.
size(); ++i) {
714 stopCalcStats(x.
size());
724 for (Size i = 0; i < x.
n_; ++i) {
737 for (Size i = 0; i < x.
n_; ++i) {
750 for (Size i = 0; i < x.
n_; ++i) {
763 for (Size i = 0; i < x.
n_; ++i) {
776 for (Size i = 0; i < x.
n_; ++i) {
789 for (Size i = 0; i < x.
n_; ++i) {
802 for (Size i = 0; i < x.
n_; ++i) {
811 static const boost::math::normal_distribution<double> n;
816 for (Size i = 0; i < x.
n_; ++i) {
825 static const boost::math::normal_distribution<double> n;
830 for (Size i = 0; i < x.
n_; ++i) {
841 QL_REQUIRE(x.
size() == y.
size(),
"RandomVariable: close_enough(x,y): x size ("
842 << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
849 for (Size i = 0; i < x.
size(); ++i) {
850 result.
set(i, QuantLib::close_enough(x[i], y[i]));
852 stopCalcStats(x.
size());
857 QL_REQUIRE(x.
size() == y.
size(),
"RandomVariable: close_enough_all(x,y): x size ("
858 << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
864 for (Size i = 0; i < x.
size(); ++i) {
865 if (!QuantLib::close_enough(x[i], y[i]))
868 stopCalcStats(x.
size());
876 "conditionalResult(f,x,y): f size (" << f.
size() <<
") must match x size (" << x.
size() <<
")");
878 "conditionalResult(f,x,y): f size (" << f.
size() <<
") must match y size (" << y.
size() <<
")");
881 return f.
at(0) ? x : y;
884 for (Size i = 0; i < f.
size(); ++i) {
888 stopCalcStats(f.
size());
895 QL_REQUIRE(x.
size() == y.
size(),
"RandomVariable: indicatorEq(x,y): x size ("
896 << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
904 for (Size i = 0; i < x.
n_; ++i) {
905 x.
data_[i] = QuantLib::close_enough(x.
data_[i], y[i]) ? trueVal : falseVal;
916 QL_REQUIRE(x.
size() == y.
size(),
"RandomVariable: indicatorEq(x,y): x size ("
917 << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
922 Real delta = getDelta(x - y, eps);
923 if (!QuantLib::close_enough(delta, 0.0)) {
926 Real delta = getDelta(x - y, eps);
928 for (Size i = 0; i < x.
n_; ++i) {
929 x.
data_[i] = falseVal + (trueVal - falseVal) * 1.0 / (1.0 + std::exp(-x.
data_[i] / delta));
942 for (Size i = 0; i < x.
n_; ++i) {
943 x.
data_[i] = (x.
data_[i] > y[i] && !QuantLib::close_enough(x.
data_[i], y[i])) ? trueVal : falseVal;
954 QL_REQUIRE(x.
size() == y.
size(),
"RandomVariable: indicatorEq(x,y): x size ("
955 << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
960 Real delta = getDelta(x - y, eps);
961 if (!QuantLib::close_enough(delta, 0.0)) {
964 Real delta = getDelta(x - y, eps);
966 for (Size i = 0; i < x.
n_; ++i) {
967 x.
data_[i] = falseVal + (trueVal - falseVal) * 1.0 / (1.0 + std::exp(-x.
data_[i] / delta));
980 for (Size i = 0; i < x.
n_; ++i) {
981 x.
data_[i] = (x.
data_[i] > y[i] || QuantLib::close_enough(x.
data_[i], y[i])) ? trueVal : falseVal;
992 "RandomVariable: x < y: x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
1000 for (Size i = 0; i < x.
size(); ++i) {
1001 result.
set(i, x[i] < y[i] && !QuantLib::close_enough(x[i], y[i]));
1003 stopCalcStats(x.
size());
1011 "RandomVariable: x <= y: x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
1019 for (Size i = 0; i < x.
size(); ++i) {
1020 result.
set(i, x[i] < y[i] || QuantLib::close_enough(x[i], y[i]));
1022 stopCalcStats(x.
size());
1030 "RandomVariable: x > y: x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
1037 for (Size i = 0; i < x.
size(); ++i) {
1038 result.
set(i, x[i] > y[i] && !QuantLib::close_enough(x[i], y[i]));
1047 "RandomVariable: x >= y: x size (" << x.
size() <<
") must be equal to y size (" << y.
size() <<
")");
1055 for (Size i = 0; i < x.
size(); ++i) {
1056 result.
set(i, x[i] > y[i] || QuantLib::close_enough(x[i], y[i]));
1058 stopCalcStats(x.
size());
1065 QL_REQUIRE(!f.
initialised() || f.
size() == x.
size(),
"RandomVariable: applyFitler(x,f): filter size ("
1066 << f.
size() <<
") must be equal to x size (" << x.
size()
1079 for (Size i = 0; i < x.
size(); ++i) {
1083 stopCalcStats(x.
size());
1090 QL_REQUIRE(!f.
initialised() || f.
size() == x.
size(),
"RandomVariable: applyFitler(x,f): filter size ("
1091 << f.
size() <<
") must be equal to x size (" << x.
size()
1104 for (Size i = 0; i < x.
size(); ++i) {
1108 stopCalcStats(x.
size());
1113 if (regressor.empty())
1116 Matrix cov(regressor.size(), regressor.size());
1117 for (Size i = 0; i < regressor.size(); ++i) {
1119 for (Size j = 0; j < i; ++j) {
1120 cov(i, j) = cov(j, i) =
covariance(*regressor[i], *regressor[j]).
at(0);
1124 QuantLib::SymmetricSchurDecomposition schur(cov);
1125 Real totalVariance = std::accumulate(schur.eigenvalues().begin(), schur.eigenvalues().end(), 0.0);
1128 Real explainedVariance = 0.0;
1129 while (keep < schur.eigenvalues().size() && explainedVariance < totalVariance * (1.0 - varianceCutoff)) {
1130 explainedVariance += schur.eigenvalues()[keep++];
1133 Matrix result(keep, regressor.size());
1134 for (Size i = 0; i < keep; ++i) {
1135 std::copy(schur.eigenvectors().column_begin(i), schur.eigenvectors().column_end(i), result.row_begin(i));
1141 const Matrix& transform) {
1142 QL_REQUIRE(transform.columns() == regressor.size(),
1143 "applyCoordinateTransform(): number of random variables ("
1144 << regressor.size() <<
") does not match number of columns in transform (" << transform.columns());
1145 if (regressor.empty())
1147 Size n = regressor.front()->size();
1148 std::vector<RandomVariable> result(transform.rows(),
RandomVariable(n, 0.0));
1149 for (Size i = 0; i < transform.rows(); ++i) {
1150 for (Size j = 0; j < transform.columns(); ++j) {
1151 result[i] +=
RandomVariable(n, transform(i, j)) * (*regressor[j]);
1157std::vector<const RandomVariable*>
vec2vecptr(
const std::vector<RandomVariable>& values) {
1158 std::vector<const RandomVariable*> result(values.size());
1159 std::transform(values.begin(), values.end(), result.begin(), [](
const RandomVariable& v) { return &v; });
1165 const std::vector<std::function<
RandomVariable(
const std::vector<const RandomVariable*>&)>>& basisFn,
1168 for (
auto const reg : regressor) {
1169 QL_REQUIRE(reg->size() == r.
size(),
1170 "regressor size (" << reg->size() <<
") must match regressand size (" << r.
size() <<
")");
1173 QL_REQUIRE(filter.
size() == 0 || filter.
size() == r.
size(),
1174 "filter size (" << filter.
size() <<
") must match regressand size (" << r.
size() <<
")");
1176 QL_REQUIRE(r.
size() >= basisFn.size(),
"regressionCoefficients(): sample size ("
1177 << r.
size() <<
") must be geq basis fns size (" << basisFn.size()
1182 Matrix A(r.
size(), basisFn.size());
1183 for (Size j = 0; j < basisFn.size(); ++j) {
1189 std::fill(A.column_begin(j), A.column_end(j), a[0]);
1194 if (!debugLabel.empty()) {
1195 for (Size i = 0; i < r.
size(); ++i) {
1196 std::cout << debugLabel <<
"," << r[i] <<
",";
1197 for (Size j = 0; j < regressor.size(); ++j) {
1198 std::cout << regressor[j]->operator[](i) << (j == regressor.size() - 1 ?
"\n" :
",");
1201 std::cout << std::flush;
1204 if (filter.
size() > 0) {
1210 std::fill(b.begin(), b.end(), r[0]);
1217 const Matrix& V = svd.V();
1218 const Matrix& U = svd.U();
1219 const Array& w = svd.singularValues();
1220 Real threshold = r.
size() * QL_EPSILON * svd.singularValues()[0];
1221 res = Array(basisFn.size(), 0.0);
1222 for (Size i = 0; i < basisFn.size(); ++i) {
1223 if (w[i] > threshold) {
1224 Real u = std::inner_product(U.column_begin(i), U.column_end(i), b.begin(), Real(0.0)) / w[i];
1225 for (Size j = 0; j < basisFn.size(); ++j) {
1226 res[j] += u * V[j][i];
1231 res = qrSolve(A, b);
1233 QL_FAIL(
"regressionCoefficients(): unknown regression method, expected SVD or QR");
1237 stopCalcStats(r.
size() * basisFn.size() * std::min(r.
size(), basisFn.size()));
1242 const std::vector<const RandomVariable*>& regressor,
1243 const std::vector<std::function<
RandomVariable(
const std::vector<const RandomVariable*>&)>>& basisFn,
1244 const Array& coefficients) {
1245 QL_REQUIRE(!regressor.empty(),
"regressor vector is empty");
1246 Size n = regressor.front()->size();
1247 for (Size i = 1; i < regressor.size(); ++i) {
1248 QL_REQUIRE(regressor[i] !=
nullptr,
"regressor #" << i <<
" is null.");
1249 QL_REQUIRE(n == regressor[i]->size(),
"regressor #" << i <<
" size (" << regressor[i]->size()
1250 <<
") must match regressor #0 size (" << n <<
")");
1252 QL_REQUIRE(basisFn.size() == coefficients.size(),
1253 "basisFn size (" << basisFn.size() <<
") must match coefficients size (" << coefficients.size() <<
")");
1255 for (Size i = 0; i < coefficients.size(); ++i) {
1256 r = r +
RandomVariable(n, coefficients[i]) * basisFn[i](regressor);
1262 const RandomVariable& r,
const std::vector<const RandomVariable*>& regressor,
1263 const std::vector<std::function<
RandomVariable(
const std::vector<const RandomVariable*>&)>>& basisFn,
1275 boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::mean>> acc;
1276 for (Size i = 0; i < r.
size(); ++i)
1285 boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::variance>> acc;
1286 for (Size i = 0; i < r.
size(); ++i) {
1289 stopCalcStats(r.
size());
1294 QL_REQUIRE(r.
size() == s.
size(),
"covariance(RandomVariable r, RandomVariable s): inconsistent sizes r ("
1295 << r.
size() <<
"), s(" << s.
size() <<
")");
1299 boost::accumulators::accumulator_set<
1301 boost::accumulators::stats<boost::accumulators::tag::covariance<double, boost::accumulators::tag::covariate1>>>
1303 for (Size i = 0; i < r.
size(); ++i) {
1304 acc(r[i], boost::accumulators::covariate1 = s[i]);
1306 stopCalcStats(r.
size());
1330 Real delta = getDelta(x, eps);
1332 if (QuantLib::close_enough(delta, 0.0))
1337 for (Size i = 0; i < tmp.
size(); ++i) {
1348 tmp.
set(i, std::exp(-1.0 / delta * x[i]) / (delta * std::pow(1.0 + std::exp(-1.0 / delta * x[i]), 2.0)));
1351 stopCalcStats(x.
size() * 8);
1357 std::function<void(RandomVariable&)>([](RandomVariable& x) { x.clear(); });
1359std::vector<std::function<RandomVariable(
const std::vector<const RandomVariable*>&)>>
1360multiPathBasisSystem(Size dim, Size order, QuantLib::LsmBasisSystem::PolynomialType type, Size basisSystemSizeBound) {
1361 thread_local static std::map<std::pair<Size, Size>,
1362 std::vector<std::function<
RandomVariable(
const std::vector<const RandomVariable*>&)>>>
1364 QL_REQUIRE(order > 0,
"multiPathBasisSystem: order must be > 0");
1365 if (basisSystemSizeBound != Null<Size>()) {
1370 if (
auto c = cache.find(std::make_pair(dim, order)); c != cache.end())
1373 cache[std::make_pair(dim, order)] = tmp;
static Real size(Size dim, Size order)
static std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > multiPathBasisSystem(Size dim, Size order, QuantLib::LsmBasisSystem::PolynomialType type)
bool operator<(const Dividend &d1, const Dividend &d2)
BucketedDistribution operator+(const BucketedDistribution &lhs, const BucketedDistribution &rhs)
Sum probabilities in two bucketed distributions with equal buckets.
std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > multiPathBasisSystem(Size dim, Size order, QuantLib::LsmBasisSystem::PolynomialType type, Size basisSystemSizeBound)
bool operator!=(const Filter &a, const Filter &b)
RandomVariable sqrt(RandomVariable x)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
RandomVariable variance(const RandomVariable &r)
RandomVariable cos(RandomVariable x)
CompiledFormula exp(CompiledFormula x)
RandomVariable sin(RandomVariable x)
RandomVariableRegressionMethod
bool close_enough_all(const RandomVariable &x, const RandomVariable &y)
Filter operator!(Filter x)
RandomVariable conditionalResult(const Filter &f, RandomVariable x, const RandomVariable &y)
CompiledFormula min(CompiledFormula x, const CompiledFormula &y)
Filter operator>=(const RandomVariable &x, const RandomVariable &y)
RandomVariable indicatorDerivative(const RandomVariable &x, const double eps)
RandomVariable black(const RandomVariable &omega, const RandomVariable &t, const RandomVariable &strike, const RandomVariable &forward, const RandomVariable &impliedVol)
RandomVariable covariance(const RandomVariable &r, const RandomVariable &s)
bool operator==(const Dividend &d1, const Dividend &d2)
Compare dividends.
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 * > ®ressor, const std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > &basisFn, const Array &coefficients)
Filter operator&&(Filter x, const Filter &y)
RandomVariable applyInverseFilter(RandomVariable x, const Filter &f)
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 applyFilter(RandomVariable x, const Filter &f)
RandomVariable indicatorEq(RandomVariable x, const RandomVariable &y, const Real trueVal, const Real falseVal)
RandomVariable normalPdf(RandomVariable x)
Filter equal(Filter x, const Filter &y)
Filter operator||(Filter x, const Filter &y)
Matrix pcaCoordinateTransform(const std::vector< const RandomVariable * > ®ressor, const Real varianceCutoff)
CompiledFormula log(CompiledFormula x)
void checkTimeConsistency(const RandomVariable &x, const RandomVariable &y)
Real sum(const Cash &c, const Cash &d)
CompiledFormula operator-(CompiledFormula x, const CompiledFormula &y)
CompiledFormula operator/(CompiledFormula x, const CompiledFormula &y)
Array regressionCoefficients(RandomVariable r, std::vector< const RandomVariable * > regressor, const std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > &basisFn, const Filter &filter, const RandomVariableRegressionMethod regressionMethod, const std::string &debugLabel)
Filter operator<=(const RandomVariable &x, const RandomVariable &y)
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 * > ®ressor, const Matrix &transform)
BucketedDistribution operator*(Real factor, const BucketedDistribution &rhs)
bool operator>(const Currency &, const Currency &)
ql utility class for random variables
void set(const Size i, const bool v)
bool deterministic() const
void setAll(const bool v)
void updateDeterministic()
bool at(const Size i) const
Filter & operator=(const Filter &r)
void resetSize(const Size n)
static std::function< void(RandomVariable &)> deleter
void copyToMatrixCol(QuantLib::Matrix &, const Size j) const
RandomVariable & operator+=(const RandomVariable &)
void checkTimeConsistencyAndUpdate(const Real t)
Real at(const Size i) const
RandomVariable & operator=(const RandomVariable &r)
bool deterministic() const
void set(const Size i, const Real v)
RandomVariable & operator-=(const RandomVariable &)
RandomVariable & operator*=(const RandomVariable &)
void copyToArray(QuantLib::Array &array) const
void updateDeterministic()
RandomVariable & operator/=(const RandomVariable &)
void setAll(const Real v)
void resetSize(const Size n)