vnl_lbfgs.cxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_lbfgs.cxx
2 //:
3 // \file
4 //
5 // \author Andrew W. Fitzgibbon, Oxford RRG
6 // \date 22 Aug 99
7 //
8 //-----------------------------------------------------------------------------
9 
10 #include <cmath>
11 #include <iostream>
12 #include <iomanip>
13 #include "vnl_lbfgs.h"
14 
15 #include <vnl/algo/vnl_netlib.h> // lbfgs_()
16 
17 //: Default constructor.
18 // memory is set to 5, line_search_accuracy to 0.9.
19 // Calls init_parameters
21  f_(nullptr)
22 {
24 }
25 
26 //: Constructor. f is the cost function to be minimized.
27 // Calls init_parameters
29  f_(&f)
30 {
32 }
33 
34 //: Called by constructors.
35 // Memory is set to 5, line_search_accuracy to 0.9, default_step_length to 1.
37 {
38  memory = 5;
40  default_step_length = 1.0;
41 }
42 
44 {
45  // Local variables
46  // The driver for vnl_lbfgs must always declare LB2 as EXTERNAL
47 
48  long n = f_->get_number_of_unknowns();
49  long m = memory; // The number of basis vectors to remember.
50 
51  // Create an instance of the lbfgs global data to pass as an
52  // argument. It must persist through all calls in this
53  // minimization.
54  v3p_netlib_lbfgs_global_t lbfgs_global;
55  v3p_netlib_lbfgs_init(&lbfgs_global);
56 
57  long iprint[2] = {1, 0};
58  vnl_vector<double> g(n);
59 
60  // Workspace
61  vnl_vector<double> diag(n);
62 
63  vnl_vector<double> w(n * (2*m+1)+2*m);
64 
65  if (verbose_)
66  std::cerr << "vnl_lbfgs: n = "<< n <<", memory = "<< m <<", Workspace = "
67  << w.size() << "[ "<< ( w.size() / 128.0 / 1024.0) <<" MB], ErrorScale = "
68  << f_->reported_error(1) <<", xnorm = "<< x.magnitude() << std::endl;
69 
70  bool we_trace = (verbose_ && !trace);
71 
72  if (we_trace)
73  std::cerr << "vnl_lbfgs: ";
74 
75  double best_f = 0;
76  vnl_vector<double> best_x;
77 
78  bool ok;
79  this->num_evaluations_ = 0;
80  this->num_iterations_ = 0;
81  long iflag = 0;
82  while (true) {
83  // We do not wish to provide the diagonal matrices Hk0, and therefore set DIAGCO to FALSE.
84  v3p_netlib_logical diagco = false;
85 
86  // Set these every iter in case user changes them to bail out
87  double eps = gtol; // Gradient tolerance
88  double local_xtol = 1e-16;
89  lbfgs_global.gtol = line_search_accuracy; // set to 0.1 for huge problems or cheap functions
90  lbfgs_global.stpinit = default_step_length;
91 
92  // Call function
93  double f;
94  f_->compute(x, &f, &g);
95  if (this->num_evaluations_ == 0) {
96  this->start_error_ = f;
97  best_x = x;
98  best_f = f;
99  } else if (f < best_f) {
100  best_x = x;
101  best_f = f;
102  }
103 
104 #define print_(i,a,b,c,d) std::cerr<<std::setw(6)<<(i)<<' '<<std::setw(20)<<(a)<<' '\
105  <<std::setw(20)<<(b)<<' '<<std::setw(20)<<(c)<<' '<<std::setw(20)<<(d)<<'\n'
106 
107  if (check_derivatives_)
108  {
109  std::cerr << "vnl_lbfgs: f = " << f_->reported_error(f) << ", computing FD gradient\n";
110  vnl_vector<double> fdg = f_->fdgradf(x);
111  if (verbose_)
112  {
113  int l = n;
114  int limit = 100;
115  int limit_tail = 10;
116  if (l > limit + limit_tail) {
117  std::cerr << " [ Showing only first " <<limit<< " components ]\n";
118  l = limit;
119  }
120  print_("i","x","g","fdg","dg");
121  print_("-","-","-","---","--");
122  for (int i = 0; i < l; ++i)
123  print_(i, x[i], g[i], fdg[i], g[i]-fdg[i]);
124  if (n > limit) {
125  std::cerr << " ...\n";
126  for (int i = n - limit_tail; i < n; ++i)
127  print_(i, x[i], g[i], fdg[i], g[i]-fdg[i]);
128  }
129  }
130  std::cerr << " ERROR = " << (fdg - g).squared_magnitude() / std::sqrt(double(n)) << "\n";
131  }
132 
133  iprint[0] = trace ? 1 : -1; // -1 no o/p, 0 start and end, 1 every iter.
134  iprint[1] = 0; // 1 prints X and G
135  v3p_netlib_lbfgs_(
136  &n, &m, x.data_block(), &f, g.data_block(), &diagco, diag.data_block(),
137  iprint, &eps, &local_xtol, w.data_block(), &iflag, &lbfgs_global);
138 
139  this->report_eval(f);
140 
141  if (this->report_iter()) {
143  ok = false;
144  x = best_x;
145  break;
146  }
147 
148  if (we_trace)
149  std::cerr << iflag << ":" << f_->reported_error(f) << " ";
150 
151  if (iflag == 0) {
152  // Successful return
153  this->end_error_ = f;
154  ok = true;
155  x = best_x;
156  break;
157  }
158 
159  if (iflag < 0) {
160  // Netlib routine lbfgs failed
161  std::cerr << "vnl_lbfgs: Error. Netlib routine lbfgs failed.\n";
162  ok = false;
163  x = best_x;
164  break;
165  }
166 
169  ok = false;
170  x = best_x;
171  break;
172  }
173 
174  }
175  if (we_trace) std::cerr << "done\n";
176 
177  return ok;
178 }
An object that represents a function from R^n -> R.
Limited memory Broyden Fletcher Goldfarb Shannon minimization.
int get_number_of_unknowns() const
Return the number of unknowns.
double default_step_length
Default step length in line search.
Definition: vnl_lbfgs.h:67
vnl_lbfgs()
Default constructor.
Definition: vnl_lbfgs.cxx:19
#define m
Definition: vnl_vector.h:43
size_t size() const
Return the length, number of elements, dimension of this vector.
Definition: vnl_vector.h:126
void init_parameters()
Called by constructors.
Definition: vnl_lbfgs.cxx:35
T const * data_block() const
Access the contiguous block storing the elements in the vector. O(1).
Definition: vnl_vector.h:230
vnl_cost_function * f_
Definition: vnl_lbfgs.h:71
abs_t magnitude() const
Return magnitude (length) of vector.
Definition: vnl_vector.h:282
int memory
Step accuracy/speed tradeoff.
Definition: vnl_lbfgs.h:55
vnl_bignum squared_magnitude(vnl_bignum const &x)
Definition: vnl_bignum.h:433
void fdgradf(vnl_vector< double > const &x, vnl_vector< double > &gradient, double stepsize=1e-5)
Compute finite-difference gradient.
void report_eval(double f)
Called by derived classes after each function evaluation.
double line_search_accuracy
Accuracy of line search.
Definition: vnl_lbfgs.h:60
virtual bool report_iter()
Called by derived classes after each iteration.
double gtol
Termination tolerance on Grad(F)' * F = 0.
Declare in a central place the list of symbols from netlib.
#define print_(i, a, b, c, d)
virtual void compute(vnl_vector< double > const &x, double *f, vnl_vector< double > *g)
Compute one or both of f and g.
virtual double reported_error(double f_value)
Called when error is printed for user.
bool minimize(vnl_vector< double > &x)
Definition: vnl_lbfgs.cxx:42