2626#include < boost/math/distributions/normal.hpp>
2727
2828#include < boost/accumulators/accumulators.hpp>
29+ #include < boost/accumulators/statistics/mean.hpp>
2930#include < boost/accumulators/statistics/stats.hpp>
3031#include < boost/accumulators/statistics/variance.hpp>
31- #include < boost/accumulators/statistics/mean.hpp>
3232
3333#include < iostream>
3434#include < map>
@@ -75,6 +75,16 @@ inline void stopCalcStats(const std::size_t n) {}
7575
7676#endif
7777
78+ double getDelta (const RandomVariable& x, const Real eps) {
79+ Real sum = 0.0 ;
80+ for (Size i = 0 ; i < x.size (); ++i) {
81+ sum += x[i] * x[i];
82+ }
83+ Real delta = std::sqrt (sum / static_cast <Real>(x.size ())) * eps / 2.0 ;
84+ // std::cout << "delta = " << delta << std::endl;
85+ return delta;
86+ }
87+
7888} // namespace
7989
8090Filter::~Filter () { clear (); }
@@ -891,14 +901,30 @@ RandomVariable indicatorEq(RandomVariable x, const RandomVariable& y, const Real
891901 return x;
892902}
893903
894- RandomVariable indicatorGt (RandomVariable x, const RandomVariable& y, const Real trueVal, const Real falseVal) {
904+ RandomVariable indicatorGt (RandomVariable x, const RandomVariable& y, const Real trueVal, const Real falseVal,
905+ const Real eps) {
895906 if (!x.initialised () || !y.initialised ())
896907 return RandomVariable ();
897908 QL_REQUIRE (x.size () == y.size (), " RandomVariable: indicatorEq(x,y): x size ("
898909 << x.size () << " ) must be equal to y size (" << y.size () << " )" );
899910 x.checkTimeConsistencyAndUpdate (y.time ());
900911 if (!y.deterministic_ )
901912 x.expand ();
913+ if (eps != 0.0 ) {
914+ Real delta = getDelta (x - y, eps);
915+ if (!QuantLib::close_enough (delta, 0.0 )) {
916+ // logistic function
917+ x.expand ();
918+ Real delta = getDelta (x - y, eps);
919+ resumeCalcStats ();
920+ for (Size i = 0 ; i < x.n_ ; ++i) {
921+ x.data_ [i] = falseVal + (trueVal - falseVal) * 1.0 / (1.0 + std::exp (-x.data_ [i] / delta));
922+ }
923+ stopCalcStats (x.n_ );
924+ return x;
925+ }
926+ }
927+ // eps == 0.0 or delta == 0.0
902928 if (x.deterministic ()) {
903929 x.constantData_ =
904930 (x.constantData_ > y.constantData_ && !QuantLib::close_enough (x.constantData_ , y.constantData_ )) ? trueVal
@@ -913,14 +939,30 @@ RandomVariable indicatorGt(RandomVariable x, const RandomVariable& y, const Real
913939 return x;
914940}
915941
916- RandomVariable indicatorGeq (RandomVariable x, const RandomVariable& y, const Real trueVal, const Real falseVal) {
942+ RandomVariable indicatorGeq (RandomVariable x, const RandomVariable& y, const Real trueVal, const Real falseVal,
943+ const Real eps) {
917944 if (!x.initialised () || !y.initialised ())
918945 return RandomVariable ();
919946 QL_REQUIRE (x.size () == y.size (), " RandomVariable: indicatorEq(x,y): x size ("
920947 << x.size () << " ) must be equal to y size (" << y.size () << " )" );
921948 x.checkTimeConsistencyAndUpdate (y.time ());
922949 if (!y.deterministic_ )
923950 x.expand ();
951+ if (eps != 0.0 ) {
952+ Real delta = getDelta (x - y, eps);
953+ if (!QuantLib::close_enough (delta, 0.0 )) {
954+ // logistic function
955+ x.expand ();
956+ Real delta = getDelta (x - y, eps);
957+ resumeCalcStats ();
958+ for (Size i = 0 ; i < x.n_ ; ++i) {
959+ x.data_ [i] = falseVal + (trueVal - falseVal) * 1.0 / (1.0 + std::exp (-x.data_ [i] / delta));
960+ }
961+ stopCalcStats (x.n_ );
962+ return x;
963+ }
964+ }
965+ // eps == 0.0 or delta == 0.0
924966 if (x.deterministic ()) {
925967 x.constantData_ =
926968 (x.constantData_ > y.constantData_ || QuantLib::close_enough (x.constantData_ , y.constantData_ )) ? trueVal
@@ -1206,33 +1248,27 @@ RandomVariable indicatorDerivative(const RandomVariable& x, const double eps) {
12061248 // Fries, 2017: Automatic Backward Differentiation for American Monte-Carlo Algorithms -
12071249 // ADD for Conditional Expectations and Indicator Functions
12081250
1209- if (QuantLib::close_enough (eps, 0.0 ) || x.deterministic ())
1210- return tmp;
1211-
12121251 resumeCalcStats ();
12131252
1214- Real sum = 0.0 ;
1215- for (Size i = 0 ; i < x.size (); ++i) {
1216- sum += x[i] * x[i];
1217- }
1218-
1219- Real delta = std::sqrt (sum / static_cast <Real>(x.size ())) * eps / 2.0 ;
1253+ Real delta = getDelta (x, eps);
12201254
12211255 if (QuantLib::close_enough (delta, 0.0 ))
12221256 return tmp;
12231257
12241258 // compute derivative
12251259
12261260 for (Size i = 0 ; i < tmp.size (); ++i) {
1227- Real ax = std::abs (x[i]);
12281261
12291262 // linear approximation of step
1263+ // Real ax = std::abs(x[i]);
12301264 // if (ax < delta) {
12311265 // tmp.set(i, 1.0 / (2.0 * delta));
12321266 // }
12331267
12341268 // logistic function
1235- tmp.set (i, std::exp (-1.0 / delta * ax) / (delta * std::pow (1.0 + std::exp (-1.0 / delta * ax), 2.0 )));
1269+ // f(x) = 1 / (1 + exp(-x / delta))
1270+ // f'(x) = exp(-x/delta) / (delta * (1 + exp(-x / delta))^2), this is an even function
1271+ tmp.set (i, std::exp (-1.0 / delta * x[i]) / (delta * std::pow (1.0 + std::exp (-1.0 / delta * x[i]), 2.0 )));
12361272 }
12371273
12381274 stopCalcStats (x.size () * 8 );
0 commit comments