vnl_sparse_lst_sqr_function.h
Go to the documentation of this file.
1 // This is core/vnl/vnl_sparse_lst_sqr_function.h
2 #ifndef vnl_sparse_lst_sqr_function_h_
3 #define vnl_sparse_lst_sqr_function_h_
4 //:
5 // \file
6 // \brief Abstract base for sparse least squares functions
7 // \author Matt Leotta (Brown)
8 // \date April 13, 2005
9 //
10 // \verbatim
11 // Modifications
12 // Apr 13, 2005 MJL - Modified from vnl_least_squares_function
13 // Mar 15, 2010 MJL - Modified to add 'c' parameters (globals)
14 // \endverbatim
15 //
16 #include <vnl/vnl_vector.h>
17 #include <vnl/vnl_matrix.h>
18 #include <vnl/vnl_crs_index.h>
19 #include "vnl/vnl_export.h"
20 
21 //: Abstract base for sparse least squares functions.
22 // vnl_sparse_lst_sqr_function is an abstract base for functions to be minimized
23 // by an optimizer. To define your own function to be minimized, subclass
24 // from vnl_sparse_lst_sqr_function, and implement the pure virtual f (and
25 // optionally grad_f).
26 //
27 // This differs from a vnl_least_squares_function in that many entries in the
28 // Jacobian are known to be zero, and we don't want to compute them. The particular
29 // sparse structure is that described in Hartley and Zisserman section A4.3. It
30 // is assumed that the parameter vector can be partitioned into sets A and B.
31 // These are further partitioned into subsets {a_1, a_2, ... a_m} and
32 // {b_1, b_2, ... b_n}. Likewise, the residual vector X is partitioned into
33 // {x_11, x_12, ... x_mn} (not all x_ij are required). We further assume that
34 // dx_ij/da_k = 0 for all i != k and dx_ij/db_k = 0 for all j != k.
35 //
36 // This implementation further generalizes the concept by allowing for a
37 // third set of parameters C that are non-sparse. That is, dx_ij/dC != 0
38 // for all i and j (in general).
39 //
40 // An example use case is bundle adjustment where each a_i is the parameters
41 // for one of m cameras, each b_j is the parameters of a 3D point, and x_ij
42 // is the projection error of the jth point by the ith camera. If type
43 // C parameters are used, they might represent the unknown intrinic camera
44 // parameters that are assumed to be fixed over all images.
46 {
47  public:
48  enum UseGradient {
50  use_gradient
51  };
52  enum UseWeights {
54  use_weights
55  };
56  bool failure;
57 
58  //: Construct vnl_sparse_lst_sqr_function.
59  // Assumes A consists of \p num_a parameters each of size \p num_params_per_a
60  // Assumes B consists of \p num_b parameters each of size \p num_params_per_b
61  // Assumes C consists of \p num_params_c parameters
62  // Assumes there is a residual x_ij for all i and j, each of size \p num_residuals_per_e
63  // The optional argument should be no_gradient if the gradf function has not
64  // been implemented. Default is use_gradient.
65  vnl_sparse_lst_sqr_function(unsigned int num_a,
66  unsigned int num_params_per_a,
67  unsigned int num_b,
68  unsigned int num_params_per_b,
69  unsigned int num_params_c,
70  unsigned int num_residuals_per_e,
71  UseGradient g = use_gradient,
72  UseWeights w = no_weights);
73 
74  //: Construct vnl_sparse_lst_sqr_function.
75  // Assumes A consists of \p num_a parameters each of size \p num_params_per_a
76  // Assumes B consists of \p num_b parameters each of size \p num_params_per_b
77  // Assumes C consists of \p num_params_c parameters
78  // \p xmask is a mask for residual availability. residual e_ij exists only if mask[i][j]==true
79  // Assumes each available residual has size \p num_residuals_per_e
80  // The optional argument should be no_gradient if the gradf function has not
81  // been implemented. Default is use_gradient.
82  vnl_sparse_lst_sqr_function(unsigned int num_a,
83  unsigned int num_params_per_a,
84  unsigned int num_b,
85  unsigned int num_params_per_b,
86  unsigned int num_params_c,
87  const std::vector<std::vector<bool> >& xmask,
88  unsigned int num_residuals_per_e,
89  UseGradient g = use_gradient,
90  UseWeights w = no_weights);
91 
92  //: Construct vnl_sparse_lst_sqr_function.
93  // This constructor is the most general
94  // \param a_sizes is a vector describing the number of parameters for each a_i
95  // \param b_sizes is a vector describing the number of parameters for each b_j
96  // \param num_params_c is the number of C parameters
97  // \param e_sizes is a vector describing the number of parameters for each residual e_ij
98  // \param xmask is a mask for residual availability. residual e_ij exists only if mask[i][j]==true
99  // xmask must be a_sizes.size() by b_sizes.size() and contain e_sizes.size() true entries
100  // The optional argument should be no_gradient if the gradf function has not
101  // been implemented. Default is use_gradient.
102  vnl_sparse_lst_sqr_function(const std::vector<unsigned int>& a_sizes,
103  const std::vector<unsigned int>& b_sizes,
104  unsigned int num_params_c,
105  const std::vector<unsigned int>& e_sizes,
106  const std::vector<std::vector<bool> >& xmask,
107  UseGradient g = use_gradient,
108  UseWeights w = no_weights);
109 
110  virtual ~vnl_sparse_lst_sqr_function() = default;
111 
112  // the virtuals may call this to signal a failure.
113  void throw_failure() { failure = true; }
114  void clear_failure() { failure = false; }
115 
116  //: Compute all residuals.
117  // Given the parameter vectors a, b, and c, compute the vector of residuals f.
118  // f has been sized appropriately before the call.
119  // The default implementation computes f by calling fij for each valid
120  // pair of i and j. You do not need to overload this method unless you
121  // want to provide a more efficient implementation for your problem.
122  virtual void f(vnl_vector<double> const& a,
123  vnl_vector<double> const& b,
124  vnl_vector<double> const& c,
125  vnl_vector<double>& f);
126 
127  //: Compute the sparse Jacobian in block form.
128  // Given the parameter vectors a, b, and c, compute the set of block
129  // Jacobians Aij, Bij, and Cij.
130  // All Aij, Bij, and Cij have been sized appropriately before the call.
131  // The default implementation computes A, B, and C by calling
132  // jac_Aij, jac_Bij, and jac_Cij for each valid pair of i and j.
133  // You do not need to overload this method unless you want to provide
134  // a more efficient implementation for your problem.
135  virtual void jac_blocks(vnl_vector<double> const& a,
136  vnl_vector<double> const& b,
137  vnl_vector<double> const& c,
138  std::vector<vnl_matrix<double> >& A,
139  std::vector<vnl_matrix<double> >& B,
140  std::vector<vnl_matrix<double> >& C);
141 
142  //: Compute the sparse Jacobian in block form using a finite difference approximation.
143  // Given the parameter vectors a, b and c, compute the set of block Jacobians
144  // Aij, Bij, and Cij. The finite difference approximation is done independently
145  // at each block. All Aij, Bij, and Cij have been sized appropriately before the call.
146  // The default implementation computes A, B, and C by calling
147  // jac_Aij, jac_Bij, and jac_Cij for each valid pair of i and j.
148  // You do not need to overload this method unless you want to provide
149  // a more efficient implementation for your problem.
150  virtual void fd_jac_blocks(vnl_vector<double> const& a,
151  vnl_vector<double> const& b,
152  vnl_vector<double> const& c,
153  std::vector<vnl_matrix<double> >& A,
154  std::vector<vnl_matrix<double> >& B,
155  std::vector<vnl_matrix<double> >& C,
156  double stepsize);
157 
158  //: If using weighted least squares, compute the weights for each i and j.
159  // Return the weights in \a weights.
160  // The default implementation computes \a weights by calling
161  // compute_weight_ij for each valid pair of i and j.
162  // You do not need to overload this method unless you want to provide
163  // a more specialized implementation for your problem.
164  virtual void compute_weights(vnl_vector<double> const& a,
165  vnl_vector<double> const& b,
166  vnl_vector<double> const& c,
167  vnl_vector<double> const& f,
168  vnl_vector<double>& weights);
169 
170  //: If using weighted least squares, apply the weights to residuals f.
171  // The default implementation applies \a weights by calling
172  // apply_weight_ij for each valid pair of i and j.
173  // You do not need to overload this method unless you want to provide
174  // a more specialized implementation for your problem.
175  virtual void apply_weights(vnl_vector<double> const& weights,
176  vnl_vector<double>& f);
177 
178  //: If using weighted least squares, apply the weights to residuals A, B, C.
179  // The default implementation applies \a weights by calling
180  // apply_weight_ij for each valid pair of i and j.
181  // You do not need to overload this method unless you want to provide
182  // a more specialized implementation for your problem.
183  virtual void apply_weights(vnl_vector<double> const& weights,
184  std::vector<vnl_matrix<double> >& A,
185  std::vector<vnl_matrix<double> >& B,
186  std::vector<vnl_matrix<double> >& C);
187 
188  //: Compute the residuals from the ith component of a, the jth component of b.
189  // Given the parameter vectors ai, bj, and c, compute the vector of residuals fij.
190  // fij has been sized appropriately before the call.
191  virtual void fij(int i, int j,
192  vnl_vector<double> const& ai,
193  vnl_vector<double> const& bj,
194  vnl_vector<double> const& c,
195  vnl_vector<double>& fij);
196 
197  //: Calculate the Jacobian A_ij, given the parameter vectors a_i, b_j, and c.
198  virtual void jac_Aij(unsigned int i, unsigned int j,
199  vnl_vector<double> const& ai,
200  vnl_vector<double> const& bj,
201  vnl_vector<double> const& c,
202  vnl_matrix<double>& Aij);
203 
204  //: Calculate the Jacobian B_ij, given the parameter vectors a_i, b_j, and c.
205  virtual void jac_Bij(unsigned int i, unsigned int j,
206  vnl_vector<double> const& ai,
207  vnl_vector<double> const& bj,
208  vnl_vector<double> const& c,
209  vnl_matrix<double>& Bij);
210 
211  //: Calculate the Jacobian C_ij, given the parameter vectors a_i, b_j, and c.
212  virtual void jac_Cij(unsigned int i, unsigned int j,
213  vnl_vector<double> const& ai,
214  vnl_vector<double> const& bj,
215  vnl_vector<double> const& c,
216  vnl_matrix<double>& Cij);
217 
218  //: Use this to compute a finite-difference Jacobian A_ij
219  void fd_jac_Aij(int i, int j,
220  vnl_vector<double> const& ai,
221  vnl_vector<double> const& bj,
222  vnl_vector<double> const& c,
223  vnl_matrix<double>& Aij,
224  double stepsize);
225 
226  //: Use this to compute a finite-difference Jacobian B_ij
227  void fd_jac_Bij(int i, int j,
228  vnl_vector<double> const& ai,
229  vnl_vector<double> const& bj,
230  vnl_vector<double> const& c,
231  vnl_matrix<double>& Bij,
232  double stepsize);
233 
234  //: Use this to compute a finite-difference Jacobian C_ij
235  void fd_jac_Cij(int i, int j,
236  vnl_vector<double> const& ai,
237  vnl_vector<double> const& bj,
238  vnl_vector<double> const& c,
239  vnl_matrix<double>& Cij,
240  double stepsize);
241 
242  //: If using weighted least squares, compute the weight.
243  // Return the weight in \a weight.
244  // The default implementation sets weight = 1
245  virtual void compute_weight_ij(int i, int j,
246  vnl_vector<double> const& ai,
247  vnl_vector<double> const& bj,
248  vnl_vector<double> const& c,
249  vnl_vector<double> const& fij,
250  double& weight);
251 
252  //: If using weighted least squares, apply the weight to fij.
253  // The default implementation multiplies fij by weight.
254  virtual void apply_weight_ij(int i, int j,
255  double const& weight,
256  vnl_vector<double>& fij);
257 
258  //: If using weighted least squares, apply the weight to Aij, Bij, Cij.
259  // The default implementation multiplies each matrix by weight.
260  virtual void apply_weight_ij(int i, int j,
261  double const& weight,
262  vnl_matrix<double>& Aij,
263  vnl_matrix<double>& Bij,
264  vnl_matrix<double>& Cij);
265 
266  //: Called after each LM iteration to print debugging etc.
267  virtual void trace(int iteration,
268  vnl_vector<double> const& a,
269  vnl_vector<double> const& b,
270  vnl_vector<double> const& c,
271  vnl_vector<double> const& e);
272 
273  //: Return the number of parameters of a_j
274  unsigned int number_of_params_a(int i) const { return indices_a_[i+1]-indices_a_[i]; }
275 
276  //: Return the number of parameters of b_i
277  unsigned int number_of_params_b(int j) const { return indices_b_[j+1]-indices_b_[j]; }
278 
279  //: Return the number of parameters of c
280  unsigned int number_of_params_c() const { return num_params_c_; }
281 
282  //: Return the number of residuals in the kth residual vector.
283  unsigned int number_of_residuals(int k) const { return indices_e_[k+1]-indices_e_[k]; }
284 
285  //: Return the number of residuals for x_ij.
286  unsigned int number_of_residuals(int i, int j) const
287  {
288  int k = residual_indices_(i,j);
289  if (k<0) return 0;
290  else return number_of_residuals(k);
291  }
292 
293  //: return the index of aj in a
294  unsigned int index_a(int i) const { return indices_a_[i]; }
295 
296  //: return the index of bj in b
297  unsigned int index_b(int j) const { return indices_b_[j]; }
298 
299  //: return the index of ek in e
300  unsigned int index_e(int k) const { return indices_e_[k]; }
301 
302  //: Return the number of subsets in \p a
303  unsigned int number_of_a() const { return (unsigned int)(indices_a_.size()-1); }
304 
305  //: Return the number of subsets in \p b
306  unsigned int number_of_b() const { return (unsigned int)(indices_b_.size()-1); }
307 
308  //: Return the number of residual vectors
309  unsigned int number_of_e() const { return (unsigned int)(indices_e_.size()-1); }
310 
311  //: Return true if the derived class has indicated that gradf has been implemented
312  bool has_gradient() const { return use_gradient_; }
313 
314  //: Return true if the derived class has indicated that
315  // \a apply_weights or \a apply_weight_ij have been implemented
316  bool has_weights() const { return use_weights_; }
317 
318  //: Return a const reference to the residual indexer
319  const vnl_crs_index& residual_indices() const { return residual_indices_; }
320 
321  protected:
323  std::vector<unsigned int> indices_a_;
324  std::vector<unsigned int> indices_b_;
325  unsigned int num_params_c_;
326  std::vector<unsigned int> indices_e_;
327 
330 
331  private:
332  void dim_warning(unsigned int n_unknowns, unsigned int n_residuals);
333 };
334 
335 #endif // vnl_sparse_lst_sqr_function_h_
unsigned int number_of_params_a(int i) const
Return the number of parameters of a_j.
unsigned int number_of_residuals(int i, int j) const
Return the number of residuals for x_ij.
unsigned int index_a(int i) const
return the index of aj in a.
unsigned int number_of_b() const
Return the number of subsets in b.
unsigned int number_of_params_c() const
Return the number of parameters of c.
Compressed Row Storage (CRS) indexing.
std::vector< unsigned int > indices_e_
const vnl_crs_index & residual_indices() const
Return a const reference to the residual indexer.
unsigned int number_of_residuals(int k) const
Return the number of residuals in the kth residual vector.
unsigned int index_b(int j) const
return the index of bj in b.
An ordinary mathematical matrix.
unsigned int number_of_a() const
Return the number of subsets in a.
unsigned int index_e(int k) const
return the index of ek in e.
Abstract base for sparse least squares functions.
bool has_weights() const
Return true if the derived class has indicated that.
std::vector< unsigned int > indices_b_
unsigned int number_of_e() const
Return the number of residual vectors.
Represents the configuration of a sparse matrix but not the data.
Definition: vnl_crs_index.h:26
unsigned int number_of_params_b(int j) const
Return the number of parameters of b_i.
std::vector< unsigned int > indices_a_
bool has_gradient() const
Return true if the derived class has indicated that gradf has been implemented.