Automatic Differentiation
 
Loading...
Searching...
No Matches
barzilai_borwein_step_size.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_MIX_FUNCTOR_BARZILAI_BORWEIN_STEP_SIZE_HPP
2#define STAN_MATH_MIX_FUNCTOR_BARZILAI_BORWEIN_STEP_SIZE_HPP
4#include <algorithm>
5#include <numeric>
6#include <cmath>
7
8namespace stan::math::internal {
63inline double barzilai_borwein_step_size(const Eigen::VectorXd& s,
64 const Eigen::VectorXd& g_curr,
65 const Eigen::VectorXd& g_prev,
66 double prev_step, int last_backtracks,
67 double min_alpha, double max_alpha) {
68 // Fallbacks
69 auto safe_fallback = [&]() -> double {
70 double a = std::clamp(
71 prev_step > 0.0 && std::isfinite(prev_step) ? prev_step : 1.0,
72 min_alpha, max_alpha);
73 return a;
74 };
75
76 const Eigen::VectorXd y = g_curr - g_prev;
77 const double sty = s.dot(y);
78 const double sts = s.squaredNorm();
79 const double yty = y.squaredNorm();
80
81 // Basic validity checks
82 constexpr double eps = 1e-16;
83 if (!(std::isfinite(sty) && std::isfinite(sts) && std::isfinite(yty))
84 || sts <= eps || yty <= eps || sty <= eps || last_backtracks == -1) {
85 return safe_fallback();
86 }
87
88 // BB candidates
89 double alpha_bb1 = std::clamp(std::abs(sts / sty), min_alpha, max_alpha);
90 double alpha_bb2 = std::clamp(std::abs(sty / yty), min_alpha, max_alpha);
91
92 // Safeguard candidates
93 if (!std::isfinite(alpha_bb1) || !std::isfinite(alpha_bb2) || alpha_bb1 <= 0.0
94 || alpha_bb2 <= 0.0) {
95 return safe_fallback();
96 }
97
98 // Spectral cosine r = cos^2(angle(s, y)) in [0,1]
99 const double r = (sty * sty) / (sts * yty);
100
101 // Heuristic thresholds (robust defaults)
102 constexpr double kLoose = 0.9; // "nice" curvature
103 constexpr double kTight = 0.1; // "dodgy" curvature
104
105 double alpha0 = alpha_bb2; // default to short BB for robustness
106 if (r > kLoose && last_backtracks <= 1) {
107 // Spectrum looks friendly and line search was not harsh -> try long BB
108 alpha0 = alpha_bb1;
109 } else if (r >= kTight && r <= kLoose) {
110 // Neither clearly friendly nor clearly dodgy -> neutral middle
111 alpha0 = std::sqrt(alpha_bb1 * alpha_bb2);
112 } // else keep alpha_bb2
113
114 // Clip to user bounds
115 alpha0 = std::clamp(alpha0, min_alpha, max_alpha);
116
117 if (!std::isfinite(alpha0) || alpha0 <= 0.0) {
118 return safe_fallback();
119 }
120 return alpha0;
121}
122
123} // namespace stan::math::internal
124#endif
double barzilai_borwein_step_size(const Eigen::VectorXd &s, const Eigen::VectorXd &g_curr, const Eigen::VectorXd &g_prev, double prev_step, int last_backtracks, double min_alpha, double max_alpha)
Curvature-aware Barzilai–Borwein (BB) step length with robust safeguards.
A comparator that works for any container type that has the brackets operator.
static constexpr double e()
Return the base of the natural logarithm.
Definition constants.hpp:20