15 namespace mrpt {
namespace srba {
31 template <
class RBA_ENGINE>
36 static const size_t POSE_DIMS = RBA_ENGINE::kf2kf_pose_type::REL_POSE_DIMS;
37 static const size_t LM_DIMS = RBA_ENGINE::lm_type::LM_DIMS;
42 typename hessian_traits_t::TSparseBlocksHessian_Ap &
HAp;
43 typename hessian_traits_t::TSparseBlocksHessian_f &
Hf;
44 typename hessian_traits_t::TSparseBlocksHessian_Apf &
HApf;
55 const int verbose_level,
57 typename hessian_traits_t::TSparseBlocksHessian_Ap &HAp_,
58 typename hessian_traits_t::TSparseBlocksHessian_f &Hf_,
59 typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_,
60 Eigen::VectorXd &minus_grad_,
61 const size_t nUnknowns_k2k_,
62 const size_t nUnknowns_k2f_) :
63 m_verbose_level(verbose_level),
65 HAp(HAp_), Hf(Hf_), HApf(HApf_),
66 minus_grad(minus_grad_),
67 nUnknowns_k2k(nUnknowns_k2k_),
68 nUnknowns_k2f(nUnknowns_k2f_),
69 nUnknowns_scalars( POSE_DIMS*nUnknowns_k2k + LM_DIMS*nUnknowns_k2f ),
70 idx_start_f(POSE_DIMS*nUnknowns_k2k),
71 sS(NULL), sS_is_valid(false)
77 if (sS) {
delete sS; sS=NULL; }
88 if (!sS) sS =
new CSparseMatrix(nUnknowns_scalars,nUnknowns_scalars);
89 else sS->
clear(nUnknowns_scalars,nUnknowns_scalars);
93 for (
size_t i=0;i<nUnknowns_k2k;i++)
95 const typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t & col_i = HAp.getCol(i);
99 if (itRowEntry->first==i)
102 typename hessian_traits_t::TSparseBlocksHessian_Ap::matrix_t sSii = itRowEntry->second.num;
103 for (
size_t k=0;k<POSE_DIMS;k++)
104 sSii.coeffRef(k,k)+=lambda;
110 POSE_DIMS*itRowEntry->first,
112 itRowEntry->second.num );
118 for (
size_t i=0;i<nUnknowns_k2k;i++)
120 const typename hessian_traits_t::TSparseBlocksHessian_Apf::col_t & row_i = HApf.getCol(i);
126 idx_start_f+LM_DIMS*itColEntry->first,
127 itColEntry->second.num );
132 for (
size_t i=0;i<nUnknowns_k2f;i++)
134 const typename hessian_traits_t::TSparseBlocksHessian_f::col_t & col_i = Hf.getCol(i);
138 if (itRowEntry->first==i)
141 typename hessian_traits_t::TSparseBlocksHessian_f::matrix_t sSii = itRowEntry->second.num;
142 for (
size_t k=0;k<LM_DIMS;k++)
143 sSii.coeffRef(k,k)+=lambda;
149 idx_start_f+LM_DIMS*itRowEntry->first,
150 idx_start_f+LM_DIMS*i,
151 itRowEntry->second.num );
170 else ptrCh.get()->update(*sS);
187 ptrCh->backsub(minus_grad,delta_eps);
208 void get_extra_results(
typename RBA_ENGINE::rba_options_type::solver_t::extra_results_t & out_info )
210 out_info.hessian_valid = sS_is_valid;
211 if (sS) sS->
swap(out_info.hessian);
217 template <
class RBA_ENGINE>
222 static const size_t POSE_DIMS = RBA_ENGINE::kf2kf_pose_type::REL_POSE_DIMS;
223 static const size_t LM_DIMS = RBA_ENGINE::lm_type::LM_DIMS;
230 typename hessian_traits_t::TSparseBlocksHessian_Ap &
HAp;
231 typename hessian_traits_t::TSparseBlocksHessian_f &
Hf;
232 typename hessian_traits_t::TSparseBlocksHessian_Apf &
HApf;
241 typename hessian_traits_t::TSparseBlocksHessian_Ap,
242 typename hessian_traits_t::TSparseBlocksHessian_f,
243 typename hessian_traits_t::TSparseBlocksHessian_Apf
249 const int verbose_level,
251 typename hessian_traits_t::TSparseBlocksHessian_Ap &HAp_,
252 typename hessian_traits_t::TSparseBlocksHessian_f &Hf_,
253 typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_,
254 Eigen::VectorXd &minus_grad_,
255 const size_t nUnknowns_k2k_,
256 const size_t nUnknowns_k2f_) :
257 m_verbose_level(verbose_level),
258 m_profiler(profiler),
259 nUnknowns_k2k(nUnknowns_k2k_),
260 nUnknowns_k2f(nUnknowns_k2f_),
261 HAp(HAp_),Hf(Hf_),HApf(HApf_),
262 minus_grad(minus_grad_),
263 sS(NULL), sS_is_valid(false),
268 nUnknowns_k2f!=0 ? &minus_grad[POSE_DIMS*nUnknowns_k2k] : NULL
275 if (sS) {
delete sS; sS=NULL; }
290 schur_compl.numeric_build_reduced_system(lambda);
293 if (schur_compl.getNumFeaturesFullRank()!=schur_compl.getNumFeatures())
294 VERBOSE_LEVEL(1) <<
"[OPT] Schur warning: only " << schur_compl.getNumFeaturesFullRank() <<
" out of " << schur_compl.getNumFeatures() <<
" features have full-rank.\n";
297 if (!sS) sS =
new CSparseMatrix(nUnknowns_k2k*POSE_DIMS,nUnknowns_k2k*POSE_DIMS);
298 else sS->
clear(nUnknowns_k2k*POSE_DIMS,nUnknowns_k2k*POSE_DIMS);
304 for (
size_t i=0;i<nUnknowns_k2k;i++)
306 const typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t & col_i = HAp.getCol(i);
310 if (itRowEntry->first==i)
313 typename hessian_traits_t::TSparseBlocksHessian_Ap::matrix_t sSii = itRowEntry->second.num;
314 for (
size_t k=0;k<POSE_DIMS;k++)
315 sSii.coeffRef(k,k)+=lambda;
321 POSE_DIMS*itRowEntry->first,
323 itRowEntry->second.num );
342 else ptrCh.get()->update(*sS);
361 delta_eps.assign(nUnknowns_k2k*POSE_DIMS + nUnknowns_k2f*LM_DIMS, 0);
363 ptrCh->backsub(&minus_grad[0],&delta_eps[0],nUnknowns_k2k*POSE_DIMS);
373 schur_compl.numeric_solve_for_features(
376 nUnknowns_k2f!=0 ? &delta_eps[nUnknowns_k2k*POSE_DIMS] : NULL
389 schur_compl.realize_HAp_changed();
398 return schur_compl.was_ith_feature_invertible(i);
401 void get_extra_results(
typename RBA_ENGINE::rba_options_type::solver_t::extra_results_t & out_info )
403 out_info.hessian_valid = sS_is_valid;
404 if (sS) sS->
swap(out_info.hessian);
410 template <
class RBA_ENGINE>
415 static const size_t POSE_DIMS = RBA_ENGINE::kf2kf_pose_type::REL_POSE_DIMS;
416 static const size_t LM_DIMS = RBA_ENGINE::lm_type::LM_DIMS;
423 typename hessian_traits_t::TSparseBlocksHessian_Ap &
HAp;
424 typename hessian_traits_t::TSparseBlocksHessian_f &
Hf;
425 typename hessian_traits_t::TSparseBlocksHessian_Apf &
HApf;
429 typename hessian_traits_t::TSparseBlocksHessian_Ap,
430 typename hessian_traits_t::TSparseBlocksHessian_f,
431 typename hessian_traits_t::TSparseBlocksHessian_Apf
445 const int verbose_level,
447 typename hessian_traits_t::TSparseBlocksHessian_Ap &HAp_,
448 typename hessian_traits_t::TSparseBlocksHessian_f &Hf_,
449 typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_,
450 Eigen::VectorXd &minus_grad_,
451 const size_t nUnknowns_k2k_,
452 const size_t nUnknowns_k2f_) :
453 m_verbose_level(verbose_level),
454 m_profiler(profiler),
455 nUnknowns_k2k(nUnknowns_k2k_),
456 nUnknowns_k2f(nUnknowns_k2f_),
457 HAp(HAp_),Hf(Hf_),HApf(HApf_),
458 minus_grad(minus_grad_),
463 nUnknowns_k2f!=0 ? &minus_grad[POSE_DIMS*nUnknowns_k2k] : NULL
465 denseChol_is_uptodate (false),
466 hessian_is_valid (false)
482 schur_compl.numeric_build_reduced_system(lambda);
485 if (schur_compl.getNumFeaturesFullRank()!=schur_compl.getNumFeatures())
486 VERBOSE_LEVEL(1) <<
"[OPT] Schur warning: only " << schur_compl.getNumFeaturesFullRank() <<
" out of " << schur_compl.getNumFeatures() <<
" features have full-rank.\n";
488 if (!denseChol_is_uptodate)
491 denseH.setZero(nUnknowns_k2k*POSE_DIMS,nUnknowns_k2k*POSE_DIMS);
492 hessian_is_valid =
false;
496 for (
size_t i=0;i<nUnknowns_k2k;i++)
498 const typename hessian_traits_t::TSparseBlocksHessian_Ap::col_t & col_i = HAp.getCol(i);
502 if (itRowEntry->first==i)
505 typename hessian_traits_t::TSparseBlocksHessian_Ap::matrix_t sSii = itRowEntry->second.num;
506 for (
size_t k=0;k<POSE_DIMS;k++)
507 sSii.coeffRef(k,k)+=lambda;
508 denseH.block<POSE_DIMS,POSE_DIMS>(POSE_DIMS*i,POSE_DIMS*i) = sSii;
512 denseH.block<POSE_DIMS,POSE_DIMS>(
513 POSE_DIMS*itRowEntry->first,
515 = itRowEntry->second.num;
521 hessian_is_valid =
true;
526 denseChol = denseH.selfadjointView<Eigen::Upper>().llt();
529 if (denseChol.info()!=Eigen::Success)
535 denseChol_is_uptodate =
true;
545 delta_eps.resize(nUnknowns_k2k*POSE_DIMS + nUnknowns_k2f*LM_DIMS );
546 delta_eps.tail(nUnknowns_k2f*LM_DIMS).setZero();
548 delta_eps.head(nUnknowns_k2k*POSE_DIMS) = denseChol.solve( minus_grad.head(nUnknowns_k2k*POSE_DIMS) );
558 schur_compl.numeric_solve_for_features(
561 nUnknowns_k2f!=0 ? &delta_eps[nUnknowns_k2k*POSE_DIMS] : NULL
571 denseChol_is_uptodate =
false;
577 schur_compl.realize_HAp_changed();
582 return schur_compl.was_ith_feature_invertible(i);
585 void get_extra_results(
typename RBA_ENGINE::rba_options_type::solver_t::extra_results_t & out_info )
587 out_info.hessian_valid = hessian_is_valid;
588 denseH.swap(out_info.hessian);
const size_t nUnknowns_scalars
hessian_traits_t::TSparseBlocksHessian_Apf & HApf
void realize_lambda_changed()
Eigen::VectorXd delta_eps
The result of solving Ax=b will be stored here.
#define DETAILED_PROFILING_ENTER(_STR)
void realize_relinearized()
RBA_ENGINE::hessian_traits_t hessian_traits_t
bool was_ith_feature_invertible(const size_t i)
bool solve(const double lambda)
Auxiliary class to hold the results of a Cholesky factorization of a sparse matrix.
A sparse matrix structure, wrapping T.
bool was_ith_feature_invertible(const size_t i)
const Scalar * const_iterator
bool sS_is_valid
Whether the Hessian was filled in, in sS.
void realize_relinearized()
bool hessian_is_valid
Whether the hessian was correctly evaluated at least once.
void swap(CSparseMatrix &other)
Fast swap contents with another sparse matrix.
hessian_traits_t::TSparseBlocksHessian_Apf & HApf
void get_extra_results(typename RBA_ENGINE::rba_options_type::solver_t::extra_results_t &out_info)
Here, out_info is of type mrpt::srba::options::solver_LM_schur_sparse_cholesky::extra_results_t.
void clear(const size_t nRows=1, const size_t nCols=1)
Erase all previous contents and leave the matrix as a "triplet" ROWS x COLS matrix without any nonzer...
Used in mrpt::math::CSparseMatrix.
void realize_lambda_changed()
const size_t nUnknowns_k2k
This base provides a set of functions for maths stuff.
solver_engine(const int verbose_level, mrpt::utils::CTimeLogger &profiler, typename hessian_traits_t::TSparseBlocksHessian_Ap &HAp_, typename hessian_traits_t::TSparseBlocksHessian_f &Hf_, typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_, Eigen::VectorXd &minus_grad_, const size_t nUnknowns_k2k_, const size_t nUnknowns_k2f_)
Constructor.
bool sS_is_valid
Whether the Hessian was filled in, in sS.
RBA_ENGINE::hessian_traits_t hessian_traits_t
std::auto_ptr< CSparseMatrix::CholeskyDecomp > SparseCholeskyDecompPtr
hessian_traits_t::TSparseBlocksHessian_f & Hf
void compressFromTriplet()
ONLY for TRIPLET matrices: convert the matrix in a column-compressed form.
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
Eigen::VectorXd & minus_grad
void get_extra_results(typename RBA_ENGINE::rba_options_type::solver_t::extra_results_t &out_info)
Here, out_info is of type mrpt::srba::options::solver_LM_no_schur_sparse_cholesky::extra_results_t.
SparseCholeskyDecompPtr ptrCh
Cholesky object, as a pointer to reuse it between iterations.
void realize_relinearized()
const int m_verbose_level
Eigen::VectorXd & minus_grad
const int m_verbose_level
SchurComplement< typename hessian_traits_t::TSparseBlocksHessian_Ap, typename hessian_traits_t::TSparseBlocksHessian_f, typename hessian_traits_t::TSparseBlocksHessian_Apf > schur_compl
bool solve(const double lambda)
#define DETAILED_PROFILING_LEAVE(_STR)
bool was_ith_feature_invertible(const size_t i)
void get_extra_results(typename RBA_ENGINE::rba_options_type::solver_t::extra_results_t &out_info)
Here, out_info is of type mrpt::srba::options::solver_LM_schur_dense_cholesky::extra_results_t.
bool solve(const double lambda)
const size_t nUnknowns_k2k
Eigen::VectorXd & minus_grad
mrpt::utils::CTimeLogger & m_profiler
mrpt::utils::CTimeLogger & m_profiler
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
mrpt::utils::CTimeLogger & m_profiler
Generic solver declaration.
hessian_traits_t::TSparseBlocksHessian_Apf & HApf
CSparseMatrix * sS
Sparse Hessian.
hessian_traits_t::TSparseBlocksHessian_f & Hf
SchurComplement< typename hessian_traits_t::TSparseBlocksHessian_Ap, typename hessian_traits_t::TSparseBlocksHessian_f, typename hessian_traits_t::TSparseBlocksHessian_Apf > schur_compl
#define VERBOSE_LEVEL(_LEVEL)
void insert_submatrix(const size_t row, const size_t col, const MATRIX &M)
ONLY for TRIPLET matrices: insert a given matrix (in any of the MRPT formats) at a given location of ...
A generic symbolic and numeric Schur-complement handler for builing reduced systems of equations...
bool denseChol_is_uptodate
A versatile "profiler" that logs the time spent within each pair of calls to enter(X)-leave(X), among other stats.
SparseCholeskyDecompPtr ptrCh
Cholesky object, as a pointer to reuse it between iterations.
solver_engine(const int verbose_level, mrpt::utils::CTimeLogger &profiler, typename hessian_traits_t::TSparseBlocksHessian_Ap &HAp_, typename hessian_traits_t::TSparseBlocksHessian_f &Hf_, typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_, Eigen::VectorXd &minus_grad_, const size_t nUnknowns_k2k_, const size_t nUnknowns_k2f_)
Constructor.
solver_engine(const int verbose_level, mrpt::utils::CTimeLogger &profiler, typename hessian_traits_t::TSparseBlocksHessian_Ap &HAp_, typename hessian_traits_t::TSparseBlocksHessian_f &Hf_, typename hessian_traits_t::TSparseBlocksHessian_Apf &HApf_, Eigen::VectorXd &minus_grad_, const size_t nUnknowns_k2k_, const size_t nUnknowns_k2f_)
Constructor.
CSparseMatrix * sS
Sparse Hessian.
Eigen::VectorXd delta_eps
void realize_lambda_changed()
hessian_traits_t::TSparseBlocksHessian_Ap & HAp
Eigen::LLT< Eigen::MatrixXd, Eigen::Upper > denseChol
hessian_traits_t::TSparseBlocksHessian_Ap & HAp
RBA_ENGINE::hessian_traits_t hessian_traits_t
Eigen::VectorXd delta_eps
The result of solving Ax=b will be stored here.
const int m_verbose_level
hessian_traits_t::TSparseBlocksHessian_f & Hf
hessian_traits_t::TSparseBlocksHessian_Ap & HAp