63 template <
typename VECTOR>
struct bfgs_invhessian {
65 typedef typename linalg_traits<VECTOR>::value_type T;
66 typedef typename number_traits<T>::magnitude_type R;
68 std::vector<VECTOR> delta, gamma, zeta;
69 std::vector<T> tau, rho;
72 template<
typename VEC1,
typename VEC2>
void hmult(
const VEC1 &X, VEC2 &Y) {
74 for (
size_type k = 0 ; k < delta.size(); ++k) {
78 add(scaled(zeta[k], rho[k]*xdelta), Y);
79 add(scaled(delta[k], rho[k]*(xzeta-rho[k]*tau[k]*xdelta)), Y);
82 add(scaled(delta[k], rho[k]*xdelta), Y);
83 add(scaled(zeta[k], -xzeta/tau[k]), Y);
90 delta.resize(0); gamma.resize(0); zeta.resize(0);
91 tau.resize(0); rho.resize(0);
94 template<
typename VECT1,
typename VECT2>
95 void update(
const VECT1 &deltak,
const VECT2 &gammak) {
96 T vsp =
vect_sp(deltak, gammak);
97 if (vsp == T(0))
return;
98 size_type N = vect_size(deltak), k = delta.size();
101 delta.resize(k+1); gamma.resize(k+1); zeta.resize(k+1);
102 tau.resize(k+1); rho.resize(k+1);
104 gmm::copy(deltak, delta[k]);
105 gmm::copy(gammak, gamma[k]);
108 add(delta[k], scaled(Y, -1), zeta[k]);
110 gmm::copy(Y, zeta[k]);
111 tau[k] =
vect_sp(gammak, zeta[k]);
114 bfgs_invhessian(
int v = 0) { version = v; }
118 template <
typename FUNCTION,
typename DERIVATIVE,
typename VECTOR>
119 void bfgs(
const FUNCTION &f,
const DERIVATIVE &grad, VECTOR &x,
120 int restart, iteration& iter,
int version = 0,
121 double lambda_init=0.001,
double print_norm=1.0) {
123 typedef typename linalg_traits<VECTOR>::value_type T;
124 typedef typename number_traits<T>::magnitude_type R;
126 bfgs_invhessian<VECTOR> invhessian(version);
127 VECTOR r(vect_size(x)), d(vect_size(x)), y(vect_size(x)), r2(vect_size(x));
129 R lambda = lambda_init, valx = f(x), valy;
132 if (iter.get_noisy() >= 1) cout <<
"value " << valx / print_norm <<
" ";
133 while (! iter.finished_vect(r)) {
135 invhessian.hmult(r, d); gmm::scale(d, T(-1));
138 R derivative = gmm::vect_sp(r, d);
139 R lambda_min(0), lambda_max(0), m1 = 0.27, m2 = 0.57;
140 bool unbounded =
true, blocked =
false, grad_computed =
false;
143 add(x, scaled(d, lambda), y);
145 if (iter.get_noisy() >= 2) {
147 cout <<
"Wolfe line search, lambda = " << lambda
148 <<
" value = " << valy /print_norm << endl;
153 if (valy <= valx + m1 * lambda * derivative) {
154 grad(y, r2); grad_computed =
true;
155 T derivative2 = gmm::vect_sp(r2, d);
156 if (derivative2 >= m2*derivative)
break;
163 if (unbounded) lambda *= R(10);
164 else lambda = (lambda_max + lambda_min) / R(2);
165 if (lambda == lambda_max || lambda == lambda_min)
break;
169 if (valy <= valx + R(2)*gmm::abs(derivative)*lambda &&
170 (lambda < R(lambda_init*1E-8) ||
171 (!unbounded && lambda_max-lambda_min < R(lambda_init*1E-8))))
172 { blocked =
true; lambda = lambda_init;
break; }
177 if (!grad_computed) grad(y, r2);
178 gmm::add(scaled(r2, -1), r);
179 if ((iter.get_iteration() % restart) == 0 || blocked) {
180 if (iter.get_noisy() >= 1) cout <<
"Restart\n";
181 invhessian.restart();
182 if (++nb_restart > 10) {
183 if (iter.get_noisy() >= 1) cout <<
"BFGS is blocked, exiting\n";
188 invhessian.update(gmm::scaled(d,lambda), gmm::scaled(r,-1));
191 copy(r2, r);
copy(y, x); valx = valy;
192 if (iter.get_noisy() >= 1)
193 cout <<
"BFGS value " << valx/print_norm <<
"\t";
199 template <
typename FUNCTION,
typename DERIVATIVE,
typename VECTOR>
200 inline void dfp(
const FUNCTION &f,
const DERIVATIVE &grad, VECTOR &x,
201 int restart, iteration& iter,
int version = 1) {
202 bfgs(f, grad, x, restart, iter, version);