/* * Abstract Nonlinear Least-Squares Solver Class * * nlls_solver.h * * Created on: Nov 5, 2012 * Author: cforster */ #ifndef LM_SOLVER_IMPL_HPP_ #define LM_SOLVER_IMPL_HPP_ #include template void vk::NLLSSolver::optimize(ModelType& model) { if(method_ == GaussNewton) optimizeGaussNewton(model); else if(method_ == LevenbergMarquardt) optimizeLevenbergMarquardt(model); } template void vk::NLLSSolver::optimizeGaussNewton(ModelType& model) { // Compute weight scale if(use_weights_) computeResiduals(model, false, true); // Save the old model to rollback in case of unsuccessful update ModelType old_model(model); // perform iterative estimation for (iter_ = 0; iter_::Identity(D,D); Jres_.setZero(); // compute initial error n_meas_ = 0; computeResiduals(model, true, false); // add damping term: H_ += (H_.diagonal()*mu_).asDiagonal(); // add prior if(have_prior_) applyPrior(model); // solve the linear system if(solve()) { // update the model update(model, new_model); // compute error with new model and compare to old error n_meas_ = 0; new_chi2 = computeResiduals(new_model, false, false); rho_ = chi2_-new_chi2; } else { // matrix was singular and could not be computed cout << "Matrix is close to singular!" << endl; cout << "H = " << H_ << endl; cout << "Jres = " << Jres_ << endl; rho_ = -1; } if(rho_>0) { // update decrased the error -> success model = new_model; chi2_ = new_chi2; stop_ = vk::norm_max(x_)<=eps_; mu_ *= max(1./3., min(1.-pow(2*rho_-1,3), 2./3.)); nu_ = 2.; if(verbose_) { cout << "It. " << iter_ << "\t Trial " << n_trials_ << "\t Success" << "\t n_meas = " << n_meas_ << "\t new_chi2 = " << new_chi2 << "\t mu = " << mu_ << "\t nu = " << nu_ << endl; } } else { // update increased the error -> fail mu_ *= nu_; nu_ *= 2.; ++n_trials_; if (n_trials_ >= n_trials_max_) stop_ = true; if(verbose_) { cout << "It. " << iter_ << "\t Trial " << n_trials_ << "\t Failure" << "\t n_meas = " << n_meas_ << "\t new_chi2 = " << new_chi2 << "\t mu = " << mu_ << "\t nu = " << nu_ << endl; } } finishTrial(); } while(!(rho_>0 || stop_)); if (stop_) break; finishIteration(); } } template void vk::NLLSSolver::setRobustCostFunction( ScaleEstimatorType scale_estimator, WeightFunctionType weight_function) { switch(scale_estimator) { case TDistScale: if(verbose_) printf("Using TDistribution Scale Estimator\n"); scale_estimator_.reset(new robust_cost::TDistributionScaleEstimator()); use_weights_=true; break; case MADScale: if(verbose_) printf("Using MAD Scale Estimator\n"); scale_estimator_.reset(new robust_cost::MADScaleEstimator()); use_weights_=true; break; case NormalScale: if(verbose_) printf("Using Normal Scale Estimator\n"); scale_estimator_.reset(new robust_cost::NormalDistributionScaleEstimator()); use_weights_=true; break; default: if(verbose_) printf("Using Unit Scale Estimator\n"); scale_estimator_.reset(new robust_cost::UnitScaleEstimator()); use_weights_=false; } switch(weight_function) { case TDistWeight: if(verbose_) printf("Using TDistribution Weight Function\n"); weight_function_.reset(new robust_cost::TDistributionWeightFunction()); break; case TukeyWeight: if(verbose_) printf("Using Tukey Weight Function\n"); weight_function_.reset(new robust_cost::TukeyWeightFunction()); break; case HuberWeight: if(verbose_) printf("Using Huber Weight Function\n"); weight_function_.reset(new robust_cost::HuberWeightFunction()); break; default: if(verbose_) printf("Using Unit Weight Function\n"); weight_function_.reset(new robust_cost::UnitWeightFunction()); } } template void vk::NLLSSolver::setPrior( const T& prior, const Matrix& Information) { have_prior_ = true; prior_ = prior; I_prior_ = Information; } template void vk::NLLSSolver::reset() { have_prior_ = false; chi2_ = 1e10; mu_ = mu_init_; nu_ = nu_init_; n_meas_ = 0; n_iter_ = n_iter_init_; iter_ = 0; stop_ = false; } template inline const double& vk::NLLSSolver::getChi2() const { return chi2_; } template inline const vk::Matrix& vk::NLLSSolver::getInformationMatrix() const { return H_; } #endif /* LM_SOLVER_IMPL_HPP_ */