bool MoochoPack::LineSearchWatchDog_Step::do_step(Algorithm& _algo , poss_type step_poss, IterationPack::EDoStepType type, poss_type assoc_step_poss) { using DenseLinAlgPack::norm_inf; using DenseLinAlgPack::V_VpV; using DenseLinAlgPack::Vp_StV; using DenseLinAlgPack::Vt_S; using LinAlgOpPack::Vp_V; using LinAlgOpPack::V_MtV; using ConstrainedOptPack::print_vector_change_stats; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); NLP &nlp = algo.nlp(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); std::ostream& out = algo.track().journal_out(); out << std::boolalpha; // print step header. if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } // ///////////////////////////////////////// // Set references to iteration quantities // // Set k+1 first then go back to get k to ensure // we have backward storage. DVector &x_kp1 = s.x().set_k(+1).v(); value_type &f_kp1 = s.f().set_k(+1); DVector &c_kp1 = s.c().set_k(+1).v(); const value_type &f_k = s.f().get_k(0); const DVector &c_k = s.c().get_k(0).v(); const DVector &x_k = s.x().get_k(0).v(); const DVector &d_k = s.d().get_k(0).v(); value_type &alpha_k = s.alpha().get_k(0); // ///////////////////////////////////// // Compute Dphi_k, phi_kp1 and phi_k // Dphi_k const value_type Dphi_k = merit_func().deriv(); if( Dphi_k >= 0 ) { throw LineSearchFailure( "LineSearch2ndOrderCorrect_Step::do_step(...) : " "Error, d_k is not a descent direction for the merit function " ); } // ph_kp1 value_type &phi_kp1 = s.phi().set_k(+1) = merit_func().value( f_kp1, c_kp1 ); // Must compute phi(x) at the base point x_k since the penalty parameter may have changed. const value_type &phi_k = s.phi().set_k(0) = merit_func().value( f_k, c_k ); // ////////////////////////////////////// // Setup the calculation merit function // Here f_kp1, and c_kp1 are updated at the same time the // line search is being performed. nlp.set_f( &f_kp1 ); nlp.set_c( &c_kp1 ); MeritFuncCalcNLP phi_calc( &merit_func(), &nlp ); // //////////////////////////////// // Use Watchdog near the solution if( watch_k_ == NORMAL_LINE_SEARCH ) { const value_type opt_kkt_err_k = s.opt_kkt_err().get_k(0), feas_kkt_err_k = s.feas_kkt_err().get_k(0); if( opt_kkt_err_k <= opt_kkt_err_threshold() && feas_kkt_err_k <= feas_kkt_err_threshold() ) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nopt_kkt_err_k = " << opt_kkt_err_k << " <= opt_kkt_err_threshold = " << opt_kkt_err_threshold() << std::endl << "\nfeas_kkt_err_k = " << feas_kkt_err_k << " <= feas_kkt_err_threshold = " << feas_kkt_err_threshold() << std::endl << "\nSwitching to watchdog linesearch ...\n"; } watch_k_ = 0; } } if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nTrial point:\n" << "phi_k = " << phi_k << std::endl << "Dphi_k = " << Dphi_k << std::endl << "phi_kp1 = " << phi_kp1 << std::endl; } bool ls_success = true, step_return = true; switch( watch_k_ ) { case 0: { // Take a full step const value_type phi_cord = phi_k + eta() * Dphi_k; const bool accept_step = phi_kp1 <= phi_cord; if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n*** Zeroth watchdog iteration:\n" << "\nphi_kp1 = " << phi_kp1 << ( accept_step ? " <= " : " > " ) << "phi_k + eta * Dphi_k = " << phi_cord << std::endl; } if( phi_kp1 > phi_cord ) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nAccept this increase for now but watch out next iteration!\n"; } // Save this initial point xo_ = x_k; fo_ = f_k; nrm_co_ = norm_inf( c_k ); do_ = d_k; phio_ = phi_k; Dphio_ = Dphi_k; phiop1_ = phi_kp1; // Slip the update of the penalty parameter const value_type mu_k = s.mu().get_k(0); s.mu().set_k(+1) = mu_k; // Move on to the next step in the watchdog procedure watch_k_ = 1; } else { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nAll is good!\n"; } // watch_k_ stays 0 } step_return = true; break; } case 1: { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n*** First watchdog iteration:\n" << "\nDo a line search to determine x_kp1 = x_k + alpha_k * d_k ...\n"; } // Now do a line search but and we require some type of reduction const DVectorSlice xd[2] = { x_k(), d_k() }; MeritFuncCalc1DQuadratic phi_calc_1d( phi_calc, 1, xd, &x_kp1() ); ls_success = direct_line_search().do_line_search( phi_calc_1d, phi_k , &alpha_k, &phi_kp1 , (int)olevel >= (int)PRINT_ALGORITHM_STEPS ? &out : static_cast<std::ostream*>(0) ); // If the linesearch failed then the rest of the tests will catch this. value_type phi_cord = 0; bool test1, test2; if( ( test1 = ( phi_k <= phio_ ) ) || ( test2 = phi_kp1 <= ( phi_cord = phio_ + eta() * Dphio_ ) ) ) { // We will accept this step and and move on. if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nphi_k = " << phi_k << ( test1 ? " <= " : " > " ) << "phi_km1 = " << phio_ << std::endl << "phi_kp1 = " << phi_kp1 << ( test2 ? " <= " : " > " ) << "phi_km1 + eta * Dphi_km1 = " << phi_cord << std::endl << "This is a sufficent reduction so reset watchdog.\n"; } watch_k_ = 0; step_return = true; } else if ( ! ( test1 = ( phi_kp1 <= phio_ ) ) ) { // Even this reduction is no good! // Go back to original point and do a linesearch from there. if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nphi_kp1 = " << phi_kp1 << " > phi_km1 = " << phio_ << std::endl << "This is not good reduction in phi so do linesearch from x_km1\n" << "\n* Go back to x_km1: x_kp1 = x_k - alpha_k * d_k ...\n"; } // Go back from x_k to x_km1 for iteration k: // // x_kp1 = x_km1 // x_kp1 = x_k - alpha_km1 * d_km1 // // A negative sign for alpha is an indication that we are backtracking. // s.alpha().set_k(0) = -1.0; s.d().set_k(0).v() = do_; s.f().set_k(+1) = fo_; if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "Output iteration k ...\n" << "k = k+1\n"; } // Output these iteration quantities algo.track().output_iteration( algo ); // k // Transition to iteration k+1 s.next_iteration(); // Take the step from x_k = x_km2 to x_kp1 for iteration k (k+1): // // x_kp1 = x_km2 + alpha_n * d_km2 // x_kp1 = x_k + alpha_n * d_km1 // x_kp1 = x_n // if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n* Take the step from x_k = x_km2 to x_kp1 for iteration k (k+1)\n" << "Find: x_kp1 = x_k + alpha_k * d_k = x_km2 + alpha_k * d_km2\n ...\n"; } // alpha_k = 1.0 value_type &alpha_k = s.alpha().set_k(0) = 1.0; // ///////////////////////////////////// // Compute Dphi_k and phi_k // x_k const DVector &x_k = xo_; // d_k const DVector &d_k = s.d().set_k(0).v() = do_; // Dphi_k const value_type &Dphi_k = Dphio_; // phi_k const value_type &phi_k = s.phi().set_k(0) = phio_; // Here f_kp1, and c_kp1 are updated at the same time the // line search is being performed. algo.nlp().set_f( &s.f().set_k(+1) ); algo.nlp().set_c( &s.c().set_k(+1).v() ); phi_calc.set_nlp( algo.get_nlp() ); // //////////////////////////////////////// // Compute x_xp1 and ph_kp1 for full step // x_kp1 = x_k + alpha_k * d_k DVector &x_kp1 = s.x().set_k(+1).v(); V_VpV( &x_kp1, x_k, d_k ); // phi_kp1 value_type &phi_kp1 = s.phi().set_k(+1) = phiop1_; const DVectorSlice xd[2] = { x_k(), d_k() }; MeritFuncCalc1DQuadratic phi_calc_1d( phi_calc, 1, xd, &x_kp1() ); ls_success = direct_line_search().do_line_search( phi_calc_1d, phi_k , &alpha_k, &phi_kp1 , (int)olevel >= (int)PRINT_ALGORITHM_STEPS ? &out : static_cast<std::ostream*>(0) ); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nOutput iteration k (k+1) ...\n" << "k = k+1 (k+2)\n" << "Reinitialize watchdog algorithm\n"; } // Output these iteration quantities algo.track().output_iteration( algo ); // (k+1) // Transition to iteration k+1 (k+2) s.next_iteration(); watch_k_ = 0; // Reinitialize the watchdog // Any update for k (k+2) should use the last updated value // which was for k-2 (k) since there is not much info for k-1 (k+1). // Be careful here and make sure this is square with other steps. algo.do_step_next( EvalNewPoint_name ); step_return = false; // Redirect control } else { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "phi_kp1 = " << phi_kp1 << " <= phi_km1 = " << phio_ << std::endl << "\nAccept this step but do a linesearch next iteration!\n"; } // Slip the update of the penalty parameter const value_type mu_k = s.mu().get_k(0); s.mu().set_k(+1) = mu_k; // Do the last stage of the watchdog procedure next iteration. watch_k_ = 2; step_return = true; } break; } case NORMAL_LINE_SEARCH: case 2: { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { if( watch_k_ == 2 ) { out << "\n*** Second watchdog iteration:\n" << "Do a line search to determine x_kp1 = x_k + alpha_k * d_k ...\n"; } else { out << "\n*** Normal linesearch:\n" << "Do a line search to determine x_kp1 = x_k + alpha_k * d_k ...\n"; } } const DVectorSlice xd[2] = { x_k(), d_k() }; MeritFuncCalc1DQuadratic phi_calc_1d( phi_calc, 1, xd, &x_kp1() ); ls_success = direct_line_search().do_line_search( phi_calc_1d, phi_k , &alpha_k, &phi_kp1 , (int)olevel >= (int)PRINT_ALGORITHM_STEPS ? &out : static_cast<std::ostream*>(0) ); if( watch_k_ == 2 ) watch_k_ = 0; step_return = true; break; } default: TEST_FOR_EXCEPT(true); // Only local programming error } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nalpha = " << s.alpha().get_k(0) << "\n"; out << "\nphi_kp1 = " << s.phi().get_k(+1) << "\n"; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nd_k = \n" << s.d().get_k(0)(); out << "\nx_kp1 = \n" << s.x().get_k(+1)(); } if( !ls_success ) throw LineSearchFailure("LineSearchWatchDog_Step::do_step(): Line search failure"); return step_return; }
bool MeritFunc_PenaltyParamsUpdateWithMult_AddedStep::do_step(Algorithm& _algo , poss_type step_poss, IterationPack::EDoStepType type , poss_type assoc_step_poss) { using DenseLinAlgPack::norm_inf; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); std::ostream& out = algo.track().journal_out(); // print step header. if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } MeritFuncPenaltyParams *params = dynamic_cast<MeritFuncPenaltyParams*>(&merit_func()); if( !params ) { std::ostringstream omsg; omsg << "MeritFunc_PenaltyParamsUpdateWithMult_AddedStep::do_step(...), Error " << "The class " << typeName(&merit_func()) << " does not support the " << "MeritFuncPenaltyParams iterface\n"; out << omsg.str(); throw std::logic_error( omsg.str() ); } MeritFuncNLPDirecDeriv *direc_deriv = dynamic_cast<MeritFuncNLPDirecDeriv*>(&merit_func()); if( !direc_deriv ) { std::ostringstream omsg; omsg << "MeritFunc_PenaltyParamsUpdateWithMult_AddedStep::do_step(...), Error " << "The class " << typeName(&merit_func()) << " does not support the " << "MeritFuncNLPDirecDeriv iterface\n"; out << omsg.str(); throw std::logic_error( omsg.str() ); } bool perform_update = true; if( s.mu().updated_k(0) ) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nmu_k is already updated by someone else?\n"; } const value_type mu_k = s.mu().get_k(0); if( mu_k == norm_inf_mu_last_ ) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nmu_k " << mu_k << " == norm_inf_mu_last = " << norm_inf_mu_last_ << "\nso we will take this as a signal to skip the update.\n"; } perform_update = false; } else { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nmu_k " << mu_k << " != norm_inf_mu_last = " << norm_inf_mu_last_ << "\nso we will ignore this and perform the update anyway.\n"; } } } if(perform_update) { if ( s.lambda().updated_k(0) ) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nUpdate the penalty parameter...\n"; } const DVector &lambda_k = s.lambda().get_k(0).cv(); if( params->mu().size() != lambda_k.size() ) params->resize( lambda_k.size() ); DVectorSlice mu = params->mu(); const value_type max_lambda = norm_inf( lambda_k() ), mult_fact = (1.0 + mult_factor_); if(near_solution_) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nNear solution, forcing mu(j) >= mu_old(j)...\n"; } DVector::const_iterator lb_itr = lambda_k.begin(); DVectorSlice::iterator mu_itr = mu.begin(); for( ; lb_itr != lambda_k.end(); ++mu_itr, ++ lb_itr ) *mu_itr = max( max( *mu_itr, mult_fact * ::fabs(*lb_itr) ), small_mu_ ); } else { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nNot near solution, allowing reduction in mu(j) ...\n"; } DVector::const_iterator lb_itr = lambda_k.begin(); DVectorSlice::iterator mu_itr = mu.begin(); for( ; lb_itr != lambda_k.end(); ++mu_itr, ++ lb_itr ) { const value_type lb_j = ::fabs(*lb_itr); *mu_itr = max( (3.0 * (*mu_itr) + lb_j) / 4.0 , max( mult_fact * lb_j, small_mu_ ) ); } value_type kkt_error = s.opt_kkt_err().get_k(0) + s.feas_kkt_err().get_k(0); if(kkt_error <= kkt_near_sol_) { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nkkt_error = " << kkt_error << " <= kkt_near_sol = " << kkt_near_sol_ << std::endl << "Switching to forcing mu_k >= mu_km1 in the future\n"; } near_solution_ = true; } } // Force the ratio const value_type max_mu = norm_inf( mu() ), min_mu = min_mu_ratio_ * max_mu; for(DVectorSlice::iterator mu_itr = mu.begin(); mu_itr != mu.end(); ++mu_itr) *mu_itr = max( (*mu_itr), min_mu ); s.mu().set_k(0) = norm_inf_mu_last_ = max_mu; if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nmax(|mu(j)|) = " << (*std::max_element( mu.begin(), mu.end() )) << "\nmin(|mu(j)|) = " << (*std::min_element( mu.begin(), mu.end() )) << std::endl; } if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nmu = \n" << mu; } } else { if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nDon't have the info to update penalty parameter so just use the last updated...\n"; } } } // In addition also compute the directional derivative direc_deriv->calc_deriv( s.Gf().get_k(0)(), s.c().get_k(0)(), s.d().get_k(0)() ); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\nmu_k = " << s.mu().get_k(0) << "\n"; } return true; }