vnl_lsqr.cxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_lsqr.cxx
2 //
3 // vnl_lsqr
4 // Author: David Capel
5 // Created: July 2000
6 //
7 //-----------------------------------------------------------------------------
8 
9 #include <vector>
10 #include <iostream>
11 #include <algorithm>
12 #include "vnl_lsqr.h"
13 #include <vnl/vnl_vector_ref.h>
14 
15 #include "lsqrBase.h"
16 
17 class lsqrVNL : public lsqrBase
18 {
19 public:
20 
22  {
23  this->ls_ = nullptr;
24  }
25 
26  ~lsqrVNL() override = default;
27 
28  /**
29  * computes y = y + A*x without altering x,
30  * where A is a matrix of dimensions A[m][n].
31  * The size of the vector x is n.
32  * The size of the vector y is m.
33  */
34  void Aprod1(unsigned int m, unsigned int n, const double * x, double * y ) const override
35  {
36  vnl_vector_ref<double> x_ref(n, const_cast<double*>(x) );
37  vnl_vector_ref<double> y_ref(m,y);
38 
40  this->ls_->multiply(x_ref, tmp);
41  y_ref += tmp;
42  }
43 
44 
45  /**
46  * computes x = x + A'*y without altering y,
47  * where A is a matrix of dimensions A[m][n].
48  * The size of the vector x is n.
49  * The size of the vector y is m.
50  */
51  void Aprod2(unsigned int m, unsigned int n, double * x, const double * y ) const override
52  {
53  vnl_vector_ref<double> x_ref(n,x);
54  vnl_vector_ref<double> y_ref(m, const_cast<double*>( y ) );
55 
56  vnl_vector_ref<double> tmp(n,this->rw);
57  this->ls_->transpose_multiply(y_ref, tmp);
58  x_ref += tmp;
59  }
60 
61  /** Set the linear system to be solved A*x = b. */
63  {
64  this->ls_ = inls;
65  }
66 
67  void SetWorkingSpace( double * inrw )
68  {
69  this->rw = inrw;
70  }
71 
72 private:
73 
75 
76  double * rw;
77 };
78 
79 
80 vnl_lsqr::~vnl_lsqr() = default;
81 
82 // Requires number_of_residuals() of workspace in rw.
83 int vnl_lsqr::aprod_(const long* mode, const long* m, const long* n, double* x, double* y, long* /*leniw*/, long* /*lenrw*/, long* /*iw*/, double* rw, void* userdata)
84 {
85  //
86  // THIS CODE IS DEPRECATED
87  // THE FUNCTIONALITY HAS BEEN MOVED TO THE lsqrVNL class above.
88  // THE FUNCTIONS IS CONSERVED HERE ONLY FOR BACKWARD COMPATIBILITY.
89  //
90  auto* self = static_cast<vnl_lsqr*>(userdata);
91 
92  // If MODE = 1, compute y = y + A*x.
93  // If MODE = 2, compute x = x + A(transpose)*y.
94 
95  vnl_vector_ref<double> x_ref(*n,x);
96  vnl_vector_ref<double> y_ref(*m,y);
97 
98  if (*mode == 1) {
99  vnl_vector_ref<double> tmp(*m,rw);
100  self->ls_->multiply(x_ref, tmp);
101  y_ref += tmp;
102  }
103  else {
104  vnl_vector_ref<double> tmp(*n,rw);
105  self->ls_->transpose_multiply(y_ref, tmp);
106  x_ref += tmp;
107  }
108 
109  return 0;
110 }
111 
113 {
114  long m = ls_->get_number_of_residuals();
115  long n = ls_->get_number_of_unknowns();
116  double damp = 0;
117 
118  //NOTE: rw is a scratch space used for both intermediate residual and unknown computations
119  std::vector<double> rw(std::max(m,n));
120  std::vector<double> v(n);
121  std::vector<double> se(n);
122 
123  double atol = 0;
124  double btol = 0;
125 #ifdef THIS_CODE_IS_DISABLED_BECAUSE_THE_LSQR_CODE_FROM_NETLIB_WAS_COPYRIGHTED_BY_ACM
126  double conlim = 0;
127  long nout = -1;
128  double acond, rnorm, xnorm;
129 #endif
130  double anorm, arnorm;
131 
132  vnl_vector<double> rhs(m);
133  ls_->get_rhs(rhs);
134 
135  lsqrVNL solver;
136 
137  solver.SetDamp( damp );
138  solver.SetLinearSystem( this->ls_ );
139  solver.SetWorkingSpace( rw.data() );
140  solver.SetMaximumNumberOfIterations( max_iter_ );
141  solver.SetStandardErrorEstimates( se.data() );
142  solver.SetToleranceA( atol );
143  solver.SetToleranceB( btol );
144 
145  solver.Solve( m, n, rhs.data_block(), result.data_block() );
146 
147 #ifdef THIS_CODE_IS_DISABLED_BECAUSE_THE_LSQR_CODE_FROM_NETLIB_WAS_COPYRIGHTED_BY_ACM
148  v3p_netlib_lsqr_(
149  &m, &n, aprod_, &damp, &leniw, &lenrw, iw, &rw[0],
150  rhs.data_block(), &v[0], &w[0], result.data_block(), &se[0],
151  &atol, &btol, &conlim, &max_iter_, &nout, &return_code_,
152  &num_iter_, &anorm, &acond, &rnorm, &arnorm, &xnorm,
153  this);
154 #endif
155 
156  resid_norm_estimate_ = solver.GetFinalEstimateOfNormRbar();
157  result_norm_estimate_ = solver.GetFinalEstimateOfNormOfX();
158  A_condition_estimate_ = solver.GetConditionNumberEstimateOfAbar();
159  return_code_ = solver.GetStoppingReason();
160  num_iter_ = solver.GetNumberOfIterationsPerformed();
161  anorm = solver.GetFrobeniusNormEstimateOfAbar();
162  arnorm = solver.GetFinalEstimateOfNormOfResiduals();
163 
164 #ifdef THIS_CODE_IS_DISABLED_BECAUSE_THE_LSQR_CODE_FROM_NETLIB_WAS_COPYRIGHTED_BY_ACM
165  std::cerr << "A Fro norm estimate = " << anorm << std::endl
166  << "A condition estimate = " << acond << std::endl
167  << "Residual norm estimate = " << rnorm << std::endl
168  << "A'(Ax - b) norm estimate = " << arnorm << std::endl
169  << "x norm estimate = " << xnorm << std::endl;
170 #endif
171 
172  // We should return the return code, as translate_return_code is public and
173  // it is very misleading that the return code from this function can't be fed
174  // into translate_return_code. (Brian Amberg)
175  return return_code_;
176 }
177 
178 void vnl_lsqr::diagnose_outcome(std::ostream& os) const
179 {
181  os << __FILE__ " : residual norm estimate = " << resid_norm_estimate_ << std::endl
182  << __FILE__ " : result norm estimate = " << result_norm_estimate_ << std::endl
183  << __FILE__ " : condition no. estimate = " << A_condition_estimate_ << std::endl
184  << __FILE__ " : iterations = " << num_iter_ << std::endl;
185 }
186 
187 void vnl_lsqr::translate_return_code(std::ostream& os, int rc)
188 {
189  const char* vnl_lsqr_reasons[] = {
190  "x = 0 is the exact solution. No iterations were performed.",
191  "The equations A*x = b are probably compatible. "
192  "Norm(A*x - b) is sufficiently small, given the "
193  "values of ATOL and BTOL.",
194  "The system A*x = b is probably not compatible. "
195  "A least-squares solution has been obtained that is "
196  "sufficiently accurate, given the value of ATOL.",
197  "An estimate of cond(Abar) has exceeded CONLIM. "
198  "The system A*x = b appears to be ill-conditioned. "
199  "Otherwise, there could be an error in subroutine APROD.",
200  "The equations A*x = b are probably compatible. "
201  "Norm(A*x - b) is as small as seems reasonable on this machine.",
202  "The system A*x = b is probably not compatible. A least-squares "
203  "solution has been obtained that is as accurate as seems "
204  "reasonable on this machine.",
205  "Cond(Abar) seems to be so large that there is no point in doing further "
206  "iterations, given the precision of this machine. "
207  "There could be an error in subroutine APROD.",
208  "The iteration limit ITNLIM was reached."
209  };
210 
211  if
212  (rc < 0 || rc > 7) os << __FILE__ " : Illegal return code : " << rc << std::endl;
213  else
214  os << __FILE__ " : " << vnl_lsqr_reasons[rc] << std::endl;
215 }
vnl_linear_system * ls_
Definition: vnl_lsqr.cxx:74
double * rw
Definition: vnl_lsqr.cxx:76
static int aprod_(const long *mode, const long *m, const long *n, double *x, double *y, long *leniw, long *lenrw, long *iw, double *rw, void *userdata)
Definition: vnl_lsqr.cxx:83
virtual void multiply(vnl_vector< double > const &x, vnl_vector< double > &y) const =0
Compute A*x, putting result in y.
virtual void get_rhs(vnl_vector< double > &b) const =0
void Aprod1(unsigned int m, unsigned int n, const double *x, double *y) const override
computes y = y + A*x without altering x, where A is a matrix of dimensions A[m][n].
Definition: vnl_lsqr.cxx:34
double resid_norm_estimate_
Definition: vnl_lsqr.h:69
double A_condition_estimate_
Definition: vnl_lsqr.h:71
vnl_vector using user-supplied storage
vnl_vector using user-supplied storage.
Definition: vnl_fwd.h:17
static void translate_return_code(std::ostream &os, int return_code)
Definition: vnl_lsqr.cxx:187
#define m
Definition: vnl_vector.h:43
T const * data_block() const
Access the contiguous block storing the elements in the vector. O(1).
Definition: vnl_vector.h:230
vnl_linear_system * ls_
Definition: vnl_lsqr.h:66
void SetWorkingSpace(double *inrw)
Definition: vnl_lsqr.cxx:67
Abstraction for a linear system of equations.
#define v
Definition: vnl_vector.h:42
Linear least squares.
lsqrVNL()
Definition: vnl_lsqr.cxx:21
unsigned int get_number_of_residuals() const
Return the number of residuals.
virtual void transpose_multiply(vnl_vector< double > const &y, vnl_vector< double > &x) const =0
Compute A_transpose * y, putting result in x.
double result_norm_estimate_
Definition: vnl_lsqr.h:70
long num_iter_
Definition: vnl_lsqr.h:68
vnl_decnum max(vnl_decnum const &x, vnl_decnum const &y)
Definition: vnl_decnum.h:412
long max_iter_
Definition: vnl_lsqr.h:67
unsigned int get_number_of_unknowns() const
Return the number of unknowns.
void diagnose_outcome(std::ostream &os) const
Pontificate about the outcome of the last minimization.
Definition: vnl_lsqr.cxx:178
long return_code_
Definition: vnl_lsqr.h:73
~lsqrVNL() override=default
void Aprod2(unsigned int m, unsigned int n, double *x, const double *y) const override
computes x = x + A'*y without altering y, where A is a matrix of dimensions A[m][n].
Definition: vnl_lsqr.cxx:51
void SetLinearSystem(vnl_linear_system *inls)
Set the linear system to be solved A*x = b.
Definition: vnl_lsqr.cxx:62
int minimize(vnl_vector< double > &x)
Perform the minimization starting from x=0 and putting the result into x.
Definition: vnl_lsqr.cxx:112