10 using namespace Eigen;
13 #define MAP_BRM_ERM( BMatrix ) Map< const Matrix<double, Dynamic, Dynamic, RowMajor> >(BMatrix.data(), BMatrix.rows(), BMatrix.cols()) 14 #define MAP_BV_ECV( BVector ) Map< const VectorXd >(BVector.data(), BVector.size()) 15 #define MAP_ECV_BV( EVector ) blitz::Array<double, 1>(EVector.data(), shape(EVector.size()), neverDeleteData) 28 void givens(
double val1,
double val2,
double &c,
double &
s)
36 if (fabs(val2) > fabs(val1)) {
37 tempDbl = -val1 / val2;
38 s = 1.0 /
sqrt(1.0 + tempDbl * tempDbl);
41 tempDbl = -val2 / val1;
42 c = 1.0 /
sqrt(1.0 + tempDbl * tempDbl);
52 double g_tol_abs,
double g_tol_rel,
bool vrbs )
53 :
NLLSSolver(p, max_cost_function_calls, vrbs),
55 Dx_tol_abs(dx_tol_abs), Dx_tol_rel(dx_tol_rel),
56 G_tol_abs(g_tol_abs), G_tol_rel(g_tol_rel),
57 CR_ratio(0), Lambda(0)
64 const VectorXd& dx,
const VectorXd& x,
double dx_tol_rel )
68 for(VectorXd::Index i=0; i<dx.size(); i++)
69 if( abs(dx(i)) >= dx_tol_rel*(dx_tol_rel + abs(x(i))) )
78 const VectorXd& dx,
double dx_tol_abs )
87 const Eigen::VectorXd& dx,
const Eigen::VectorXd& x,
double dx_tol_rel,
double dx_tol_abs )
97 if( (dx_tol_abs>0) && (dx_tol_rel>0) )
101 else if(dx_tol_abs>0)
109 const VectorXd&
g,
const VectorXd& x,
double cost,
double g_tol_rel )
111 return (g.cwiseProduct( x.cwiseAbs().cwiseMax(1.0) ).lpNorm<Infinity>() < abs(g_tol_rel*
max(cost,1.0)))
118 const VectorXd&
g,
double g_tol_abs )
229 std::ios oldState(
nullptr);
230 oldState.copyfmt(ostr);
233 <<
"; (|f(x)|^2)/2 = " <<
P->cost() <<
"; status = " <<
status_str() << endl;
235 (void) ostr.precision(15);
237 ostr <<
"Where the point x is" << endl << fixed << setw(25) <<
P->parameters() << endl;
238 ostr <<
"The gradient g(x) is" << endl << fixed << setw(25) <<
P->gradient() << endl << endl;
240 ostr.copyfmt(oldState);
254 ColPivHouseholderQR< Matrix<double, Dynamic, Dynamic, RowMajor> > j_QR(
MAP_BRM_ERM(
P->jacobian()) );
258 uint32_t n =
P->expected_parameter_size();
259 uint32_t r = j_QR.rank();
273 double res_norm_sqrd =
MAP_BV_ECV(
P->residual()).squaredNorm();
274 VectorXd QTResidual = j_QR.householderQ().transpose() *
MAP_BV_ECV(
P->residual());
275 VectorXd perm_W = j_QR.colsPermutation().transpose()*
W;
276 MatrixXd Rrn = j_QR.matrixR().topRows(r).template triangularView<Upper>();
277 MatrixXd TRrn = Rrn*perm_W.cwiseInverse().asDiagonal();
289 VectorXd scaled_step;
290 double scaled_step_norm;
293 scaled_step =
W.cwiseProduct(step);
294 scaled_step_norm = scaled_step.stableNorm();
296 HouseholderQR<MatrixXd> TRrnT_QR(TRrn.transpose());
297 MatrixXd TrrT( TRrnT_QR.matrixQR().topRows(r).template triangularView<Upper>() );
298 VectorXd y = TrrT.transpose().triangularView<Lower>().
solve(-QTResidual.head(r));
299 scaled_step_norm = y.stableNorm();
300 VectorXd y_augmented(n);
301 y_augmented << y, VectorXd::Zero(n-r);
302 scaled_step = j_QR.colsPermutation()*(TRrnT_QR.householderQ()*y_augmented);
303 step =
W.cwiseInverse().cwiseProduct(scaled_step);
312 bool cost_reducing_step=
true;
325 double upper = (TRrn.transpose()*QTResidual.head(r)).stableNorm()/
Opt.
tr_rad;
332 double phi_0 = scaled_step_norm-
Opt.
tr_rad;
333 VectorXd temp =j_QR.colsPermutation().transpose()*(
W.asDiagonal()*scaled_step/scaled_step_norm);
334 VectorXd z = Rrn.transpose().triangularView<Lower>().
solve(temp);
335 double phi_prime_0 = -scaled_step_norm * z.squaredNorm();
336 lower = -phi_0/phi_prime_0;
338 if( !cost_reducing_step )
342 assert( (0 <= lower) && (lower < upper) );
344 bool step_in_trust_region_found=
false;
357 VectorXd QTRes_head = QTResidual.head(n);
358 VectorXd QTRes_extra = VectorXd::Zero(n);
359 MatrixXd Rnn = MatrixXd::Zero(n,n);
360 Rnn.topRows(r) = Rrn;
361 MatrixXd diag = (
sqrt(
Lambda)*(j_QR.colsPermutation().transpose()*
W)).asDiagonal();
362 for(uint32_t i=0; i<n; i++) {
365 for(uint32_t j=i; j>0; j--) {
366 givens( diag(j-1,i), diag(j,i), cs, sn);
368 RowVectorXd tempv = diag.block(j-1,i,1,n-i);
369 diag.block(j-1,i,1,n-i) = cs*tempv - sn*diag.block(j,i,1,n-i);
370 diag.block(j,i,1,n-i) = sn*tempv + cs*diag.block(j,i,1,n-i);
372 double temps = QTRes_extra[j-1];
373 QTRes_extra[j-1] = cs*temps - sn*QTRes_extra[j];
374 QTRes_extra[j] = sn*temps + cs*QTRes_extra[j];
377 givens( Rnn(i,i), diag(0,i), cs, sn );
379 RowVectorXd tempv = Rnn.block(i,i,1,n-i);
380 Rnn.block(i,i,1,n-i) = cs*tempv - sn*diag.block(0,i,1,n-i);
381 diag.block(0,i,1,n-i) = sn*tempv + cs*diag.block(0,i,1,n-i);
383 double temps = QTRes_head[i];
384 QTRes_head[i] = cs*temps - sn*QTRes_extra[0];
385 QTRes_extra[0] = sn*temps + cs*QTRes_extra[0];
387 VectorXd y = Rnn.triangularView<Upper>().
solve(-QTRes_head);
388 step = j_QR.colsPermutation()*y;
393 scaled_step =
W.cwiseProduct(step);
394 scaled_step_norm = scaled_step.stableNorm();
399 step_in_trust_region_found =
406 if(!step_in_trust_region_found) {
407 double phi = scaled_step_norm-
Opt.
tr_rad;
408 VectorXd temp =j_QR.colsPermutation().transpose()*(
W.asDiagonal()*scaled_step/scaled_step_norm);
409 VectorXd z = Rnn.transpose().triangularView<Lower>().
solve(temp);
410 double phi_prime = -scaled_step_norm * z.squaredNorm();
419 lower =
max(lower, (
Lambda-phi/phi_prime));
426 }
while(!step_in_trust_region_found);
430 double jacob_step_norm_sqrd =
431 (Rrn.triangularView<Upper>()*(j_QR.colsPermutation().transpose()*step)).squaredNorm();
438 blitz::Array<double, 1> x =
P->parameters();
442 blitz::Array<double, 1> x_next(x+
MAP_ECV_BV(step));
443 P->parameters( blitz::Array<double,1>(x_next));
444 double next_res_norm_sqrd =
MAP_BV_ECV(
P->residual()).squaredNorm();
460 if( (next_res_norm_sqrd >= res_norm_sqrd) || (scaled_step_norm <= 0) ) {
463 CR_ratio = (1.0 - next_res_norm_sqrd/res_norm_sqrd) /
464 ( (jacob_step_norm_sqrd/res_norm_sqrd)
465 + (2.0*
Lambda*scaled_step_norm*scaled_step_norm/res_norm_sqrd) );
472 if(!cost_reducing_step) {
484 W =
W.cwiseMax(
MAP_BRM_ERM(
P->jacobian()).colwise().stableNorm().transpose() );
511 double tr_scaling_factor = 1.0;
513 if(next_res_norm_sqrd <= res_norm_sqrd)
514 tr_scaling_factor = 0.5;
515 else if(next_res_norm_sqrd >= 100*res_norm_sqrd)
516 tr_scaling_factor = 0.1;
518 double temp = -( jacob_step_norm_sqrd/res_norm_sqrd
519 +
Lambda*scaled_step_norm*scaled_step_norm/res_norm_sqrd );
520 tr_scaling_factor = temp / (2.0*temp + 1.0 - next_res_norm_sqrd/res_norm_sqrd);
521 if(tr_scaling_factor < 0.1)
522 tr_scaling_factor = 0.1;
523 else if(tr_scaling_factor > 0.5)
524 tr_scaling_factor = 0.5;
528 tr_scaling_factor = 2.0;
529 Opt.
tr_rad = tr_scaling_factor*scaled_step_norm;
virtual const char *const status_str() const
Returns the string version of the solver status.
solve method called but an error was encountered
virtual void print_state(std::ostream &ostr=std::cout)
Prints solver state.
const Unit s("s", 1.0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0)
FullPhysics::DoubleWithUnit max(const FullPhysics::DoubleWithUnit &x, const FullPhysics::DoubleWithUnit &y)
virtual void solve()
The method that solves the optimization problem.
void record_cost_at_accepted_point(double cost)
Called to record the cost function value at an accepted point.
solve method called and a solution found
FullPhysics::AutoDerivative< double > sqrt(const FullPhysics::AutoDerivative< double > &x)
static status_t test_dx(const Eigen::VectorXd &dx, const Eigen::VectorXd &x, double dx_tol_rel, double dx_tol_abs)
The base class for the solvers of the Nonlinear-Least-Squares Problem.
static status_t test_dx_abs(const Eigen::VectorXd &dx, double dx_tol_abs)
double tr_rad
A positive number and the initial trust region radius.
solve method was called but stalled
status_t
Enum type for the status of the iterative solver.
#define MAP_BV_ECV(BVector)
void record_gradient_at_accepted_point(const blitz::Array< double, 1 > &gradient)
For recording the gradient of the cost function evaluated at an accepted point.
virtual status_t iterate()
virtual int num_accepted_steps() const
Returns the number of the accepted steps.
void givens(double val1, double val2, double &c, double &s)
static status_t test_grad_rel(const Eigen::VectorXd &g, const Eigen::VectorXd &x, double cost, double g_tol_rel)
static status_t test_dx_rel(const Eigen::VectorXd &dx, const Eigen::VectorXd &x, double dx_tol_rel)
Apply value function to a blitz array.
solve method called but did not converge to a solution
solve method not called yet
double tr_rad_tol
A positive number and a tolerance for comparing to the trust region radius.
virtual status_t status() const
Returns a value of IterativeSolver::status_t type.
double min_W
A positive number and the smallest value for the diagonal entries of the diagonal weight matrix...
There is an error in the problem.
void record_accepted_point(const blitz::Array< double, 1 > &point)
Called to record an accepted point.
#define MAP_ECV_BV(EVector)
#define MAP_BRM_ERM(BMatrix)
const Unit g("g", 1e-3 *kg)
Contains classes to abstract away details in various Spurr Radiative Transfer software.
boost::shared_ptr< NLLSProblem > P
static status_t test_grad_abs(const Eigen::VectorXd &g, double g_tol_abs)
NLLSSolverLM(const boost::shared_ptr< NLLSProblem > &p, int max_cost_function_calls, const NLLSSolverLM::Options &opt=NLLSSolverLM::Options(), double dx_tol_abs=0.000001, double dx_tol_rel=0.000001, double g_tol_abs=0.000001, double g_tol_rel=6.0555e-06, bool vrbs=false)
Constructor.
double cr_ratio_tol
A positive number and tolerance on the ratio of the actual to the predicted reduction of the value of...