From cb001a7c6947cb2bfa17895dbae5f71b96b78758 Mon Sep 17 00:00:00 2001 From: Matthew Parno Date: Fri, 13 Oct 2023 13:53:32 -0400 Subject: [PATCH 1/6] Fixed bug in computation of initial bracket for inverse evaluation. --- MParT/Utilities/RootFinding.h | 82 ++++++++++++++++++++++++++--------- tests/Test_RootFinding.cpp | 26 +++-------- 2 files changed, 67 insertions(+), 41 deletions(-) diff --git a/MParT/Utilities/RootFinding.h b/MParT/Utilities/RootFinding.h index 6d8702ea..c290df4a 100644 --- a/MParT/Utilities/RootFinding.h +++ b/MParT/Utilities/RootFinding.h @@ -11,22 +11,62 @@ KOKKOS_INLINE_FUNCTION void swapPair(T& x1, T& x2, T& y1, T& y2) { simple_swap(y1, y2); } +/** Finds a bracket [xlb, xub] such that f(xlb)yd. */ template -KOKKOS_INLINE_FUNCTION void FindBound(bool haveLowerBound, double yd, - FunctorType f, double& x_bound, double& y_bound, - double& x_unbound, double& y_unbound, const unsigned int maxIts) { - double boundSign = haveLowerBound ? 1.0 : -1.0; +KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, + double& xlb, double& ylb, + double& xub, double& yub, + const double yd) +{ + double xb, xf; // Bisection point and regula falsi point + double xc, yc; + const unsigned int maxIts = 1000; double stepSize = 1.0; - unsigned int iter; - for(iter = 0; iter < maxIts; iter++) { - x_unbound += boundSign*stepSize; - y_unbound = f(x_unbound); - if(boundSign*(y_unbound - yd) > 0) return; - swapPair(x_bound, x_unbound, y_bound, y_unbound); - stepSize *= 2; + + ylb = f(xb); + + // We actually found an upper bound... + if(ylb>yd){ + + mpart::simple_swap(ylb,yub); + mpart::simple_swap(xlb,xub); + + // Now find a lower bound... + unsigned int i; + for(i=0; iyd){ + mpart::simple_swap(ylb,yub); + mpart::simple_swap(xlb,xub); + stepSize *= 2.0; + }else{ + break; + } + } + + if(i>=maxIts) + ProcAgnosticError::error("FindBracket: Could not find initial bracket such that f(xlb)yd."); + + // We have a lower bound... + }else{ + // Now find an upper bound... + unsigned int i; + for(i=0; i=maxIts) + ProcAgnosticError::error("FindBracket: Could not find initial bracket such that f(xlb)yd."); } - if(iter>=maxIts) - ProcAgnosticError::error("InverseSingleBracket: bound calculation exceeds maxIts"); } KOKKOS_INLINE_FUNCTION double Find_x_ITP(double xlb, double xub, double yd, double ylb, double yub, @@ -47,7 +87,8 @@ KOKKOS_INLINE_FUNCTION double Find_x_ITP(double xlb, double xub, double yd, doub template KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, double x0, const double xtol, const double ftol) -{ +{ + std::cout << "Hereherehere" << std::endl; double stepSize=1.0; const unsigned int maxIts = 10000; @@ -59,13 +100,10 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou xlb = xub = x0; ylb = yub = f(xlb); - bool haveLowerBound = ylb < yd; // if ylb is a lower bound for yd - if(haveLowerBound) { - FindBound(haveLowerBound, yd, f, xlb, ylb, xub, yub, maxIts); - } else { - FindBound(haveLowerBound, yd, f, xub, yub, xlb, ylb, maxIts); - } - + // Compute bounds + std::cout << "About to call find bracket..." << std::endl; + FindBracket(f, xlb, ylb, xub, yub, yd); + std::cout << "done " << xlb << ", " << xub << ", " << ylb << ", " << yub << std::endl; assert(ylb(false, yd, identity, xub, yub, xlb, ylb, 10'000); + FindBracket(identity, xlb, ylb, xub, ylb, 10'000); CheckFoundBounds(identity, xlb, xd, xub, ylb, yd, yub); } - SECTION("FindBound upper linear") { - double xd = 1.1; - double yd = identity(xd); - double xub = 0., yub = 0.; - double xlb = -2., ylb = -2.; - FindBound(true, yd, identity, xlb, ylb, xub, yub, 10'000); - CheckFoundBounds(identity, xlb, xd, xub, ylb, yd, yub); - } - SECTION("FindBound lower sigmoid") { + SECTION("FindBracker sigmoid") { double xd = -0.5; double yd = sigmoid(xd); double xub = 2., yub = sigmoid(xub); double xlb = 0., ylb = sigmoid(xlb); - FindBound(false, yd, sigmoid, xub, yub, xlb, ylb, 10'000); - CheckFoundBounds(sigmoid, xlb, xd, xub, ylb, yd, yub); - } - SECTION("FindBound upper sigmoid") { - double xd = 0.5; - double yd = sigmoid(xd); - double xub = 0., yub = sigmoid(xub); - double xlb = -2., ylb = sigmoid(xlb); - FindBound(true, yd, sigmoid, xlb, ylb, xub, yub, 10'000); + FindBracket(sigmoid, xlb, ylb, xub, ylb, 10'000); CheckFoundBounds(sigmoid, xlb, xd, xub, ylb, yd, yub); } SECTION("Test Inverse Linear, low x0") { From 6b6adc1afb25be4b432f4626feaffc420a93c836 Mon Sep 17 00:00:00 2001 From: Matthew Parno Date: Fri, 13 Oct 2023 14:29:19 -0400 Subject: [PATCH 2/6] More bug fixes related to root finding tests. --- MParT/MonotoneComponent.h | 2 +- MParT/Utilities/RootFinding.h | 18 ++++++------------ tests/Test_RootFinding.cpp | 4 ++-- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/MParT/MonotoneComponent.h b/MParT/MonotoneComponent.h index 30b9a9d4..ed9c0c80 100644 --- a/MParT/MonotoneComponent.h +++ b/MParT/MonotoneComponent.h @@ -400,7 +400,7 @@ class MonotoneComponent : public ConditionalMapBase // Compute the inverse Kokkos::View workspace(team_member.thread_scratch(1), workspaceSize); - auto eval = SingleEvaluator(workspace.data(), cache.data(), pt, coeffs, quad_, expansion_); + auto eval = SingleEvaluator(workspace.data(), cache.data(), pt, coeffs, quad_, expansion_); output(ptInd) = RootFinding::InverseSingleBracket(ys(ptInd), eval, pt(pt.extent(0)-1), xtol, ytol); } }; diff --git a/MParT/Utilities/RootFinding.h b/MParT/Utilities/RootFinding.h index c290df4a..5228174c 100644 --- a/MParT/Utilities/RootFinding.h +++ b/MParT/Utilities/RootFinding.h @@ -18,16 +18,15 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, double& xub, double& yub, const double yd) { - double xb, xf; // Bisection point and regula falsi point - double xc, yc; const unsigned int maxIts = 1000; double stepSize = 1.0; - - ylb = f(xb); - + + ylb = f(xlb); + yub = f(xub); + // We actually found an upper bound... if(ylb>yd){ - + mpart::simple_swap(ylb,yub); mpart::simple_swap(xlb,xub); @@ -67,7 +66,7 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, if(i>=maxIts) ProcAgnosticError::error("FindBracket: Could not find initial bracket such that f(xlb)yd."); } -} + } KOKKOS_INLINE_FUNCTION double Find_x_ITP(double xlb, double xub, double yd, double ylb, double yub, double k1, double k2, double nhalf, double n0, int it, double xtol) { @@ -88,7 +87,6 @@ KOKKOS_INLINE_FUNCTION double Find_x_ITP(double xlb, double xub, double yd, doub template KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, double x0, const double xtol, const double ftol) { - std::cout << "Hereherehere" << std::endl; double stepSize=1.0; const unsigned int maxIts = 10000; @@ -101,9 +99,7 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou ylb = yub = f(xlb); // Compute bounds - std::cout << "About to call find bracket..." << std::endl; FindBracket(f, xlb, ylb, xub, yub, yd); - std::cout << "done " << xlb << ", " << xub << ", " << ylb << ", " << yub << std::endl; assert(ylb(identity, xlb, ylb, xub, ylb, 10'000); + FindBracket(identity, xlb, ylb, xub, yub, yd); CheckFoundBounds(identity, xlb, xd, xub, ylb, yd, yub); } SECTION("FindBracker sigmoid") { @@ -38,7 +38,7 @@ TEST_CASE( "RootFindingUtils", "[RootFindingUtils]") { double yd = sigmoid(xd); double xub = 2., yub = sigmoid(xub); double xlb = 0., ylb = sigmoid(xlb); - FindBracket(sigmoid, xlb, ylb, xub, ylb, 10'000); + FindBracket(sigmoid, xlb, ylb, xub, yub, yd); CheckFoundBounds(sigmoid, xlb, xd, xub, ylb, yd, yub); } SECTION("Test Inverse Linear, low x0") { From e4eeb5d6562da6f20e0091123f924e4849793174 Mon Sep 17 00:00:00 2001 From: Matthew Parno Date: Fri, 13 Oct 2023 21:42:27 -0400 Subject: [PATCH 3/6] Now throwing nan if inverse blows up. --- MParT/MonotoneComponent.h | 270 +++++++++++++++++++------------- MParT/Utilities/Miscellaneous.h | 2 +- MParT/Utilities/RootFinding.h | 50 ++++-- 3 files changed, 198 insertions(+), 124 deletions(-) diff --git a/MParT/MonotoneComponent.h b/MParT/MonotoneComponent.h index ed9c0c80..6b6be68f 100644 --- a/MParT/MonotoneComponent.h +++ b/MParT/MonotoneComponent.h @@ -312,6 +312,16 @@ class MonotoneComponent : public ConditionalMapBase StridedVector output, std::map options=std::map()) { + // std::cout << "xs.shape = " << xs.extent(0) << "," << xs.extent(1) << std::endl; + // std::cout << "xs = \n" << std::endl; + // for(unsigned int row=0; row // Create a subview containing x_{1:d-1} auto pt = Kokkos::subview(xs, Kokkos::ALL(), xInd); + + //std::cout << "\n\nPt0 = \n" << std::endl; + for(unsigned int ii=0; ii cache(team_member.thread_scratch(1), cacheSize); expansion_.FillCache1(cache.data(), pt, DerivativeFlags::None); + // std::cout << "\n\nPt1 = \n" << std::endl; + // double max_val = 0.0; + // for(unsigned int ii=0; iimax_val) ? abs(pt(ii)) : max_val; + // } + // std::cout << std::endl << std::endl; + // if (max_val > 1e-4){ + // std::cout << "Max val = " << max_val; + // assert(max_val < 1e4); + // } // Compute the inverse Kokkos::View workspace(team_member.thread_scratch(1), workspaceSize); auto eval = SingleEvaluator(workspace.data(), cache.data(), pt, coeffs, quad_, expansion_); + //std::cout << "Here 0" << std::endl; output(ptInd) = RootFinding::InverseSingleBracket(ys(ptInd), eval, pt(pt.extent(0)-1), xtol, ytol); + //std::cout << "Here 1" << std::endl; } }; @@ -967,6 +1001,16 @@ class MonotoneComponent : public ConditionalMapBase QuadratureType const& quad, ExpansionType const& expansion) { + // std::cout << "pt = " << std::endl; + // for(unsigned int i=0; i integrand(cache, @@ -977,11 +1021,17 @@ class MonotoneComponent : public ConditionalMapBase DerivativeFlags::None); quad.Integrate(workspace, integrand, 0, 1, &output); + // std::cout << "output 1 = " << output << std::endl; // Finish filling in the cache for an evaluation of the expansion with x_d=0 + // std::cout << "pt = " << std::endl; + // for(unsigned int i=0; imaxIts) - ProcAgnosticError::error("InverseSingleBracket: upper bound calculation exceeds maxIts"); - } - - assert(ylb0)?1.0:-1.0; // sign(xb-xf) - delta = fmin(k1*pow((xub-xlb), k2), fabs(xb-xf)); - - xf += delta*sigma; - - rho = fmin(xtol*pow(2.0, nhalf + n0 - it) - 0.5*(xub-xlb), fabs(xf - xb)); - xc = xb - sigma*rho; - - yc = EvaluateSingle(workspace, cache, pt, xc, coeffs, quad, expansion); - - if(abs(yc-yd)yd){ - mpart::simple_swap(yc,yub); - mpart::simple_swap(xc,xub); - }else{ - mpart::simple_swap(yc,ylb); - mpart::simple_swap(xc,xlb); - } - - // Check for convergence - if(((xub-xlb)maxIts) - ProcAgnosticError::error("InverseSingleBracket: Bracket search iterations exceeds maxIts"); - return 0.5*(xub+xlb); - } + // template + // KOKKOS_FUNCTION static double InverseSingleBracket(double* cache, + // double* workspace, + // PointType const& pt, + // double yd, + // CoeffsType const& coeffs, + // const double xtol, + // const double ftol, + // QuadratureType const& quad, + // ExpansionType const& expansion) + // { + // double stepSize=1.0; + // const unsigned int maxIts = 10000; + + // // First, we need to find two points that bound the solution. + // double xlb, xub; + // double ylb, yub; + // double xb, xf; // Bisection point and regula falsi point + // double xc, yc; + + // xlb = pt(pt.extent(0)-1); + // ylb = EvaluateSingle(workspace, cache, pt, xlb, coeffs, quad, expansion); + + // // We actually found an upper bound... + // if(ylb>yd){ + + // mpart::simple_swap(ylb,yub); + // mpart::simple_swap(xlb,xub); + + // // Now find a lower bound... + // unsigned int i; + // for(i=0; iyd){ + // mpart::simple_swap(ylb,yub); + // mpart::simple_swap(xlb,xub); + // stepSize *= 2.0; + // }else{ + // break; + // } + // } + // if(i>maxIts) + // ProcAgnosticError::error("InverseSingleBracket: lower bound iterations exceed maxIts"); + + // // We have a lower bound... + // }else{ + // // Now find an upper bound... + // unsigned int i; + // for(i=0; imaxIts) + // ProcAgnosticError::error("InverseSingleBracket: upper bound calculation exceeds maxIts"); + // } + + // assert(ylb0)?1.0:-1.0; // sign(xb-xf) + // delta = fmin(k1*pow((xub-xlb), k2), fabs(xb-xf)); + + // xf += delta*sigma; + + // rho = fmin(xtol*pow(2.0, nhalf + n0 - it) - 0.5*(xub-xlb), fabs(xf - xb)); + // xc = xb - sigma*rho; + + // yc = EvaluateSingle(workspace, cache, pt, xc, coeffs, quad, expansion); + + // if(abs(yc-yd)yd){ + // mpart::simple_swap(yc,yub); + // mpart::simple_swap(xc,xub); + // }else{ + // mpart::simple_swap(yc,ylb); + // mpart::simple_swap(xc,xlb); + // } + + // // Check for convergence + // if(((xub-xlb)maxIts) + // ProcAgnosticError::error("InverseSingleBracket: Bracket search iterations exceeds maxIts"); + // return 0.5*(xub+xlb); + // } /** Give access to the underlying FixedMultiIndexSet * @return The FixedMultiIndexSet diff --git a/MParT/Utilities/Miscellaneous.h b/MParT/Utilities/Miscellaneous.h index f1dfa790..6647bf26 100644 --- a/MParT/Utilities/Miscellaneous.h +++ b/MParT/Utilities/Miscellaneous.h @@ -22,7 +22,7 @@ namespace mpart{ template struct ProcAgnosticError { static void error(const char*) { - assert(0); + assert(false); } }; diff --git a/MParT/Utilities/RootFinding.h b/MParT/Utilities/RootFinding.h index 5228174c..03e5c65d 100644 --- a/MParT/Utilities/RootFinding.h +++ b/MParT/Utilities/RootFinding.h @@ -18,12 +18,14 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, double& xub, double& yub, const double yd) { - const unsigned int maxIts = 1000; + const unsigned int maxIts = 40; double stepSize = 1.0; ylb = f(xlb); yub = f(xub); - + //std::cout << "-1" << ": " << xlb << ", " << ylb << ", " << xub << ", " << yub << " vs " << yd << std::endl; + + // We actually found an upper bound... if(ylb>yd){ @@ -35,17 +37,26 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, for(i=0; iyd."); + + // if(i>=maxIts) + // ProcAgnosticError::error("FindBracket: Could not find initial bracket such that f(xlb)yd."); // We have a lower bound... }else{ @@ -54,17 +65,24 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, for(i=0; iyd."); + // if(i>=maxIts) + // ProcAgnosticError::error("FindBracket: Could not find initial bracket such that f(xlb)yd."); } } @@ -95,13 +113,15 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou double ylb, yub; double xc, yc; + //std::cout << "xlb = " << xlb << std::endl; xlb = xub = x0; ylb = yub = f(xlb); // Compute bounds FindBracket(f, xlb, ylb, xub, yub, yd); - assert(ylbyd)||(yub::quiet_NaN(); // Bracketed search const double k1 = 0.1; @@ -111,6 +131,8 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou unsigned int it; for(it=0; itmaxIts) - ProcAgnosticError::error("InverseSingleBracket: Bracket search iterations exceeds maxIts"); + return std::numeric_limits::quiet_NaN(); + //ProcAgnosticError::error("InverseSingleBracket: Bracket search iterations exceeds maxIts"); return 0.5*(xub+xlb); } From 23a76046fc87b588aa41055fed670f85fb756242 Mon Sep 17 00:00:00 2001 From: Matthew Parno Date: Tue, 17 Oct 2023 16:55:30 -0400 Subject: [PATCH 4/6] Improved robustness of error handling in bracketed inverse. --- MParT/MonotoneComponent.h | 23 ++--------- MParT/Utilities/Miscellaneous.h | 3 ++ MParT/Utilities/RootFinding.h | 67 +++++++++++++++++++-------------- tests/Test_RootFinding.cpp | 51 +++++++++++++++++++++---- 4 files changed, 88 insertions(+), 56 deletions(-) diff --git a/MParT/MonotoneComponent.h b/MParT/MonotoneComponent.h index 6b6be68f..aa7744fb 100644 --- a/MParT/MonotoneComponent.h +++ b/MParT/MonotoneComponent.h @@ -395,6 +395,7 @@ class MonotoneComponent : public ConditionalMapBase auto functor = KOKKOS_CLASS_LAMBDA (typename Kokkos::TeamPolicy::member_type team_member) { unsigned int ptInd = team_member.league_rank () * team_member.team_size () + team_member.team_rank (); + int info; if(ptInd // Create a subview containing x_{1:d-1} auto pt = Kokkos::subview(xs, Kokkos::ALL(), xInd); - //std::cout << "\n\nPt0 = \n" << std::endl; + // Check for NaNs. If found, set output to nan and return for(unsigned int ii=0; ii::quiet_NaN(); return; } } - //std::cout << std::endl << std::endl; // Fill in the cache with everything that doesn't depend on x_d Kokkos::View cache(team_member.thread_scratch(1), cacheSize); expansion_.FillCache1(cache.data(), pt, DerivativeFlags::None); - // std::cout << "\n\nPt1 = \n" << std::endl; - // double max_val = 0.0; - // for(unsigned int ii=0; iimax_val) ? abs(pt(ii)) : max_val; - // } - // std::cout << std::endl << std::endl; - // if (max_val > 1e-4){ - // std::cout << "Max val = " << max_val; - // assert(max_val < 1e4); - // } // Compute the inverse Kokkos::View workspace(team_member.thread_scratch(1), workspaceSize); auto eval = SingleEvaluator(workspace.data(), cache.data(), pt, coeffs, quad_, expansion_); - //std::cout << "Here 0" << std::endl; - output(ptInd) = RootFinding::InverseSingleBracket(ys(ptInd), eval, pt(pt.extent(0)-1), xtol, ytol); - //std::cout << "Here 1" << std::endl; + output(ptInd) = RootFinding::InverseSingleBracket(ys(ptInd), eval, pt(pt.extent(0)-1), xtol, ytol, info); } }; diff --git a/MParT/Utilities/Miscellaneous.h b/MParT/Utilities/Miscellaneous.h index 6647bf26..b4e3b290 100644 --- a/MParT/Utilities/Miscellaneous.h +++ b/MParT/Utilities/Miscellaneous.h @@ -19,6 +19,9 @@ namespace mpart{ std::string const& key, std::string const& defaultValue); + /** Provides a mechanism for raising exceptions in CPU code where recovery is possible + and assertions in GPU code where exceptions aren't alllowed. + */ template struct ProcAgnosticError { static void error(const char*) { diff --git a/MParT/Utilities/RootFinding.h b/MParT/Utilities/RootFinding.h index 03e5c65d..971ef235 100644 --- a/MParT/Utilities/RootFinding.h +++ b/MParT/Utilities/RootFinding.h @@ -11,20 +11,25 @@ KOKKOS_INLINE_FUNCTION void swapPair(T& x1, T& x2, T& y1, T& y2) { simple_swap(y1, y2); } -/** Finds a bracket [xlb, xub] such that f(xlb)yd. */ +/** Finds a bracket [xlb, xub] such that f(xlb)yd. + * The info argument can be used to detect when a bracket cannot be found. Upon exit, a value of info=0 + * indicates success while a negative value indicates failure. info=-1 indicates that the function + * seems to be perfectly flat and a root might not exist. info=-2 indicates that the maximum number of + * iterations (128) was exceeded. +*/ template KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, double& xlb, double& ylb, double& xub, double& yub, - const double yd) + const double yd, + int& info) { - const unsigned int maxIts = 40; + const unsigned int maxIts = 128; double stepSize = 1.0; - + info = 0; + ylb = f(xlb); yub = f(xub); - //std::cout << "-1" << ": " << xlb << ", " << ylb << ", " << xub << ", " << yub << " vs " << yd << std::endl; - // We actually found an upper bound... if(ylb>yd){ @@ -37,12 +42,10 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, for(i=0; iyd."); + if(i>=maxIts) + info = -2; // We have a lower bound... }else{ @@ -65,13 +67,13 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, for(i=0; iyd."); + if(i>=maxIts){ + info = -2; + } } } KOKKOS_INLINE_FUNCTION double Find_x_ITP(double xlb, double xub, double yd, double ylb, double yub, - double k1, double k2, double nhalf, double n0, int it, double xtol) { + double k1, double k2, double nhalf, double n0, int it, double xtol) { double xb = 0.5*(xub+xlb); // bisection point double xf = (xub*ylb - xlb*yub)/(ylb-yub); // regula-falsi point @@ -102,8 +105,13 @@ KOKKOS_INLINE_FUNCTION double Find_x_ITP(double xlb, double xub, double yd, doub return xc; } +/** Computes the inverse of a function using the ITP method. + * The info argument will be 0 upon successful completion and negative for failed inversions. + * A value of info=-2 indicates a failure to find a bracket that contains the root. In this case, a nan will be returned. + * A value of info=-1 indicates that the maximum number of iterations was exceeded. +*/ template -KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, double x0, const double xtol, const double ftol) +KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, double x0, const double xtol, const double ftol, int& info) { double stepSize=1.0; const unsigned int maxIts = 10000; @@ -112,16 +120,18 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou double xlb, xub; double ylb, yub; double xc, yc; + info = 0; - //std::cout << "xlb = " << xlb << std::endl; xlb = xub = x0; ylb = yub = f(xlb); - // Compute bounds - FindBracket(f, xlb, ylb, xub, yub, yd); - - if ((ylb>yd)||(yub(f, xlb, ylb, xub, yub, yd, bracket_info); + if((bracket_info<0)||(((ylb>yd)||(yub::quiet_NaN(); + } // Bracketed search const double k1 = 0.1; @@ -151,8 +161,7 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou if(it>maxIts) - return std::numeric_limits::quiet_NaN(); - //ProcAgnosticError::error("InverseSingleBracket: Bracket search iterations exceeds maxIts"); + info = -1; return 0.5*(xub+xlb); } diff --git a/tests/Test_RootFinding.cpp b/tests/Test_RootFinding.cpp index b630ee35..67462966 100644 --- a/tests/Test_RootFinding.cpp +++ b/tests/Test_RootFinding.cpp @@ -30,52 +30,87 @@ TEST_CASE( "RootFindingUtils", "[RootFindingUtils]") { double yd = identity(xd); double xub = 2., yub = 2.; double xlb = 0., ylb = 0.; - FindBracket(identity, xlb, ylb, xub, yub, yd); + int info = 0; + FindBracket(identity, xlb, ylb, xub, yub, yd, info); CheckFoundBounds(identity, xlb, xd, xub, ylb, yd, yub); + CHECK(info==0); } SECTION("FindBracker sigmoid") { double xd = -0.5; double yd = sigmoid(xd); double xub = 2., yub = sigmoid(xub); double xlb = 0., ylb = sigmoid(xlb); - FindBracket(sigmoid, xlb, ylb, xub, yub, yd); + int info = 0; + FindBracket(sigmoid, xlb, ylb, xub, yub, yd, info); CheckFoundBounds(sigmoid, xlb, xd, xub, ylb, yd, yub); + CHECK(info==0); + } + SECTION("FindBracket flat") { + double xd = -1.1; + double yd = 0.0; + double xub = 2., yub = -1.0; + double xlb = 0., ylb = -1.0; + int info = 0; + auto f = [](double x){return -1.0;}; + FindBracket(f, xlb, ylb, xub, yub, yd, info); + CHECK(info==-1); } SECTION("Test Inverse Linear, low x0") { double xd = 0.5, yd = identity(xd); double x0 = 0.0, xtol = 1e-5, ftol = 1e-5; - double xd_found = InverseSingleBracket(yd, identity, x0, xtol, ftol); + int info = 0; + double xd_found = InverseSingleBracket(yd, identity, x0, xtol, ftol, info); CHECK( xd_found == Approx(xd).epsilon(2*xtol)); + CHECK(info==0); } SECTION("Test Inverse Linear, high x0") { double xd = 0.5, yd = identity(xd); double x0 = 1.0, xtol = 1e-5, ftol = 1e-5; - double xd_found = InverseSingleBracket(yd, identity, x0, xtol, ftol); + int info = 0; + double xd_found = InverseSingleBracket(yd, identity, x0, xtol, ftol, info); CHECK( xd_found == Approx(xd).epsilon(2*xtol)); + CHECK(info==0); + } + SECTION("Test Inverse Flat") { + double xd = 0.5, yd = -1.0; + double x0 = 0.0, xtol = 1e-5, ftol = 1e-5; + auto f = [](double x){return -1.0;}; + int info = 0; + double xd_found = InverseSingleBracket(yd, f, x0, xtol, ftol, info); + CHECK( std::isnan(xd_found)); + CHECK(info==-2); } SECTION("Test Inverse Sigmoid, low x0") { double xd = 0.5, yd = sigmoid(xd); double x0 = 0.0, xtol = 1e-5, ftol = 1e-5; - double xd_found = InverseSingleBracket(yd, sigmoid, x0, xtol, ftol); + int info = 0; + double xd_found = InverseSingleBracket(yd, sigmoid, x0, xtol, ftol, info); CHECK( xd_found == Approx(xd).epsilon(2*xtol)); + CHECK(info==0); } SECTION("Test Inverse Sigmoid, high x0") { double xd = 0.5, yd = sigmoid(xd); double x0 = 1.0, xtol = 1e-5, ftol = 1e-5; - double xd_found = InverseSingleBracket(yd, sigmoid, x0, xtol, ftol); + int info; + double xd_found = InverseSingleBracket(yd, sigmoid, x0, xtol, ftol, info); CHECK( xd_found == Approx(xd).epsilon(2*xtol)); + CHECK(info==0); } SECTION("Test Inverse Sigmoid Combo, low x0") { double xd = 0.5, yd = sigmoid_combo(xd); double x0 = -5.0, xtol = 1e-5, ftol = 1e-5; - double xd_found = InverseSingleBracket(yd, sigmoid_combo, x0, xtol, ftol); + int info; + double xd_found = InverseSingleBracket(yd, sigmoid_combo, x0, xtol, ftol, info); CHECK( xd_found == Approx(xd).epsilon(2*xtol)); + CHECK(info==0); } SECTION("Test Inverse Sigmoid Combo, high x0") { double xd = 0.5, yd = sigmoid_combo(xd); double x0 = 5.0, xtol = 1e-5, ftol = 1e-5; - double xd_found = InverseSingleBracket(yd, sigmoid_combo, x0, xtol, ftol); + int info; + double xd_found = InverseSingleBracket(yd, sigmoid_combo, x0, xtol, ftol, info); CHECK( xd_found == Approx(xd).epsilon(2*xtol)); + CHECK(info==0); } } \ No newline at end of file From 892c746342c218421b4c3213799148f007625718 Mon Sep 17 00:00:00 2001 From: Matthew Parno Date: Tue, 17 Oct 2023 17:21:45 -0400 Subject: [PATCH 5/6] Added additional check on slope. --- MParT/Utilities/RootFinding.h | 14 +++++++------- tests/Test_RootFinding.cpp | 4 +--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/MParT/Utilities/RootFinding.h b/MParT/Utilities/RootFinding.h index 971ef235..384d755f 100644 --- a/MParT/Utilities/RootFinding.h +++ b/MParT/Utilities/RootFinding.h @@ -43,9 +43,9 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, xlb = xub-stepSize; ylb = f(xlb); - if(abs((yub-ylb)/(xub-xlb))<1e-12){ + if((fabs((yub-ylb)/(xub-xlb))<1e-12)&&((xub-xlb)>10)){ info = -1; - break; + return; } if(ylb>yd){ @@ -67,11 +67,11 @@ KOKKOS_INLINE_FUNCTION void FindBracket(FunctorType f, for(i=0; i10)){ info = -1; - break; + return; } if(yub(f, xlb, ylb, xub, yub, yd, bracket_info); + if((bracket_info<0)||(((ylb>yd)||(yub::quiet_NaN(); @@ -142,7 +143,6 @@ KOKKOS_INLINE_FUNCTION double InverseSingleBracket(double yd, FunctorType f, dou unsigned int it; for(it=0; it Date: Wed, 18 Oct 2023 14:00:25 -0400 Subject: [PATCH 6/6] Cleaning up unnecessary comments. --- MParT/MonotoneComponent.h | 157 +------------------------------------- 1 file changed, 1 insertion(+), 156 deletions(-) diff --git a/MParT/MonotoneComponent.h b/MParT/MonotoneComponent.h index aa7744fb..d5fab1d5 100644 --- a/MParT/MonotoneComponent.h +++ b/MParT/MonotoneComponent.h @@ -312,16 +312,6 @@ class MonotoneComponent : public ConditionalMapBase StridedVector output, std::map options=std::map()) { - // std::cout << "xs.shape = " << xs.extent(0) << "," << xs.extent(1) << std::endl; - // std::cout << "xs = \n" << std::endl; - // for(unsigned int row=0; row QuadratureType const& quad, ExpansionType const& expansion) { - // std::cout << "pt = " << std::endl; - // for(unsigned int i=0; i integrand(cache, @@ -1006,148 +986,13 @@ class MonotoneComponent : public ConditionalMapBase DerivativeFlags::None); quad.Integrate(workspace, integrand, 0, 1, &output); - // std::cout << "output 1 = " << output << std::endl; - - // Finish filling in the cache for an evaluation of the expansion with x_d=0 - // std::cout << "pt = " << std::endl; - // for(unsigned int i=0; imaxIts) - // ProcAgnosticError::error("InverseSingleBracket: upper bound calculation exceeds maxIts"); - // } - - // assert(ylb0)?1.0:-1.0; // sign(xb-xf) - // delta = fmin(k1*pow((xub-xlb), k2), fabs(xb-xf)); - - // xf += delta*sigma; - - // rho = fmin(xtol*pow(2.0, nhalf + n0 - it) - 0.5*(xub-xlb), fabs(xf - xb)); - // xc = xb - sigma*rho; - - // yc = EvaluateSingle(workspace, cache, pt, xc, coeffs, quad, expansion); - - // if(abs(yc-yd)yd){ - // mpart::simple_swap(yc,yub); - // mpart::simple_swap(xc,xub); - // }else{ - // mpart::simple_swap(yc,ylb); - // mpart::simple_swap(xc,xlb); - // } - - // // Check for convergence - // if(((xub-xlb)maxIts) - // ProcAgnosticError::error("InverseSingleBracket: Bracket search iterations exceeds maxIts"); - // return 0.5*(xub+xlb); - // } - /** Give access to the underlying FixedMultiIndexSet * @return The FixedMultiIndexSet */