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_