SRBA: Sparser Relative Bundle Adjustment
srba/impl/lev-marq_solvers.h
00001 /* +---------------------------------------------------------------------------+
00002    |                     Mobile Robot Programming Toolkit (MRPT)               |
00003    |                          http://www.mrpt.org/                             |
00004    |                                                                           |
00005    | Copyright (c) 2005-2015, Individual contributors, see AUTHORS file        |
00006    | See: http://www.mrpt.org/Authors - All rights reserved.                   |
00007    | Released under BSD License. See details in http://www.mrpt.org/License    |
00008    +---------------------------------------------------------------------------+ */
00009 
00010 #pragma once
00011 
00012 #include <mrpt/math/CSparseMatrix.h>
00013 #include <memory> // for auto_ptr, unique_ptr
00014 
00015 namespace srba {
00016 
00017 namespace internal
00018 {
00019 #if MRPT_HAS_CXX11
00020     typedef std::unique_ptr<mrpt::math::CSparseMatrix::CholeskyDecomp>  SparseCholeskyDecompPtr;
00021 #else
00022     typedef std::auto_ptr<mrpt::math::CSparseMatrix::CholeskyDecomp>    SparseCholeskyDecompPtr;
00023 #endif
00024 
00025     // ------------------------------------------------------------------------------------------
00027     template <class RBA_ENGINE>
00028     struct solver_engine<false /*Schur*/,false /*dense Chol*/,RBA_ENGINE>
00029     {
00030         typedef typename RBA_ENGINE::hessian_traits_t hessian_traits_t;
00031 
00032         static const size_t POSE_DIMS = RBA_ENGINE::kf2kf_pose_t::REL_POSE_DIMS;
00033         static const size_t LM_DIMS   = RBA_ENGINE::landmark_t::LM_DIMS;
00034 
00035         const int m_verbose_level;
00036         mrpt::utils::CTimeLogger &m_profiler;
00037         Eigen::VectorXd  delta_eps; 
00038         typename hessian_traits_t::TSparseBlocksHessian_Ap  &HAp;
00039         typename hessian_traits_t::TSparseBlocksHessian_f   &Hf;
00040         typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf;
00041         Eigen::VectorXd  &minus_grad;
00042         const size_t nUnknowns_k2k, nUnknowns_k2f, nUnknowns_scalars,idx_start_f;
00043 
00044         mrpt::math::CSparseMatrix* sS; 
00045         bool           sS_is_valid; 
00046 
00047         SparseCholeskyDecompPtr ptrCh;
00048 
00050         solver_engine(
00051             const int verbose_level,
00052             mrpt::utils::CTimeLogger & profiler,
00053             typename hessian_traits_t::TSparseBlocksHessian_Ap  &HAp_,
00054             typename hessian_traits_t::TSparseBlocksHessian_f   &Hf_,
00055             typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_,
00056             Eigen::VectorXd  &minus_grad_,
00057             const size_t nUnknowns_k2k_,
00058             const size_t nUnknowns_k2f_) :
00059                 m_verbose_level(verbose_level),
00060                 m_profiler(profiler),
00061                 HAp(HAp_), Hf(Hf_), HApf(HApf_),
00062                 minus_grad(minus_grad_),
00063                 nUnknowns_k2k(nUnknowns_k2k_),
00064                 nUnknowns_k2f(nUnknowns_k2f_),
00065                 nUnknowns_scalars( POSE_DIMS*nUnknowns_k2k + LM_DIMS*nUnknowns_k2f ),
00066                 idx_start_f(POSE_DIMS*nUnknowns_k2k),
00067                 sS(NULL), sS_is_valid(false)
00068         {
00069         }
00070 
00071         ~solver_engine()
00072         {
00073             if (sS) { delete sS; sS=NULL; }
00074         }
00075 
00076         // ----------------------------------------------------------------------
00077         // Solve the entire H Ax = -g system with H as a single sparse Hessian.
00078         // Return: true on success. false to retry with a different lambda (Lev-Marq algorithm is assumed)
00079         // ----------------------------------------------------------------------
00080         bool solve(const double lambda)
00081         {
00082             DETAILED_PROFILING_ENTER("opt.SparseTripletFill")
00083 
00084             if (!sS) sS = new mrpt::math::CSparseMatrix(nUnknowns_scalars,nUnknowns_scalars);
00085             else     sS->clear(nUnknowns_scalars,nUnknowns_scalars);
00086             sS_is_valid=false;
00087 
00088             // 1/3: Hp --------------------------------------
00089             for (size_t i=0;i<nUnknowns_k2k;i++)
00090             {   // Only upper-half triangle:
00091                 const typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t & col_i = HAp.getCol(i);
00092 
00093                 for (typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t::const_iterator itRowEntry = col_i.begin();itRowEntry != col_i.end(); ++itRowEntry )
00094                 {
00095                     if (itRowEntry->first==i)
00096                     {
00097                         // block Diagonal: Add lambda*I to these ones
00098                         typename hessian_traits_t::TSparseBlocksHessian_Ap::matrix_t sSii = itRowEntry->second.num;
00099                         for (size_t k=0;k<POSE_DIMS;k++)
00100                             sSii.coeffRef(k,k)+=lambda;
00101                         sS->insert_submatrix(POSE_DIMS*i,POSE_DIMS*i, sSii );
00102                     }
00103                     else
00104                     {
00105                         sS->insert_submatrix(
00106                             POSE_DIMS*itRowEntry->first,  // row index
00107                             POSE_DIMS*i,                  // col index
00108                             itRowEntry->second.num );
00109                     }
00110                 }
00111             }
00112 
00113             // 2/3: HApf --------------------------------------
00114             for (size_t i=0;i<nUnknowns_k2k;i++)
00115             {
00116                 const typename hessian_traits_t::TSparseBlocksHessian_Apf::col_t & row_i = HApf.getCol(i);
00117 
00118                 for (typename hessian_traits_t::TSparseBlocksHessian_Apf::col_t::const_iterator itColEntry = row_i.begin();itColEntry != row_i.end(); ++itColEntry )
00119                 {
00120                     sS->insert_submatrix(
00121                         POSE_DIMS*i,  // row index
00122                         idx_start_f+LM_DIMS*itColEntry->first,  // col index
00123                         itColEntry->second.num );
00124                 }
00125             }
00126 
00127             // 3/3: Hf --------------------------------------
00128             for (size_t i=0;i<nUnknowns_k2f;i++)
00129             {   // Only upper-half triangle:
00130                 const typename hessian_traits_t::TSparseBlocksHessian_f::col_t & col_i = Hf.getCol(i);
00131 
00132                 for (typename hessian_traits_t::TSparseBlocksHessian_f::col_t::const_iterator itRowEntry = col_i.begin();itRowEntry != col_i.end(); ++itRowEntry )
00133                 {
00134                     if (itRowEntry->first==i)
00135                     {
00136                         // block Diagonal: Add lambda*I to these ones
00137                         typename hessian_traits_t::TSparseBlocksHessian_f::matrix_t sSii = itRowEntry->second.num;
00138                         for (size_t k=0;k<LM_DIMS;k++)
00139                             sSii.coeffRef(k,k)+=lambda;
00140                         sS->insert_submatrix(idx_start_f+LM_DIMS*i,idx_start_f+LM_DIMS*i, sSii );
00141                     }
00142                     else
00143                     {
00144                         sS->insert_submatrix(
00145                             idx_start_f+LM_DIMS*itRowEntry->first,  // row index
00146                             idx_start_f+LM_DIMS*i,                  // col index
00147                             itRowEntry->second.num );
00148                     }
00149                 }
00150             }
00151             DETAILED_PROFILING_LEAVE("opt.SparseTripletFill")
00152 
00153             // Compress the sparse matrix:
00154             // --------------------------------------
00155             DETAILED_PROFILING_ENTER("opt.SparseTripletCompress")
00156             sS->compressFromTriplet();
00157             DETAILED_PROFILING_LEAVE("opt.SparseTripletCompress")
00158 
00159             // Sparse cholesky
00160             // --------------------------------------
00161             DETAILED_PROFILING_ENTER("opt.SparseChol")
00162             try
00163             {
00164                 if (!ptrCh.get())
00165                         ptrCh = SparseCholeskyDecompPtr(new mrpt::math::CSparseMatrix::CholeskyDecomp(*sS) );
00166                 else ptrCh.get()->update(*sS);
00167 
00168                 sS_is_valid=true;
00169 
00170                 DETAILED_PROFILING_LEAVE("opt.SparseChol")
00171             }
00172             catch (mrpt::math::CExceptionNotDefPos &)
00173             {
00174                 DETAILED_PROFILING_LEAVE("opt.SparseChol")
00175                 return false;
00176             }
00177 
00178             // backsubtitution gives us "DeltaEps" from Cholesky and "-grad":
00179             //
00180             //    (J^tJ + lambda*I) DeltaEps = -grad
00181             // ----------------------------------------------------------------
00182             DETAILED_PROFILING_ENTER("opt.backsub")
00183             ptrCh->backsub(minus_grad,delta_eps);
00184             DETAILED_PROFILING_LEAVE("opt.backsub")
00185 
00186             return true; // solved OK.
00187         }
00188 
00189         void realize_relinearized()
00190         {
00191             // Nothing to do.
00192         }
00193         void realize_lambda_changed()
00194         {
00195             // Nothing to do.
00196         }
00197         bool was_ith_feature_invertible(const size_t i)
00198         {
00199             MRPT_UNUSED_PARAM(i);
00200             return true;
00201         }
00202 
00204         void get_extra_results(typename RBA_ENGINE::rba_options_t::solver_t::extra_results_t & out_info )
00205         {
00206             out_info.hessian_valid = sS_is_valid;
00207             if (sS) sS->swap(out_info.hessian);
00208         }
00209     };
00210 
00211     // ------------------------------------------------------------------------------------------
00213     template <class RBA_ENGINE>
00214     struct solver_engine<true /*Schur*/,false /*dense Chol*/,RBA_ENGINE>
00215     {
00216         typedef typename RBA_ENGINE::hessian_traits_t hessian_traits_t;
00217 
00218         static const size_t POSE_DIMS = RBA_ENGINE::kf2kf_pose_t::REL_POSE_DIMS;
00219         static const size_t LM_DIMS   = RBA_ENGINE::landmark_t::LM_DIMS;
00220 
00221         const int m_verbose_level;
00222         mrpt::utils::CTimeLogger &m_profiler;
00223 
00224         const size_t   nUnknowns_k2k, nUnknowns_k2f;
00225         Eigen::VectorXd  delta_eps;
00226         typename hessian_traits_t::TSparseBlocksHessian_Ap  &HAp;
00227         typename hessian_traits_t::TSparseBlocksHessian_f   &Hf;
00228         typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf;
00229         Eigen::VectorXd  &minus_grad;
00230 
00231         mrpt::math::CSparseMatrix* sS; 
00232         bool           sS_is_valid; 
00233 
00234         SparseCholeskyDecompPtr  ptrCh;
00235 
00236         SchurComplement<
00237             typename hessian_traits_t::TSparseBlocksHessian_Ap,
00238             typename hessian_traits_t::TSparseBlocksHessian_f,
00239             typename hessian_traits_t::TSparseBlocksHessian_Apf
00240             >
00241             schur_compl;
00242 
00244         solver_engine(
00245             const int verbose_level,
00246             mrpt::utils::CTimeLogger & profiler,
00247             typename hessian_traits_t::TSparseBlocksHessian_Ap  &HAp_,
00248             typename hessian_traits_t::TSparseBlocksHessian_f   &Hf_,
00249             typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_,
00250             Eigen::VectorXd  &minus_grad_,
00251             const size_t nUnknowns_k2k_,
00252             const size_t nUnknowns_k2f_) :
00253                 m_verbose_level(verbose_level),
00254                 m_profiler(profiler),
00255                 nUnknowns_k2k(nUnknowns_k2k_),
00256                 nUnknowns_k2f(nUnknowns_k2f_),
00257                 HAp(HAp_),Hf(Hf_),HApf(HApf_),
00258                 minus_grad(minus_grad_),
00259                 sS(NULL), sS_is_valid(false),
00260                 schur_compl(
00261                     HAp_,Hf_,HApf_, // The different symbolic/numeric Hessians
00262                     &minus_grad[0],  // minus gradient of the Ap part
00263                     // Handle case of no unknown features:
00264                     nUnknowns_k2f!=0 ? &minus_grad[POSE_DIMS*nUnknowns_k2k] : NULL   // minus gradient of the features part
00265                     )
00266         {
00267         }
00268 
00269         ~solver_engine()
00270         {
00271             if (sS) { delete sS; sS=NULL; }
00272         }
00273 
00274         // ----------------------------------------------------------------------
00275         // Solve the H*Ax = -g system using the Schur complement to generate a
00276         //   Ap-only reduced system.
00277         // Return: always true (success).
00278         // ----------------------------------------------------------------------
00279         bool solve(const double lambda)
00280         {
00281             // 1st: Numeric part: Update HAp hessian into the reduced system
00282             // Note: We have to re-evaluate the entire reduced Hessian HAp even if
00283             //       only lambda changed, because of the terms inv(Hf+\lambda*I).
00284 
00285             DETAILED_PROFILING_ENTER("opt.schur_build_reduced")
00286             schur_compl.numeric_build_reduced_system(lambda);
00287             DETAILED_PROFILING_LEAVE("opt.schur_build_reduced")
00288 
00289             if (schur_compl.getNumFeaturesFullRank()!=schur_compl.getNumFeatures())
00290             {
00291                 VERBOSE_LEVEL_COLOR(1,mrpt::system::CONCOL_RED) << "[OPT] Schur warning: only " << schur_compl.getNumFeaturesFullRank() << " out of " << schur_compl.getNumFeatures() << " features have full-rank.\n";
00292                 VERBOSE_LEVEL_COLOR_POST();
00293             }
00294 
00295             // Only the H_Ap part of the Hessian:
00296             if (!sS) sS = new mrpt::math::CSparseMatrix(nUnknowns_k2k*POSE_DIMS,nUnknowns_k2k*POSE_DIMS);
00297             else     sS->clear(nUnknowns_k2k*POSE_DIMS,nUnknowns_k2k*POSE_DIMS);
00298             sS_is_valid=false;
00299 
00300 
00301             // Now write the updated "HAp" into its sparse matrix form:
00302             DETAILED_PROFILING_ENTER("opt.SparseTripletFill")
00303             for (size_t i=0;i<nUnknowns_k2k;i++)
00304             {   // Only upper-half triangle:
00305                 const typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t & col_i = HAp.getCol(i);
00306 
00307                 for (typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t::const_iterator itRowEntry = col_i.begin();itRowEntry != col_i.end(); ++itRowEntry )
00308                 {
00309                     if (itRowEntry->first==i)
00310                     {
00311                         // block Diagonal: Add lambda*I to these ones
00312                         typename hessian_traits_t::TSparseBlocksHessian_Ap::matrix_t sSii = itRowEntry->second.num;
00313                         for (size_t k=0;k<POSE_DIMS;k++)
00314                             sSii.coeffRef(k,k)+=lambda;
00315                         sS->insert_submatrix(POSE_DIMS*i,POSE_DIMS*i, sSii );
00316                     }
00317                     else
00318                     {
00319                         sS->insert_submatrix(
00320                             POSE_DIMS*itRowEntry->first,  // row index
00321                             POSE_DIMS*i,                  // col index
00322                             itRowEntry->second.num );
00323                     }
00324                 }
00325             }
00326             DETAILED_PROFILING_LEAVE("opt.SparseTripletFill")
00327 
00328             // Compress the sparse matrix:
00329             // ----------------------------------
00330             DETAILED_PROFILING_ENTER("opt.SparseTripletCompress")
00331             sS->compressFromTriplet();
00332             DETAILED_PROFILING_LEAVE("opt.SparseTripletCompress")
00333 
00334             // Sparse cholesky:
00335             // ----------------------------------
00336             DETAILED_PROFILING_ENTER("opt.SparseChol")
00337             try
00338             {
00339                 if (!ptrCh.get())
00340                         ptrCh = SparseCholeskyDecompPtr(new mrpt::math::CSparseMatrix::CholeskyDecomp(*sS) );
00341                 else ptrCh.get()->update(*sS);
00342 
00343                 sS_is_valid=true;
00344 
00345                 DETAILED_PROFILING_LEAVE("opt.SparseChol")
00346             }
00347             catch (mrpt::math::CExceptionNotDefPos &)
00348             {
00349                 DETAILED_PROFILING_LEAVE("opt.SparseChol")
00350                 // not positive definite so increase lambda and try again
00351                 return false;
00352             }
00353 
00354             // backsubtitution gives us "DeltaEps" from Cholesky and "-grad":
00355             //
00356             //    (J^tJ + lambda*I) DeltaEps = -grad
00357             // ----------------------------------------------------------------
00358             DETAILED_PROFILING_ENTER("opt.backsub")
00359 
00360             delta_eps.assign(nUnknowns_k2k*POSE_DIMS + nUnknowns_k2f*LM_DIMS, 0); // Important: It's initialized to zeros!
00361 
00362             ptrCh->backsub(&minus_grad[0],&delta_eps[0],nUnknowns_k2k*POSE_DIMS);
00363 
00364             DETAILED_PROFILING_LEAVE("opt.backsub")
00365 
00366             // If using the Schur complement, at this point we must now solve the secondary
00367             //  system for features:
00368             // -----------------------------------------------------------------------------
00369             // 2nd numeric part: Solve for increments in features ----------
00370             DETAILED_PROFILING_ENTER("opt.schur_features")
00371 
00372             schur_compl.numeric_solve_for_features(
00373                 &delta_eps[0],
00374                 // Handle case of no unknown features:
00375                 nUnknowns_k2f!=0 ? &delta_eps[nUnknowns_k2k*POSE_DIMS] : NULL   // minus gradient of the features part
00376                 );
00377 
00378             DETAILED_PROFILING_LEAVE("opt.schur_features")
00379 
00380             return true;
00381         } // end solve()
00382 
00383 
00384         void realize_relinearized()
00385         {
00386             DETAILED_PROFILING_ENTER("opt.schur_realize_HAp_changed")
00387             // Update the starting value of HAp for Schur:
00388             schur_compl.realize_HAp_changed();
00389             DETAILED_PROFILING_LEAVE("opt.schur_realize_HAp_changed")
00390         }
00391         void realize_lambda_changed()
00392         {
00393             // Nothing to do.
00394         }
00395         bool was_ith_feature_invertible(const size_t i)
00396         {
00397             return schur_compl.was_ith_feature_invertible(i);
00398         }
00400         void get_extra_results(typename RBA_ENGINE::rba_options_t::solver_t::extra_results_t & out_info )
00401         {
00402             out_info.hessian_valid = sS_is_valid;
00403             if (sS) sS->swap(out_info.hessian);
00404         }
00405     };
00406 
00407     // ------------------------------------------------------------------------------------------
00409     template <class RBA_ENGINE>
00410     struct solver_engine<true /*Schur*/,true /*dense Chol*/,RBA_ENGINE>
00411     {
00412         typedef typename RBA_ENGINE::hessian_traits_t hessian_traits_t;
00413 
00414         static const size_t POSE_DIMS = RBA_ENGINE::kf2kf_pose_t::REL_POSE_DIMS;
00415         static const size_t LM_DIMS   = RBA_ENGINE::landmark_t::LM_DIMS;
00416 
00417         const int m_verbose_level;
00418         mrpt::utils::CTimeLogger &m_profiler;
00419         const size_t nUnknowns_k2k, nUnknowns_k2f;
00420 
00421         Eigen::VectorXd  delta_eps; 
00422         typename hessian_traits_t::TSparseBlocksHessian_Ap  &HAp;
00423         typename hessian_traits_t::TSparseBlocksHessian_f   &Hf;
00424         typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf;
00425         Eigen::VectorXd  &minus_grad;
00426 
00427         SchurComplement<
00428             typename hessian_traits_t::TSparseBlocksHessian_Ap,
00429             typename hessian_traits_t::TSparseBlocksHessian_f,
00430             typename hessian_traits_t::TSparseBlocksHessian_Apf
00431             >
00432             schur_compl;
00433 
00434 
00435         // Data for dense cholesky:
00436         Eigen::MatrixXd  denseH;
00437         Eigen::LLT<Eigen::MatrixXd,Eigen::Upper>  denseChol;
00438         bool  denseChol_is_uptodate;
00439         bool  hessian_is_valid; 
00440 
00441 
00443         solver_engine(
00444             const int verbose_level,
00445             mrpt::utils::CTimeLogger & profiler,
00446             typename hessian_traits_t::TSparseBlocksHessian_Ap  &HAp_,
00447             typename hessian_traits_t::TSparseBlocksHessian_f   &Hf_,
00448             typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_,
00449             Eigen::VectorXd  &minus_grad_,
00450             const size_t nUnknowns_k2k_,
00451             const size_t nUnknowns_k2f_) :
00452                 m_verbose_level(verbose_level),
00453                 m_profiler(profiler),
00454                 nUnknowns_k2k(nUnknowns_k2k_),
00455                 nUnknowns_k2f(nUnknowns_k2f_),
00456                 HAp(HAp_),Hf(Hf_),HApf(HApf_),
00457                 minus_grad(minus_grad_),
00458                 schur_compl(
00459                     HAp_,Hf_,HApf_, // The different symbolic/numeric Hessians
00460                     &minus_grad[0],  // minus gradient of the Ap part
00461                     // Handle case of no unknown features:
00462                     nUnknowns_k2f!=0 ? &minus_grad[POSE_DIMS*nUnknowns_k2k] : NULL   // minus gradient of the features part
00463                     ),
00464                 denseChol_is_uptodate (false),
00465                 hessian_is_valid (false)
00466         {
00467         }
00468 
00469         // ----------------------------------------------------------------------
00470         // Solve the H*Ax = -g system using the Schur complement to generate a
00471         //   Ap-only reduced system.
00472         // Return: always true (success).
00473         // ----------------------------------------------------------------------
00474         bool solve(const double lambda)
00475         {
00476             // 1st: Numeric part: Update HAp hessian into the reduced system
00477             // Note: We have to re-evaluate the entire reduced Hessian HAp even if
00478             //       only lambda changed, because of the terms inv(Hf+\lambda*I).
00479 
00480             DETAILED_PROFILING_ENTER("opt.schur_build_reduced")
00481             schur_compl.numeric_build_reduced_system(lambda);
00482             DETAILED_PROFILING_LEAVE("opt.schur_build_reduced")
00483 
00484             if (schur_compl.getNumFeaturesFullRank()!=schur_compl.getNumFeatures()) {
00485                 VERBOSE_LEVEL_COLOR(1,mrpt::system::CONCOL_RED) << "[OPT] Schur warning: only " << schur_compl.getNumFeaturesFullRank() << " out of " << schur_compl.getNumFeatures() << " features have full-rank.\n";
00486                 VERBOSE_LEVEL_COLOR_POST();
00487             }
00488 
00489             if (!denseChol_is_uptodate)
00490             {
00491                 // Use a dense Cholesky method for solving the set of unknowns:
00492                 denseH.setZero(nUnknowns_k2k*POSE_DIMS,nUnknowns_k2k*POSE_DIMS);  // Only for the H_Ap part of the Hessian
00493                 hessian_is_valid = false;
00494 
00495                 // Now write the updated "HAp" into its sparse matrix form:
00496                 DETAILED_PROFILING_ENTER("opt.DenseFill")
00497                 for (size_t i=0;i<nUnknowns_k2k;i++)
00498                 {   // Only upper-half triangle:
00499                     const typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t & col_i = HAp.getCol(i);
00500 
00501                     for (typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t::const_iterator itRowEntry = col_i.begin();itRowEntry != col_i.end(); ++itRowEntry )
00502                     {
00503                         if (itRowEntry->first==i)
00504                         {
00505                             // block Diagonal: Add lambda*I to these ones
00506                             typename hessian_traits_t::TSparseBlocksHessian_Ap::matrix_t sSii = itRowEntry->second.num;
00507                             for (size_t k=0;k<POSE_DIMS;k++)
00508                                 sSii.coeffRef(k,k)+=lambda;
00509                             denseH.block<POSE_DIMS,POSE_DIMS>(POSE_DIMS*i,POSE_DIMS*i) = sSii;
00510                         }
00511                         else
00512                         {
00513                             denseH.block<POSE_DIMS,POSE_DIMS>(
00514                                 POSE_DIMS*itRowEntry->first,  // row index
00515                                 POSE_DIMS*i)                   // col index
00516                                 = itRowEntry->second.num;
00517                         }
00518                     }
00519                 }
00520                 DETAILED_PROFILING_LEAVE("opt.DenseFill")
00521 
00522                 hessian_is_valid = true;
00523 
00524                 // Dense cholesky:
00525                 // ----------------------------------
00526                 DETAILED_PROFILING_ENTER("opt.DenseChol")
00527                 denseChol = denseH.selfadjointView<Eigen::Upper>().llt();
00528                 DETAILED_PROFILING_LEAVE("opt.DenseChol")
00529 
00530                 if (denseChol.info()!=Eigen::Success)
00531                 {
00532                     // not positive definite so increase lambda and try again
00533                     return false;
00534                 }
00535 
00536                 denseChol_is_uptodate = true;
00537             }
00538 
00539 
00540             // backsubtitution gives us "DeltaEps" from Cholesky and "-grad":
00541             //
00542             //    (J^tJ + lambda*I) DeltaEps = -grad
00543             // ----------------------------------------------------------------
00544             DETAILED_PROFILING_ENTER("opt.backsub")
00545 
00546             delta_eps.resize(nUnknowns_k2k*POSE_DIMS + nUnknowns_k2f*LM_DIMS );
00547             delta_eps.tail(nUnknowns_k2f*LM_DIMS).setZero();
00548 
00549             delta_eps.head(nUnknowns_k2k*POSE_DIMS) = denseChol.solve( minus_grad.head(nUnknowns_k2k*POSE_DIMS) );
00550 
00551             DETAILED_PROFILING_LEAVE("opt.backsub")
00552 
00553             // If using the Schur complement, at this point we must now solve the secondary
00554             //  system for features:
00555             // -----------------------------------------------------------------------------
00556             // 2nd numeric part: Solve for increments in features ----------
00557             DETAILED_PROFILING_ENTER("opt.schur_features")
00558 
00559             schur_compl.numeric_solve_for_features(
00560                 &delta_eps[0],
00561                 // Handle case of no unknown features:
00562                 nUnknowns_k2f!=0 ? &delta_eps[nUnknowns_k2k*POSE_DIMS] : NULL   // minus gradient of the features part
00563                 );
00564 
00565             DETAILED_PROFILING_LEAVE("opt.schur_features")
00566 
00567             return true;
00568         } // end solve()
00569 
00570         void realize_lambda_changed()
00571         {
00572             denseChol_is_uptodate = false;
00573         }
00574         void realize_relinearized()
00575         {
00576             DETAILED_PROFILING_ENTER("opt.schur_realize_HAp_changed")
00577             // Update the starting value of HAp for Schur:
00578             schur_compl.realize_HAp_changed();
00579             DETAILED_PROFILING_LEAVE("opt.schur_realize_HAp_changed")
00580         }
00581         bool was_ith_feature_invertible(const size_t i)
00582         {
00583             return schur_compl.was_ith_feature_invertible(i);
00584         }
00586         void get_extra_results(typename RBA_ENGINE::rba_options_t::solver_t::extra_results_t & out_info )
00587         {
00588             out_info.hessian_valid = hessian_is_valid;
00589             denseH.swap(out_info.hessian);
00590         }
00591     };
00592 
00593 } // end namespace "internal"
00594 
00595 } // End of namespaces
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends