vnl_conjugate_gradient.cxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_conjugate_gradient.cxx
2 //:
3 // \file
4 // \author Geoffrey Cross, Oxford RRG
5 // \date 15 Feb 99
6 //
7 //-----------------------------------------------------------------------------
8 #include <iostream>
10 
11 #include <vnl/vnl_cost_function.h>
12 #include <vnl/vnl_vector_ref.h>
13 #include <vnl/algo/vnl_netlib.h>
14 
15 /////////////////////////////////////
16 
18 
20 {
21  f_= &f;
22  num_iterations_ = 0;
23  num_evaluations_ = 0;
24  start_error_ = 0;
25  end_error_ = 0;
26 }
27 
28 ///////////////////////////////////////
29 
30 double vnl_conjugate_gradient::valuecomputer_(double *x, void* userdata)
31 {
32  auto* self =
33  static_cast<vnl_conjugate_gradient*>(userdata);
34  vnl_cost_function* f = self->f_;
36 
37  self->num_evaluations_++;
38 
39  return f->f(ref_x);
40 }
41 
42 void vnl_conjugate_gradient::gradientcomputer_(double *g, double *x, void* userdata)
43 {
44  auto* self =
45  static_cast<vnl_conjugate_gradient*>(userdata);
46  vnl_cost_function* f = self->f_;
49 
50  f->gradf(ref_x, ref_g);
51 }
52 
53 void vnl_conjugate_gradient::valueandgradientcomputer_(double *v, double *g, double *x, void* userdata)
54 {
55  auto* self =
56  static_cast<vnl_conjugate_gradient*>(userdata);
57  vnl_cost_function* f = self->f_;
60 
61  f->compute(ref_x, v, &ref_g);
62 }
63 
64 void vnl_conjugate_gradient::preconditioner_( double *out, double *in, void* userdata)
65 {
66  // FIXME - there should be some way to set a preconditioner if you have one
67  // e.g. P = inv(diag(A'A)) for linear least squares systems.
68 
69  auto* self =
70  static_cast<vnl_conjugate_gradient*>(userdata);
71  vnl_cost_function* f = self->f_;
72 
73  int n = f->get_number_of_unknowns();
74  for (int i=0; i < n; ++i)
75  out[i] = in[i];
76 }
77 
78 ///////////////////////////////////////
80 {
81  double *xp = x.data_block();
82  double max_norm_of_gradient;
83  long number_of_iterations;
84  final_step_size_ = 0;
85  double gradient_tolerance = gtol;
87  long number_of_unknowns = f_->get_number_of_unknowns();
88  long error_code;
89 
90  // Compute the initial value.
91  start_error_ = valuecomputer_(xp, this);
92  num_evaluations_ = 0;
93 
94  // Run the conjugate gradient algorithm.
95  v3p_netlib_cg_(
96  xp,
97  &max_norm_of_gradient,
98  &number_of_iterations,
100  &gradient_tolerance,
101  &maxfev,
102  &number_of_unknowns,
103  &number_of_unknowns,
108  workspace.data_block(),
109  this,
110  &error_code);
111 
112  // Check for an error condition.
113  if (error_code > 0)
114  {
116  if (verbose_)
117  {
118  switch (error_code)
119  {
120  case 1: std::cout << "UNABLE TO OBTAIN DESCENT DIRECTION\n"; break;
121  case 2: std::cout << "THE FUNCTION DECREASES WITH NO MINIMUM\n"; break;
122  case 3: std::cout << "PRECONDITIONER NOT POSITIVE DEFINITE\n"; break;
123  case 4: std::cout << "UNABLE TO SATISFY ARMIJO CONDITION\n"; break;
124  default: std::cout << "UNKNOWN ERROR CODE\n"; break;
125  }
126  }
127  }
128 
129  // Compute the final value.
130  end_error_= valuecomputer_(xp, this);
131  num_iterations_ = number_of_iterations;
132 
133  return error_code == 0;
134 }
135 
137 void vnl_conjugate_gradient::diagnose_outcome(std::ostream& os) const
138 {
139  os << "vnl_conjugate_gradient: "
140  << num_iterations_
141  << " iterations, "
143  << " evaluations. Cost function reported error"
145  << '/'
147  << " . Final step size = " << final_step_size_
148  << std::endl;
149 }
152 {
153  diagnose_outcome(std::cout);
154 }
An object that represents a function from R^n -> R.
virtual void gradf(vnl_vector< double > const &x, vnl_vector< double > &gradient)
Calculate the gradient of f at parameter vector x.
int get_number_of_unknowns() const
Return the number of unknowns.
static double valuecomputer_(double *x, void *userdata)
vnl_vector using user-supplied storage
~vnl_conjugate_gradient() override
Destructor.
vnl_vector using user-supplied storage.
Definition: vnl_fwd.h:17
Vector->Real function.
real function minimization
T const * data_block() const
Access the contiguous block storing the elements in the vector. O(1).
Definition: vnl_vector.h:230
double f(vnl_vector< double > const &x) override
The main function. Given the parameter vector x, compute the value of f(x).
#define v
Definition: vnl_vector.h:42
double gtol
Termination tolerance on Grad(F)' * F = 0.
Declare in a central place the list of symbols from netlib.
static void preconditioner_(double *out, double *in, void *userdata)
bool minimize(vnl_vector< double > &x)
Minimize the function supplied in the constructor until convergence or failure.
virtual void compute(vnl_vector< double > const &x, double *f, vnl_vector< double > *g)
Compute one or both of f and g.
long maxfev
Termination maximum number of iterations.
void init(vnl_cost_function &f)
Initialize all variables.
virtual double reported_error(double f_value)
Called when error is printed for user.
static void gradientcomputer_(double *g, double *x, void *userdata)
static void valueandgradientcomputer_(double *v, double *g, double *x, void *userdata)