#include "IpInexactDoglegNormal.hpp"
#include <cmath>
namespace Ipopt
{
#if IPOPT_VERBOSITY > 0
static const Index dbg_verbosity = 0;
#endif
InexactDoglegNormalStep::InexactDoglegNormalStep(
SmartPtr<InexactNewtonNormalStep> newton_step,
SmartPtr<InexactNormalTerminationTester> normal_tester
)
: InexactNormalStepCalculator(),
newton_step_(newton_step),
normal_tester_(normal_tester)
{ }
InexactDoglegNormalStep::~InexactDoglegNormalStep()
{ }
void InexactDoglegNormalStep::RegisterOptions(
SmartPtr<RegisteredOptions> reg_options
)
{
reg_options->AddLowerBoundedNumberOption(
"omega_init",
"Initial trust region factor for normal problem.",
0.0, true,
100.);
reg_options->AddLowerBoundedNumberOption(
"omega_max",
"Maximal trust region factor for normal problem.",
0.0, true,
1e20);
}
bool InexactDoglegNormalStep::InitializeImpl(
const OptionsList& options,
const std::string& prefix
)
{
options.GetNumericValue("omega_init", curr_omega_, prefix);
options.GetNumericValue("omega_max", omega_max_, prefix);
last_tr_inactive_ = true;
return newton_step_->Initialize(Jnlst(), IpNLP(), IpData(), IpCq(), options, prefix);
}
bool InexactDoglegNormalStep::ComputeNormalStep(
SmartPtr<Vector>& normal_x,
SmartPtr<Vector>& normal_s
)
{
DBG_START_METH("InexactDoglegNormalStep::ComputeNormalStep",
dbg_verbosity);
if( !last_tr_inactive_ && InexData().full_step_accepted() )
{
if( curr_omega_ >= omega_max_ )
{
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Trust region radius factor would be increased, but it is already at its upper limit %e.\n", curr_omega_);
IpData().Append_info_string("O");
}
else
{
Number omega_old = curr_omega_;
curr_omega_ = Min(omega_max_, 10. * curr_omega_);
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Increasing trust region factor from %e to %e\n.", omega_old,
curr_omega_);
IpData().Append_info_string("o");
}
}
last_tr_inactive_ = false;
if( IpCq().curr_primal_infeasibility(NORM_2) <= 1e-12 )
{
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: We are at a feasible point, the normal step is set to zero.\n");
normal_x = IpData().curr()->x()->MakeNew();
normal_s = IpData().curr()->s()->MakeNew();
normal_x->Set(0.);
normal_s->Set(0.);
last_tr_inactive_ = true;
return true;
}
SmartPtr<const Vector> curr_jac_cdT_times_curr_cdminuss = InexCq().curr_jac_cdT_times_curr_cdminuss();
SmartPtr<const Vector> curr_slack_scaled_d_minus_s = InexCq().curr_slack_scaled_d_minus_s();
DBG_PRINT_VECTOR(1, "curr_jac_cdT_times_curr_cdminuss", *curr_jac_cdT_times_curr_cdminuss);
DBG_PRINT_VECTOR(1, "curr_slack_scaled_d_minus_s", *curr_slack_scaled_d_minus_s);
Number v_ATc_norm = InexCq().curr_scaled_Ac_norm();
SmartPtr<const Vector> vec_AATc_c = IpCq().curr_jac_c_times_vec(*curr_jac_cdT_times_curr_cdminuss);
SmartPtr<Vector> vec_AATc_d = curr_slack_scaled_d_minus_s->MakeNewCopy();
vec_AATc_d->ElementWiseMultiply(*InexCq().curr_scaling_slacks());
DBG_PRINT_VECTOR(1, "curr_scaling_slacks", *InexCq().curr_scaling_slacks());
DBG_PRINT_VECTOR(1, "vec_AATc_d", *vec_AATc_d);
vec_AATc_d->AddOneVector(1., *IpCq().curr_jac_d_times_vec(*curr_jac_cdT_times_curr_cdminuss), 1.);
DBG_PRINT_VECTOR(1, "IpCq().curr_jac_d_times_vec(*curr_jac_cdT_times_curr_cdminuss)", *IpCq().curr_jac_d_times_vec(*curr_jac_cdT_times_curr_cdminuss));
DBG_PRINT_VECTOR(1, "vec_AATc_c", *vec_AATc_c);
DBG_PRINT_VECTOR(1, "vec_AATc_d", *vec_AATc_d);
Number AATc_norm = IpCq().CalcNormOfType(NORM_2, *vec_AATc_c, *vec_AATc_d);
Number alpha_cs = Min(curr_omega_, v_ATc_norm * v_ATc_norm / (AATc_norm * AATc_norm));
Jnlst().Printf(J_MOREDETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: Cauchy step size alpha_cs = %e\n", alpha_cs);
DBG_PRINT((1, "alpha_cs = %e v_ATc_norm = %e AATc_norm = %e\n", alpha_cs, v_ATc_norm, AATc_norm));
SmartPtr<Vector> v_cauchy_x = curr_jac_cdT_times_curr_cdminuss->MakeNewCopy();
SmartPtr<Vector> v_cauchy_s = curr_slack_scaled_d_minus_s->MakeNewCopy();
v_cauchy_x->Scal(-alpha_cs);
v_cauchy_s->Scal(alpha_cs);
if( Jnlst().ProduceOutput(J_MOREVECTOR, J_SOLVE_PD_SYSTEM) )
{
Jnlst().Printf(J_MOREVECTOR, J_SOLVE_PD_SYSTEM,
"Dogleg step: Cauchy step:\n");
v_cauchy_x->Print(Jnlst(), J_MOREVECTOR, J_SOLVE_PD_SYSTEM, "v_cauchy_x");
v_cauchy_s->Print(Jnlst(), J_MOREVECTOR, J_SOLVE_PD_SYSTEM, "v_cauchy_s");
}
SmartPtr<const Vector> curr_c = IpCq().curr_c();
SmartPtr<const Vector> curr_d_minus_s = IpCq().curr_d_minus_s();
SmartPtr<Vector> inf_c = curr_c->MakeNew();
SmartPtr<Vector> inf_d = curr_d_minus_s->MakeNew();
inf_c->AddTwoVectors(1., *curr_c, -alpha_cs, *vec_AATc_c, 0.);
inf_d->AddTwoVectors(1., *curr_d_minus_s, -alpha_cs, *vec_AATc_d, 0.);
Number c_Avc_norm_cauchy = IpCq().CalcNormOfType(NORM_2, *inf_c, *inf_d);
if( IsValid(normal_tester_) )
{
normal_tester_->Set_c_Avc_norm_cauchy(c_Avc_norm_cauchy);
}
Number objred_normal_cs = 0.5 * (IpCq().CalcNormOfType(NORM_2, *curr_c, *curr_d_minus_s) - c_Avc_norm_cauchy);
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg: Reduction of normal problem objective function by Cauchy step = %23.16e\n", objred_normal_cs);
if( alpha_cs == curr_omega_ )
{
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: Cauchy step already hits trust region.\n");
normal_x = v_cauchy_x;
normal_s = v_cauchy_s;
normal_s->ElementWiseMultiply(*InexCq().curr_scaling_slacks());
IpData().Append_info_string("Nc ");
return true;
}
SmartPtr<Vector> v_cauchy_x_bak = v_cauchy_x->MakeNewCopy();
SmartPtr<Vector> v_cauchy_s_bak = v_cauchy_s->MakeNewCopy();
SmartPtr<Vector> v_newton_x = v_cauchy_x->MakeNew();
SmartPtr<Vector> v_newton_s = v_cauchy_s->MakeNew();
bool retval = newton_step_->ComputeNewtonNormalStep(*v_newton_x, *v_newton_s);
if( !retval )
{
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: Newton step could not be calculated, return Cauchy step.\n");
normal_x = v_cauchy_x_bak;
normal_s = v_cauchy_s_bak;
normal_s->ElementWiseMultiply(*InexCq().curr_scaling_slacks());
IpData().Append_info_string("NF ");
return true;
}
if( Jnlst().ProduceOutput(J_MOREVECTOR, J_SOLVE_PD_SYSTEM) )
{
Jnlst().Printf(J_MOREVECTOR, J_SOLVE_PD_SYSTEM,
"Dogleg step: Newton step:\n");
v_newton_x->Print(Jnlst(), J_MOREVECTOR, J_SOLVE_PD_SYSTEM, "v_newton_x");
v_newton_s->Print(Jnlst(), J_MOREVECTOR, J_SOLVE_PD_SYSTEM, "v_newton_s");
}
const Number tr_radius = curr_omega_ * v_ATc_norm;
Number v_newton_norm = IpCq().CalcNormOfType(NORM_2, *v_newton_x, *v_newton_s);
Jnlst().Printf(J_MOREDETAILED, J_SOLVE_PD_SYSTEM,
"Norm of Newton step = %e, trust region radius = %e\n",
v_newton_norm, tr_radius);
if( v_newton_norm <= tr_radius )
{
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: Newton step is within trust region.\n");
normal_x = v_newton_x;
normal_s = v_newton_s;
last_tr_inactive_ = true;
IpData().Append_info_string("Nn ");
}
else
{
Number v_cauchy_norm = IpCq().CalcNormOfType(NORM_2, *v_cauchy_x, *v_cauchy_s);
Number v_cs_dot_n = v_newton_x->Dot(*v_cauchy_x) + v_newton_s->Dot(*v_cauchy_s);
Number a = v_newton_norm * v_newton_norm - 2 * v_cs_dot_n + v_cauchy_norm * v_cauchy_norm;
Number b = 2 * (v_cs_dot_n - v_newton_norm * v_newton_norm);
Number c = v_newton_norm * v_newton_norm - tr_radius * tr_radius;
Number lambda = (-b - std::sqrt(b * b - 4. * a * c)) / (2. * a);
DBG_PRINT((1, "v_cauchy_norm = %e v_cs_dot_n = %e v_newton_norm = %e\n", v_cauchy_norm, v_cs_dot_n, v_newton_norm));
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: Using convex combination of Cauchy and Newton step with factor lambda = %e\n", lambda);
v_cauchy_x->AddOneVector(1. - lambda, *v_newton_x, lambda);
v_cauchy_s->AddOneVector(1. - lambda, *v_newton_s, lambda);
normal_x = v_cauchy_x;
normal_s = v_cauchy_s;
IpData().Append_info_string("Nd ");
DBG_PRINT((1, "v_normal^2 = %e\n", normal_x->Dot(*normal_x) + normal_s->Dot(*normal_s)));
}
DBG_PRINT_VECTOR(1, "normal_x scaled", *normal_x);
DBG_PRINT_VECTOR(1, "normal_s scaled", *normal_s);
normal_s->ElementWiseMultiply(*InexCq().curr_scaling_slacks());
v_cauchy_s_bak->ElementWiseMultiply(*InexCq().curr_scaling_slacks());
const Number tau = IpData().curr_tau();
Number ftb_cauchy = IpCq().primal_frac_to_the_bound(tau, *v_cauchy_x_bak, *v_cauchy_s_bak);
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg: Fraction-to-the-bounary step size for Cauchy step = %23.16e\n", ftb_cauchy);
inf_c = IpCq().curr_jac_c_times_vec(*v_cauchy_x_bak)->MakeNewCopy();
inf_c->AddOneVector(1., *curr_c, ftb_cauchy);
inf_d = curr_d_minus_s->MakeNewCopy();
inf_d->AddTwoVectors(-ftb_cauchy, *v_cauchy_s_bak, ftb_cauchy, *IpCq().curr_jac_d_times_vec(*v_cauchy_x_bak), 1.);
Number objred_ftb_cauchy = 0.5
* (IpCq().CalcNormOfType(NORM_2, *curr_c, *curr_d_minus_s) - IpCq().CalcNormOfType(NORM_2, *inf_c, *inf_d));
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg: Reduction of normal problem objective function by ftb cauchy step = %23.16e\n", objred_ftb_cauchy);
Number ftb_dogleg = IpCq().primal_frac_to_the_bound(tau, *normal_x, *normal_s);
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg: Fraction-to-the-bounary step size for Dogleg step = %23.16e\n", ftb_dogleg);
inf_c = IpCq().curr_jac_c_times_vec(*normal_x)->MakeNewCopy();
inf_c->AddOneVector(1., *curr_c, ftb_dogleg);
inf_d = curr_d_minus_s->MakeNewCopy();
inf_d->AddTwoVectors(-ftb_dogleg, *normal_s, ftb_dogleg, *IpCq().curr_jac_d_times_vec(*normal_x), 1.);
Number objred_ftb_dogleg = 0.5
* (IpCq().CalcNormOfType(NORM_2, *curr_c, *curr_d_minus_s) - IpCq().CalcNormOfType(NORM_2, *inf_c, *inf_d));
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg: Reduction of normal problem objective function by ftb dogleg step = %23.16e\n", objred_ftb_dogleg);
Number rhs = 10. * objred_ftb_dogleg;
Number lhs = objred_ftb_cauchy;
Number BasVal = curr_c->Nrm2() + curr_d_minus_s->Nrm2();
bool ok = Compare_le(lhs, rhs, BasVal);
if( !ok )
{
Jnlst().Printf(J_DETAILED, J_SOLVE_PD_SYSTEM,
"Dogleg step: Dogleg step makes less progress than Cauchy step, resetting to Cauchy step.\n");
normal_x = v_cauchy_x_bak;
normal_s = v_cauchy_s_bak;
IpData().Append_info_string("NR ");
}
return true;
}
}