LBFGS++
Loading...
Searching...
No Matches
LineSearchBracketing.h
1// Copyright (C) 2016-2023 Yixuan Qiu <yixuan.qiu@cos.name>
2// Copyright (C) 2016-2023 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
11namespace LBFGSpp {
12
16template <typename Scalar>
18{
19private:
20 using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
21
22public:
46 template <typename Foo>
47 static void LineSearch(Foo& f, const LBFGSParam<Scalar>& param,
48 const Vector& xp, const Vector& drt, const Scalar& step_max,
49 Scalar& step, Scalar& fx, Vector& grad, Scalar& dg, Vector& x)
50 {
51 // Check the value of step
52 if (step <= Scalar(0))
53 throw std::invalid_argument("'step' must be positive");
54
55 // Save the function value at the current x
56 const Scalar fx_init = fx;
57 // Projection of gradient on the search direction
58 const Scalar dg_init = grad.dot(drt);
59 // Make sure d points to a descent direction
60 if (dg_init > 0)
61 throw std::logic_error("the moving direction increases the objective function value");
62
63 const Scalar test_decr = param.ftol * dg_init;
64
65 // Upper and lower end of the current line search range
66 Scalar step_lo = 0,
67 step_hi = std::numeric_limits<Scalar>::infinity();
68
69 int iter;
70 for (iter = 0; iter < param.max_linesearch; iter++)
71 {
72 // x_{k+1} = x_k + step * d_k
73 x.noalias() = xp + step * drt;
74 // Evaluate this candidate
75 fx = f(x, grad);
76
77 if (fx > fx_init + step * test_decr || (fx != fx))
78 {
79 step_hi = step;
80 }
81 else
82 {
83 dg = grad.dot(drt);
84
85 // Armijo condition is met
87 break;
88
89 if (dg < param.wolfe * dg_init)
90 {
91 step_lo = step;
92 }
93 else
94 {
95 // Regular Wolfe condition is met
97 break;
98
99 if (dg > -param.wolfe * dg_init)
100 {
101 step_hi = step;
102 }
103 else
104 {
105 // Strong Wolfe condition is met
106 break;
107 }
108 }
109 }
110
111 assert(step_lo < step_hi);
112
113 if (step < param.min_step)
114 throw std::runtime_error("the line search step became smaller than the minimum value allowed");
115
116 if (step > param.max_step)
117 throw std::runtime_error("the line search step became larger than the maximum value allowed");
118
119 // continue search in mid of current search range
120 step = std::isinf(step_hi) ? 2 * step : step_lo / 2 + step_hi / 2;
121 }
122
123 if (iter >= param.max_linesearch)
124 throw std::runtime_error("the line search routine reached the maximum number of iterations");
125 }
126};
127
128} // namespace LBFGSpp
129
130#endif // LBFGSPP_LINE_SEARCH_BRACKETING_H
Scalar max_step
Definition: Param.h:147
Scalar min_step
Definition: Param.h:141
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