LBFGS++ 0.4.0
A header-only C++ library for L-BFGS and L-BFGS-B algorithms.
Loading...
Searching...
No Matches
LineSearchBracketing.h
1// Copyright (C) 2016-2026 Yixuan Qiu <yixuan.qiu@cos.name>
2// Copyright (C) 2016-2026 Dirk Toewe <DirkToewe@GoogleMail.com>
3// Under MIT license
4
5#ifndef LBFGSPP_LINE_SEARCH_BRACKETING_H
6#define LBFGSPP_LINE_SEARCH_BRACKETING_H
7
8#include <Eigen/Core>
9#include <stdexcept> // std::runtime_error
10#include <cmath>
11#include "Param.h"
12
13namespace LBFGSpp {
14
18template <typename Scalar>
20{
21private:
22 using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
23
24public:
48 template <typename Foo>
49 static void LineSearch(Foo& f, const LBFGSParam<Scalar>& param,
50 const Vector& xp, const Vector& drt, const Scalar& step_max,
51 Scalar& step, Scalar& fx, Vector& grad, Scalar& dg, Vector& x)
52 {
53 // Check the value of step
54 if (step <= Scalar(0))
55 throw std::invalid_argument("'step' must be positive");
56
57 // Save the function value at the current x
58 const Scalar fx_init = fx;
59 // Projection of gradient on the search direction
60 const Scalar dg_init = grad.dot(drt);
61 // Make sure d points to a descent direction
62 if (dg_init > 0)
63 throw std::logic_error("the moving direction increases the objective function value");
64
65 const Scalar test_decr = param.ftol * dg_init;
66
67 // Upper and lower end of the current line search range
68 Scalar step_lo = 0,
69 step_hi = std::numeric_limits<Scalar>::infinity();
70
71 int iter;
72 for (iter = 0; iter < param.max_linesearch; iter++)
73 {
74 // x_{k+1} = x_k + step * d_k
75 x.noalias() = xp + step * drt;
76 // Evaluate this candidate
77 fx = f(x, grad);
78
79 if (fx > fx_init + step * test_decr || (!std::isfinite(fx)))
80 {
81 step_hi = step;
82 }
83 else
84 {
85 dg = grad.dot(drt);
86
87 // Armijo condition is met
89 break;
90
91 if (dg < param.wolfe * dg_init)
92 {
93 step_lo = step;
94 }
95 else
96 {
97 // Regular Wolfe condition is met
99 break;
100
101 if (dg > -param.wolfe * dg_init)
102 {
103 step_hi = step;
104 }
105 else
106 {
107 // Strong Wolfe condition is met
108 break;
109 }
110 }
111 }
112
113 if (step_lo > step_hi)
114 throw std::runtime_error("the lower bound of the bracketing interval becomes larger than the upper bound");
115
116 if (step < param.min_step)
117 throw std::runtime_error("the line search step became smaller than the minimum value allowed");
118
119 if (step > param.max_step)
120 throw std::runtime_error("the line search step became larger than the maximum value allowed");
121
122 // continue search in mid of current search range
123 step = std::isinf(step_hi) ? 2 * step : step_lo / 2 + step_hi / 2;
124 }
125
126 if (iter >= param.max_linesearch)
127 throw std::runtime_error("the line search routine reached the maximum number of iterations");
128 }
129};
130
131} // namespace LBFGSpp
132
133#endif // LBFGSPP_LINE_SEARCH_BRACKETING_H
static void LineSearch(Foo &f, const LBFGSParam< Scalar > &param, const Vector &xp, const Vector &drt, const Scalar &step_max, Scalar &step, Scalar &fx, Vector &grad, Scalar &dg, Vector &x)
@ LBFGS_LINESEARCH_BACKTRACKING_ARMIJO
Definition Param.h:35
@ LBFGS_LINESEARCH_BACKTRACKING_WOLFE
Definition Param.h:51