core/vnl/vnl_sparse_lst_sqr_function.h
Go to the documentation of this file.
00001 // This is core/vnl/vnl_sparse_lst_sqr_function.h
00002 #ifndef vnl_sparse_lst_sqr_function_h_
00003 #define vnl_sparse_lst_sqr_function_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \brief Abstract base for sparse least squares functions
00010 // \author Matt Leotta (Brown)
00011 // \date   April 13, 2005
00012 //
00013 // \verbatim
00014 //  Modifications
00015 //   Apr 13, 2005  MJL - Modified from vnl_least_squares_function
00016 //   Mar 15, 2010  MJL - Modified to add 'c' parameters (globals)
00017 // \endverbatim
00018 //
00019 #include <vnl/vnl_vector.h>
00020 #include <vnl/vnl_matrix.h>
00021 #include <vnl/vnl_crs_index.h>
00022 
00023 //: Abstract base for sparse least squares functions.
00024 //    vnl_sparse_lst_sqr_function is an abstract base for functions to be minimized
00025 //    by an optimizer.  To define your own function to be minimized, subclass
00026 //    from vnl_sparse_lst_sqr_function, and implement the pure virtual f (and
00027 //    optionally grad_f).
00028 //
00029 //    This differs from a vnl_least_squares_function in that many entries in the
00030 //    Jacobian are known to be zero, and we don't want to compute them.  The particular
00031 //    sparse structure is that described in Hartley and Zisserman section A4.3.  It
00032 //    is assumed that the parameter vector can be partitioned into sets A and B.
00033 //    These are further partitioned into subsets {a_1, a_2, ... a_m} and
00034 //    {b_1, b_2, ... b_n}.  Likewise, the residual vector X is partitioned into
00035 //    {x_11, x_12, ... x_mn} (not all x_ij are required).  We further assume that
00036 //    dx_ij/da_k = 0 for all i != k and dx_ij/db_k = 0 for all j != k.
00037 //
00038 //    This implementation further generalizes the concept by allowing for a
00039 //    third set of parameters C that are non-sparse.  That is, dx_ij/dC != 0
00040 //    for all i and j (in general).
00041 //
00042 //    An example use case is bundle adjustment where each a_i is the parameters
00043 //    for one of m cameras, each b_j is the parameters of a 3D point, and x_ij
00044 //    is the projection error of the jth point by the ith camera.  If type
00045 //    C parameters are used, they might represent the unknown intrinic camera
00046 //    parameters that are assumed to be fixed over all images.
00047 class vnl_sparse_lst_sqr_function
00048 {
00049  public:
00050   enum  UseGradient {
00051     no_gradient,
00052     use_gradient
00053   };
00054   enum  UseWeights {
00055     no_weights,
00056     use_weights
00057   };
00058   bool failure;
00059 
00060   //: Construct vnl_sparse_lst_sqr_function.
00061   // Assumes A consists of \p num_a parameters each of size \p num_params_per_a
00062   // Assumes B consists of \p num_b parameters each of size \p num_params_per_b
00063   // Assumes C consists of \p num_params_c parameters
00064   // Assumes there is a residual x_ij for all i and j, each of size \p num_residuals_per_e
00065   // The optional argument should be no_gradient if the gradf function has not
00066   // been implemented.  Default is use_gradient.
00067   vnl_sparse_lst_sqr_function(unsigned int num_a,
00068                               unsigned int num_params_per_a,
00069                               unsigned int num_b,
00070                               unsigned int num_params_per_b,
00071                               unsigned int num_params_c,
00072                               unsigned int num_residuals_per_e,
00073                               UseGradient g = use_gradient,
00074                               UseWeights w = no_weights);
00075 
00076   //: Construct vnl_sparse_lst_sqr_function.
00077   // Assumes A consists of \p num_a parameters each of size \p num_params_per_a
00078   // Assumes B consists of \p num_b parameters each of size \p num_params_per_b
00079   // Assumes C consists of \p num_params_c parameters
00080   // \p xmask is a mask for residual availability.  residual e_ij exists only if mask[i][j]==true
00081   // Assumes each available residual has size \p num_residuals_per_e
00082   // The optional argument should be no_gradient if the gradf function has not
00083   // been implemented.  Default is use_gradient.
00084   vnl_sparse_lst_sqr_function(unsigned int num_a,
00085                               unsigned int num_params_per_a,
00086                               unsigned int num_b,
00087                               unsigned int num_params_per_b,
00088                               unsigned int num_params_c,
00089                               const vcl_vector<vcl_vector<bool> >& xmask,
00090                               unsigned int num_residuals_per_e,
00091                               UseGradient g = use_gradient,
00092                               UseWeights w = no_weights);
00093 
00094   //: Construct vnl_sparse_lst_sqr_function.
00095   // This constructor is the most general
00096   // \param a_sizes is a vector describing the number of parameters for each a_i
00097   // \param b_sizes is a vector describing the number of parameters for each b_j
00098   // \param num_params_c is the number of C parameters
00099   // \param e_sizes is a vector describing the number of parameters for each residual e_ij
00100   // \param xmask is a mask for residual availability.  residual e_ij exists only if mask[i][j]==true
00101   // xmask must be a_sizes.size() by b_sizes.size() and contain e_sizes.size() true entries
00102   // The optional argument should be no_gradient if the gradf function has not
00103   // been implemented.  Default is use_gradient.
00104   vnl_sparse_lst_sqr_function(const vcl_vector<unsigned int>& a_sizes,
00105                               const vcl_vector<unsigned int>& b_sizes,
00106                               unsigned int num_params_c,
00107                               const vcl_vector<unsigned int>& e_sizes,
00108                               const vcl_vector<vcl_vector<bool> >& xmask,
00109                               UseGradient g = use_gradient,
00110                               UseWeights w = no_weights);
00111 
00112   virtual ~vnl_sparse_lst_sqr_function() {}
00113 
00114   // the virtuals may call this to signal a failure.
00115   void throw_failure() { failure = true; }
00116   void clear_failure() { failure = false; }
00117 
00118   //: Compute all residuals.
00119   //  Given the parameter vectors a, b, and c, compute the vector of residuals f.
00120   //  f has been sized appropriately before the call.
00121   //  The default implementation computes f by calling fij for each valid
00122   //  pair of i and j.  You do not need to overload this method unless you
00123   //  want to provide a more efficient implementation for your problem.
00124   virtual void f(vnl_vector<double> const& a,
00125                  vnl_vector<double> const& b,
00126                  vnl_vector<double> const& c,
00127                  vnl_vector<double>& f);
00128 
00129   //: Compute the sparse Jacobian in block form.
00130   //  Given the parameter vectors a, b, and c, compute the set of block
00131   //  Jacobians Aij, Bij, and Cij.
00132   //  All Aij, Bij, and Cij have been sized appropriately before the call.
00133   //  The default implementation computes A, B, and C by calling
00134   //  jac_Aij, jac_Bij, and jac_Cij for each valid pair of i and j.
00135   //  You do not need to overload this method unless you want to provide
00136   //  a more efficient implementation for your problem.
00137   virtual void jac_blocks(vnl_vector<double> const& a,
00138                           vnl_vector<double> const& b,
00139                           vnl_vector<double> const& c,
00140                           vcl_vector<vnl_matrix<double> >& A,
00141                           vcl_vector<vnl_matrix<double> >& B,
00142                           vcl_vector<vnl_matrix<double> >& C);
00143 
00144   //: Compute the sparse Jacobian in block form using a finite difference approximation.
00145   //  Given the parameter vectors a, b and c, compute the set of block Jacobians
00146   //  Aij, Bij, and Cij.  The finite difference approximation is done independently
00147   //  at each block.  All Aij, Bij, and Cij have been sized appropriately before the call.
00148   //  The default implementation computes A, B, and C by calling
00149   //  jac_Aij, jac_Bij, and jac_Cij for each valid pair of i and j.
00150   //  You do not need to overload this method unless you want to provide
00151   //  a more efficient implementation for your problem.
00152   virtual void fd_jac_blocks(vnl_vector<double> const& a,
00153                              vnl_vector<double> const& b,
00154                              vnl_vector<double> const& c,
00155                              vcl_vector<vnl_matrix<double> >& A,
00156                              vcl_vector<vnl_matrix<double> >& B,
00157                              vcl_vector<vnl_matrix<double> >& C,
00158                              double stepsize);
00159 
00160   //: If using weighted least squares, compute the weights for each i and j.
00161   //  Return the weights in \a weights.
00162   //  The default implementation computes \a weights by calling
00163   //  compute_weight_ij for each valid pair of i and j.
00164   //  You do not need to overload this method unless you want to provide
00165   //  a more specialized implementation for your problem.
00166   virtual void compute_weights(vnl_vector<double> const& a,
00167                                vnl_vector<double> const& b,
00168                                vnl_vector<double> const& c,
00169                                vnl_vector<double> const& f,
00170                                vnl_vector<double>& weights);
00171 
00172   //: If using weighted least squares, apply the weights to residuals f.
00173   //  The default implementation applies \a weights by calling
00174   //  apply_weight_ij for each valid pair of i and j.
00175   //  You do not need to overload this method unless you want to provide
00176   //  a more specialized implementation for your problem.
00177   virtual void apply_weights(vnl_vector<double> const& weights,
00178                              vnl_vector<double>& f);
00179 
00180   //: If using weighted least squares, apply the weights to residuals A, B, C.
00181   //  The default implementation applies \a weights by calling
00182   //  apply_weight_ij for each valid pair of i and j.
00183   //  You do not need to overload this method unless you want to provide
00184   //  a more specialized implementation for your problem.
00185   virtual void apply_weights(vnl_vector<double> const& weights,
00186                              vcl_vector<vnl_matrix<double> >& A,
00187                              vcl_vector<vnl_matrix<double> >& B,
00188                              vcl_vector<vnl_matrix<double> >& C);
00189 
00190   //: Compute the residuals from the ith component of a, the jth component of b.
00191   //  Given the parameter vectors ai, bj, and c, compute the vector of residuals fij.
00192   //  fij has been sized appropriately before the call.
00193   virtual void fij(int i, int j,
00194                    vnl_vector<double> const& ai,
00195                    vnl_vector<double> const& bj,
00196                    vnl_vector<double> const& c,
00197                    vnl_vector<double>& fij);
00198 
00199   //: Calculate the Jacobian A_ij, given the parameter vectors a_i, b_j, and c.
00200   virtual void jac_Aij(int i, int j,
00201                        vnl_vector<double> const& ai,
00202                        vnl_vector<double> const& bj,
00203                        vnl_vector<double> const& c,
00204                        vnl_matrix<double>& Aij);
00205 
00206   //: Calculate the Jacobian B_ij, given the parameter vectors a_i, b_j, and c.
00207   virtual void jac_Bij(int i, int j,
00208                        vnl_vector<double> const& ai,
00209                        vnl_vector<double> const& bj,
00210                        vnl_vector<double> const& c,
00211                        vnl_matrix<double>& Bij);
00212 
00213   //: Calculate the Jacobian C_ij, given the parameter vectors a_i, b_j, and c.
00214   virtual void jac_Cij(int i, int j,
00215                        vnl_vector<double> const& ai,
00216                        vnl_vector<double> const& bj,
00217                        vnl_vector<double> const& c,
00218                        vnl_matrix<double>& Cij);
00219 
00220   //: Use this to compute a finite-difference Jacobian A_ij
00221   void fd_jac_Aij(int i, int j,
00222                   vnl_vector<double> const& ai,
00223                   vnl_vector<double> const& bj,
00224                   vnl_vector<double> const& c,
00225                   vnl_matrix<double>& Aij,
00226                   double stepsize);
00227 
00228   //: Use this to compute a finite-difference Jacobian B_ij
00229   void fd_jac_Bij(int i, int j,
00230                   vnl_vector<double> const& ai,
00231                   vnl_vector<double> const& bj,
00232                   vnl_vector<double> const& c,
00233                   vnl_matrix<double>& Bij,
00234                   double stepsize);
00235 
00236   //: Use this to compute a finite-difference Jacobian C_ij
00237   void fd_jac_Cij(int i, int j,
00238                   vnl_vector<double> const& ai,
00239                   vnl_vector<double> const& bj,
00240                   vnl_vector<double> const& c,
00241                   vnl_matrix<double>& Cij,
00242                   double stepsize);
00243 
00244   //: If using weighted least squares, compute the weight.
00245   //  Return the weight in \a weight.
00246   //  The default implementation sets weight = 1
00247   virtual void compute_weight_ij(int i, int j,
00248                                  vnl_vector<double> const& ai,
00249                                  vnl_vector<double> const& bj,
00250                                  vnl_vector<double> const& c,
00251                                  vnl_vector<double> const& fij,
00252                                  double& weight);
00253 
00254   //: If using weighted least squares, apply the weight to fij.
00255   //  The default implementation multiplies fij by weight.
00256   virtual void apply_weight_ij(int i, int j,
00257                                double const& weight,
00258                                vnl_vector<double>& fij);
00259 
00260   //: If using weighted least squares, apply the weight to Aij, Bij, Cij.
00261   //  The default implementation multiplies each matrix by weight.
00262   virtual void apply_weight_ij(int i, int j,
00263                                double const& weight,
00264                                vnl_matrix<double>& Aij,
00265                                vnl_matrix<double>& Bij,
00266                                vnl_matrix<double>& Cij);
00267 
00268   //: Called after each LM iteration to print debugging etc.
00269   virtual void trace(int iteration,
00270                      vnl_vector<double> const& a,
00271                      vnl_vector<double> const& b,
00272                      vnl_vector<double> const& c,
00273                      vnl_vector<double> const& e);
00274 
00275   //: Return the number of parameters of a_j
00276   unsigned int number_of_params_a(int i) const { return indices_a_[i+1]-indices_a_[i]; }
00277 
00278   //: Return the number of parameters of b_i
00279   unsigned int number_of_params_b(int j) const { return indices_b_[j+1]-indices_b_[j]; }
00280 
00281   //: Return the number of parameters of c
00282   unsigned int number_of_params_c() const { return num_params_c_; }
00283 
00284   //: Return the number of residuals in the kth residual vector.
00285   unsigned int number_of_residuals(int k) const { return indices_e_[k+1]-indices_e_[k]; }
00286 
00287   //: Return the number of residuals for x_ij.
00288   unsigned int number_of_residuals(int i, int j) const
00289   {
00290     int k = residual_indices_(i,j);
00291     if (k<0) return 0;
00292     else return number_of_residuals(k);
00293   }
00294 
00295   //: return the index of aj in a
00296   unsigned int index_a(int i) const { return indices_a_[i]; }
00297 
00298   //: return the index of bj in b
00299   unsigned int index_b(int j) const { return indices_b_[j]; }
00300 
00301   //: return the index of ek in e
00302   unsigned int index_e(int k) const { return indices_e_[k]; }
00303 
00304   //: Return the number of subsets in \p a
00305   unsigned int number_of_a() const { return (unsigned int)(indices_a_.size()-1); }
00306 
00307   //: Return the number of subsets in \p b
00308   unsigned int number_of_b() const { return (unsigned int)(indices_b_.size()-1); }
00309 
00310   //: Return the number of residual vectors
00311   unsigned int number_of_e() const { return (unsigned int)(indices_e_.size()-1); }
00312 
00313   //: Return true if the derived class has indicated that gradf has been implemented
00314   bool has_gradient() const { return use_gradient_; }
00315 
00316   //: Return true if the derived class has indicated that
00317   //  \a apply_weights or \a apply_weight_ij have been implemented
00318   bool has_weights() const { return use_weights_; }
00319 
00320   //: Return a const reference to the residual indexer
00321   const vnl_crs_index& residual_indices() const { return residual_indices_; }
00322 
00323  protected:
00324   vnl_crs_index residual_indices_;
00325   vcl_vector<unsigned int> indices_a_;
00326   vcl_vector<unsigned int> indices_b_;
00327   unsigned int num_params_c_;
00328   vcl_vector<unsigned int> indices_e_;
00329 
00330   bool use_gradient_;
00331   bool use_weights_;
00332 
00333  private:
00334   void dim_warning(unsigned int n_unknowns, unsigned int n_residuals);
00335 };
00336 
00337 #endif // vnl_sparse_lst_sqr_function_h_