void Sqpmethod::evaluate() { if (inputs_check_) checkInputs(); checkInitialBounds(); if (gather_stats_) { Dict iterations; iterations["inf_pr"] = std::vector<double>(); iterations["inf_du"] = std::vector<double>(); iterations["ls_trials"] = std::vector<double>(); iterations["d_norm"] = std::vector<double>(); iterations["obj"] = std::vector<double>(); stats_["iterations"] = iterations; } // Get problem data const vector<double>& x_init = input(NLP_SOLVER_X0).data(); const vector<double>& lbx = input(NLP_SOLVER_LBX).data(); const vector<double>& ubx = input(NLP_SOLVER_UBX).data(); const vector<double>& lbg = input(NLP_SOLVER_LBG).data(); const vector<double>& ubg = input(NLP_SOLVER_UBG).data(); // Set linearization point to initial guess copy(x_init.begin(), x_init.end(), x_.begin()); // Initialize Lagrange multipliers of the NLP copy(input(NLP_SOLVER_LAM_G0).begin(), input(NLP_SOLVER_LAM_G0).end(), mu_.begin()); copy(input(NLP_SOLVER_LAM_X0).begin(), input(NLP_SOLVER_LAM_X0).end(), mu_x_.begin()); t_eval_f_ = t_eval_grad_f_ = t_eval_g_ = t_eval_jac_g_ = t_eval_h_ = t_callback_fun_ = t_callback_prepare_ = t_mainloop_ = 0; n_eval_f_ = n_eval_grad_f_ = n_eval_g_ = n_eval_jac_g_ = n_eval_h_ = 0; double time1 = clock(); // Initial constraint Jacobian eval_jac_g(x_, gk_, Jk_); // Initial objective gradient eval_grad_f(x_, fk_, gf_); // Initialize or reset the Hessian or Hessian approximation reg_ = 0; if (exact_hessian_) { eval_h(x_, mu_, 1.0, Bk_); } else { reset_h(); } // Evaluate the initial gradient of the Lagrangian copy(gf_.begin(), gf_.end(), gLag_.begin()); if (ng_>0) casadi_mv_t(Jk_.ptr(), Jk_.sparsity(), getPtr(mu_), getPtr(gLag_)); // gLag += mu_x_; transform(gLag_.begin(), gLag_.end(), mu_x_.begin(), gLag_.begin(), plus<double>()); // Number of SQP iterations int iter = 0; // Number of line-search iterations int ls_iter = 0; // Last linesearch successfull bool ls_success = true; // Reset merit_mem_.clear(); sigma_ = 0.; // NOTE: Move this into the main optimization loop // Default stepsize double t = 0; // MAIN OPTIMIZATION LOOP while (true) { // Primal infeasability double pr_inf = primalInfeasibility(x_, lbx, ubx, gk_, lbg, ubg); // inf-norm of lagrange gradient double gLag_norminf = norm_inf(gLag_); // inf-norm of step double dx_norminf = norm_inf(dx_); // Print header occasionally if (iter % 10 == 0) printIteration(userOut()); // Printing information about the actual iterate printIteration(userOut(), iter, fk_, pr_inf, gLag_norminf, dx_norminf, reg_, ls_iter, ls_success); if (gather_stats_) { Dict iterations = stats_["iterations"]; std::vector<double> tmp=iterations["inf_pr"]; tmp.push_back(pr_inf); iterations["inf_pr"] = tmp; tmp=iterations["inf_du"]; tmp.push_back(gLag_norminf); iterations["inf_du"] = tmp; tmp=iterations["d_norm"]; tmp.push_back(dx_norminf); iterations["d_norm"] = tmp; std::vector<int> tmp2=iterations["ls_trials"]; tmp2.push_back(ls_iter); iterations["ls_trials"] = tmp2; tmp=iterations["obj"]; tmp.push_back(fk_); iterations["obj"] = tmp; stats_["iterations"] = iterations; } // Call callback function if present if (!callback_.isNull()) { double time1 = clock(); if (!output(NLP_SOLVER_F).isempty()) output(NLP_SOLVER_F).set(fk_); if (!output(NLP_SOLVER_X).isempty()) output(NLP_SOLVER_X).setNZ(x_); if (!output(NLP_SOLVER_LAM_G).isempty()) output(NLP_SOLVER_LAM_G).setNZ(mu_); if (!output(NLP_SOLVER_LAM_X).isempty()) output(NLP_SOLVER_LAM_X).setNZ(mu_x_); if (!output(NLP_SOLVER_G).isempty()) output(NLP_SOLVER_G).setNZ(gk_); Dict iteration; iteration["iter"] = iter; iteration["inf_pr"] = pr_inf; iteration["inf_du"] = gLag_norminf; iteration["d_norm"] = dx_norminf; iteration["ls_trials"] = ls_iter; iteration["obj"] = fk_; stats_["iteration"] = iteration; double time2 = clock(); t_callback_prepare_ += (time2-time1)/CLOCKS_PER_SEC; time1 = clock(); int ret = callback_(ref_, user_data_); time2 = clock(); t_callback_fun_ += (time2-time1)/CLOCKS_PER_SEC; if (ret) { userOut() << endl; userOut() << "casadi::SQPMethod: aborted by callback..." << endl; stats_["return_status"] = "User_Requested_Stop"; break; } } // Checking convergence criteria if (pr_inf < tol_pr_ && gLag_norminf < tol_du_) { userOut() << endl; userOut() << "casadi::SQPMethod: Convergence achieved after " << iter << " iterations." << endl; stats_["return_status"] = "Solve_Succeeded"; break; } if (iter >= max_iter_) { userOut() << endl; userOut() << "casadi::SQPMethod: Maximum number of iterations reached." << endl; stats_["return_status"] = "Maximum_Iterations_Exceeded"; break; } if (iter > 0 && dx_norminf <= min_step_size_) { userOut() << endl; userOut() << "casadi::SQPMethod: Search direction becomes too small without " "convergence criteria being met." << endl; stats_["return_status"] = "Search_Direction_Becomes_Too_Small"; break; } // Start a new iteration iter++; log("Formulating QP"); // Formulate the QP transform(lbx.begin(), lbx.end(), x_.begin(), qp_LBX_.begin(), minus<double>()); transform(ubx.begin(), ubx.end(), x_.begin(), qp_UBX_.begin(), minus<double>()); transform(lbg.begin(), lbg.end(), gk_.begin(), qp_LBA_.begin(), minus<double>()); transform(ubg.begin(), ubg.end(), gk_.begin(), qp_UBA_.begin(), minus<double>()); // Solve the QP solve_QP(Bk_, gf_, qp_LBX_, qp_UBX_, Jk_, qp_LBA_, qp_UBA_, dx_, qp_DUAL_X_, qp_DUAL_A_); log("QP solved"); // Detecting indefiniteness double gain = casadi_quad_form(Bk_.ptr(), Bk_.sparsity(), getPtr(dx_)); if (gain < 0) { casadi_warning("Indefinite Hessian detected..."); } // Calculate penalty parameter of merit function sigma_ = std::max(sigma_, 1.01*norm_inf(qp_DUAL_X_)); sigma_ = std::max(sigma_, 1.01*norm_inf(qp_DUAL_A_)); // Calculate L1-merit function in the actual iterate double l1_infeas = primalInfeasibility(x_, lbx, ubx, gk_, lbg, ubg); // Right-hand side of Armijo condition double F_sens = inner_prod(dx_, gf_); double L1dir = F_sens - sigma_ * l1_infeas; double L1merit = fk_ + sigma_ * l1_infeas; // Storing the actual merit function value in a list merit_mem_.push_back(L1merit); if (merit_mem_.size() > merit_memsize_) { merit_mem_.pop_front(); } // Stepsize t = 1.0; double fk_cand; // Merit function value in candidate double L1merit_cand = 0; // Reset line-search counter, success marker ls_iter = 0; ls_success = true; // Line-search log("Starting line-search"); if (max_iter_ls_>0) { // max_iter_ls_== 0 disables line-search // Line-search loop while (true) { for (int i=0; i<nx_; ++i) x_cand_[i] = x_[i] + t * dx_[i]; try { // Evaluating objective and constraints eval_f(x_cand_, fk_cand); eval_g(x_cand_, gk_cand_); } catch(const CasadiException& ex) { // Silent ignore; line-search failed ls_iter++; // Backtracking t = beta_ * t; continue; } ls_iter++; // Calculating merit-function in candidate l1_infeas = primalInfeasibility(x_cand_, lbx, ubx, gk_cand_, lbg, ubg); L1merit_cand = fk_cand + sigma_ * l1_infeas; // Calculating maximal merit function value so far double meritmax = *max_element(merit_mem_.begin(), merit_mem_.end()); if (L1merit_cand <= meritmax + t * c1_ * L1dir) { // Accepting candidate log("Line-search completed, candidate accepted"); break; } // Line-search not successful, but we accept it. if (ls_iter == max_iter_ls_) { ls_success = false; log("Line-search completed, maximum number of iterations"); break; } // Backtracking t = beta_ * t; } // Candidate accepted, update dual variables for (int i=0; i<ng_; ++i) mu_[i] = t * qp_DUAL_A_[i] + (1 - t) * mu_[i]; for (int i=0; i<nx_; ++i) mu_x_[i] = t * qp_DUAL_X_[i] + (1 - t) * mu_x_[i]; // Candidate accepted, update the primal variable copy(x_.begin(), x_.end(), x_old_.begin()); copy(x_cand_.begin(), x_cand_.end(), x_.begin()); } else { // Full step copy(qp_DUAL_A_.begin(), qp_DUAL_A_.end(), mu_.begin()); copy(qp_DUAL_X_.begin(), qp_DUAL_X_.end(), mu_x_.begin()); copy(x_.begin(), x_.end(), x_old_.begin()); // x+=dx transform(x_.begin(), x_.end(), dx_.begin(), x_.begin(), plus<double>()); } if (!exact_hessian_) { // Evaluate the gradient of the Lagrangian with the old x but new mu (for BFGS) copy(gf_.begin(), gf_.end(), gLag_old_.begin()); if (ng_>0) casadi_mv_t(Jk_.ptr(), Jk_.sparsity(), getPtr(mu_), getPtr(gLag_old_)); // gLag_old += mu_x_; transform(gLag_old_.begin(), gLag_old_.end(), mu_x_.begin(), gLag_old_.begin(), plus<double>()); } // Evaluate the constraint Jacobian log("Evaluating jac_g"); eval_jac_g(x_, gk_, Jk_); // Evaluate the gradient of the objective function log("Evaluating grad_f"); eval_grad_f(x_, fk_, gf_); // Evaluate the gradient of the Lagrangian with the new x and new mu copy(gf_.begin(), gf_.end(), gLag_.begin()); if (ng_>0) casadi_mv_t(Jk_.ptr(), Jk_.sparsity(), getPtr(mu_), getPtr(gLag_)); // gLag += mu_x_; transform(gLag_.begin(), gLag_.end(), mu_x_.begin(), gLag_.begin(), plus<double>()); // Updating Lagrange Hessian if (!exact_hessian_) { log("Updating Hessian (BFGS)"); // BFGS with careful updates and restarts if (iter % lbfgs_memory_ == 0) { // Reset Hessian approximation by dropping all off-diagonal entries const int* colind = Bk_.colind(); // Access sparsity (column offset) int ncol = Bk_.size2(); const int* row = Bk_.row(); // Access sparsity (row) vector<double>& data = Bk_.data(); // Access nonzero elements for (int cc=0; cc<ncol; ++cc) { // Loop over the columns of the Hessian for (int el=colind[cc]; el<colind[cc+1]; ++el) { // Loop over the nonzero elements of the column if (cc!=row[el]) data[el] = 0; // Remove if off-diagonal entries } } } // Pass to BFGS update function bfgs_.setInput(Bk_, BFGS_BK); bfgs_.setInputNZ(x_, BFGS_X); bfgs_.setInputNZ(x_old_, BFGS_X_OLD); bfgs_.setInputNZ(gLag_, BFGS_GLAG); bfgs_.setInputNZ(gLag_old_, BFGS_GLAG_OLD); // Update the Hessian approximation bfgs_.evaluate(); // Get the updated Hessian bfgs_.getOutput(Bk_); if (monitored("bfgs")) { userOut() << "x = " << x_ << endl; userOut() << "BFGS = " << endl; Bk_.printSparse(); } } else { // Exact Hessian log("Evaluating hessian"); eval_h(x_, mu_, 1.0, Bk_); } } double time2 = clock(); t_mainloop_ = (time2-time1)/CLOCKS_PER_SEC; // Save results to outputs output(NLP_SOLVER_F).set(fk_); output(NLP_SOLVER_X).setNZ(x_); output(NLP_SOLVER_LAM_G).setNZ(mu_); output(NLP_SOLVER_LAM_X).setNZ(mu_x_); output(NLP_SOLVER_G).setNZ(gk_); if (hasOption("print_time") && static_cast<bool>(getOption("print_time"))) { // Write timings userOut() << "time spent in eval_f: " << t_eval_f_ << " s."; if (n_eval_f_>0) userOut() << " (" << n_eval_f_ << " calls, " << (t_eval_f_/n_eval_f_)*1000 << " ms. average)"; userOut() << endl; userOut() << "time spent in eval_grad_f: " << t_eval_grad_f_ << " s."; if (n_eval_grad_f_>0) userOut() << " (" << n_eval_grad_f_ << " calls, " << (t_eval_grad_f_/n_eval_grad_f_)*1000 << " ms. average)"; userOut() << endl; userOut() << "time spent in eval_g: " << t_eval_g_ << " s."; if (n_eval_g_>0) userOut() << " (" << n_eval_g_ << " calls, " << (t_eval_g_/n_eval_g_)*1000 << " ms. average)"; userOut() << endl; userOut() << "time spent in eval_jac_g: " << t_eval_jac_g_ << " s."; if (n_eval_jac_g_>0) userOut() << " (" << n_eval_jac_g_ << " calls, " << (t_eval_jac_g_/n_eval_jac_g_)*1000 << " ms. average)"; userOut() << endl; userOut() << "time spent in eval_h: " << t_eval_h_ << " s."; if (n_eval_h_>1) userOut() << " (" << n_eval_h_ << " calls, " << (t_eval_h_/n_eval_h_)*1000 << " ms. average)"; userOut() << endl; userOut() << "time spent in main loop: " << t_mainloop_ << " s." << endl; userOut() << "time spent in callback function: " << t_callback_fun_ << " s." << endl; userOut() << "time spent in callback preparation: " << t_callback_prepare_ << " s." << endl; } // Save statistics stats_["iter_count"] = iter; stats_["t_eval_f"] = t_eval_f_; stats_["t_eval_grad_f"] = t_eval_grad_f_; stats_["t_eval_g"] = t_eval_g_; stats_["t_eval_jac_g"] = t_eval_jac_g_; stats_["t_eval_h"] = t_eval_h_; stats_["t_mainloop"] = t_mainloop_; stats_["t_callback_fun"] = t_callback_fun_; stats_["t_callback_prepare"] = t_callback_prepare_; stats_["n_eval_f"] = n_eval_f_; stats_["n_eval_grad_f"] = n_eval_grad_f_; stats_["n_eval_g"] = n_eval_g_; stats_["n_eval_jac_g"] = n_eval_jac_g_; stats_["n_eval_h"] = n_eval_h_; }
void SQPInternal::evaluate(int nfdir, int nadir){ casadi_assert(nfdir==0 && nadir==0); checkInitialBounds(); // Get problem data const vector<double>& x_init = input(NLP_X_INIT).data(); const vector<double>& lbx = input(NLP_LBX).data(); const vector<double>& ubx = input(NLP_UBX).data(); const vector<double>& lbg = input(NLP_LBG).data(); const vector<double>& ubg = input(NLP_UBG).data(); // Set the static parameter if (parametric_) { const vector<double>& p = input(NLP_P).data(); if (!F_.isNull()) F_.setInput(p,F_.getNumInputs()-1); if (!G_.isNull()) G_.setInput(p,G_.getNumInputs()-1); if (!H_.isNull()) H_.setInput(p,H_.getNumInputs()-1); if (!J_.isNull()) J_.setInput(p,J_.getNumInputs()-1); } // Set linearization point to initial guess copy(x_init.begin(),x_init.end(),x_.begin()); // Lagrange multipliers of the NLP fill(mu_.begin(),mu_.end(),0); fill(mu_x_.begin(),mu_x_.end(),0); // Initial constraint Jacobian eval_jac_g(x_,gk_,Jk_); // Initial objective gradient eval_grad_f(x_,fk_,gf_); // Initialize or reset the Hessian or Hessian approximation reg_ = 0; if( hess_mode_ == HESS_BFGS){ reset_h(); } else { eval_h(x_,mu_,1.0,Bk_); } // Evaluate the initial gradient of the Lagrangian copy(gf_.begin(),gf_.end(),gLag_.begin()); if(m_>0) DMatrix::mul_no_alloc_tn(Jk_,mu_,gLag_); // gLag += mu_x_; transform(gLag_.begin(),gLag_.end(),mu_x_.begin(),gLag_.begin(),plus<double>()); // Number of SQP iterations int iter = 0; // Number of line-search iterations int ls_iter = 0; // Last linesearch successfull bool ls_success = true; // Reset merit_mem_.clear(); sigma_ = 0.; // NOTE: Move this into the main optimization loop // Default stepsize double t = 0; // MAIN OPTIMIZATION LOOP while(true){ // Primal infeasability double pr_inf = primalInfeasibility(x_, lbx, ubx, gk_, lbg, ubg); // 1-norm of lagrange gradient double gLag_norm1 = norm_1(gLag_); // 1-norm of step double dx_norm1 = norm_1(dx_); // Print header occasionally if(iter % 10 == 0) printIteration(cout); // Printing information about the actual iterate printIteration(cout,iter,fk_,pr_inf,gLag_norm1,dx_norm1,reg_,ls_iter,ls_success); // Call callback function if present if (!callback_.isNull()) { callback_.input(NLP_COST).set(fk_); callback_.input(NLP_X_OPT).set(x_); callback_.input(NLP_LAMBDA_G).set(mu_); callback_.input(NLP_LAMBDA_X).set(mu_x_); callback_.input(NLP_G).set(gk_); callback_.evaluate(); if (callback_.output(0).at(0)) { cout << endl; cout << "CasADi::SQPMethod: aborted by callback..." << endl; break; } } // Checking convergence criteria if (pr_inf < tol_pr_ && gLag_norm1 < tol_du_){ cout << endl; cout << "CasADi::SQPMethod: Convergence achieved after " << iter << " iterations." << endl; break; } if (iter >= maxiter_){ cout << endl; cout << "CasADi::SQPMethod: Maximum number of iterations reached." << endl; break; } // Start a new iteration iter++; // Formulate the QP transform(lbx.begin(),lbx.end(),x_.begin(),qp_LBX_.begin(),minus<double>()); transform(ubx.begin(),ubx.end(),x_.begin(),qp_UBX_.begin(),minus<double>()); transform(lbg.begin(),lbg.end(),gk_.begin(),qp_LBA_.begin(),minus<double>()); transform(ubg.begin(),ubg.end(),gk_.begin(),qp_UBA_.begin(),minus<double>()); // Solve the QP solve_QP(Bk_,gf_,qp_LBX_,qp_UBX_,Jk_,qp_LBA_,qp_UBA_,dx_,qp_DUAL_X_,qp_DUAL_A_); log("QP solved"); // Detecting indefiniteness double gain = quad_form(dx_,Bk_); if (gain < 0){ casadi_warning("Indefinite Hessian detected..."); } // Calculate penalty parameter of merit function sigma_ = std::max(sigma_,1.01*norm_inf(qp_DUAL_X_)); sigma_ = std::max(sigma_,1.01*norm_inf(qp_DUAL_A_)); // Calculate L1-merit function in the actual iterate double l1_infeas = primalInfeasibility(x_, lbx, ubx, gk_, lbg, ubg); // Right-hand side of Armijo condition double F_sens = inner_prod(dx_, gf_); double L1dir = F_sens - sigma_ * l1_infeas; double L1merit = fk_ + sigma_ * l1_infeas; // Storing the actual merit function value in a list merit_mem_.push_back(L1merit); if (merit_mem_.size() > merit_memsize_){ merit_mem_.pop_front(); } // Stepsize t = 1.0; double fk_cand; // Merit function value in candidate double L1merit_cand = 0; // Reset line-search counter, success marker ls_iter = 0; ls_success = true; // Line-search log("Starting line-search"); if(maxiter_ls_>0){ // maxiter_ls_== 0 disables line-search // Line-search loop while (true){ for(int i=0; i<n_; ++i) x_cand_[i] = x_[i] + t * dx_[i]; // Evaluating objective and constraints eval_f(x_cand_,fk_cand); eval_g(x_cand_,gk_cand_); ls_iter++; // Calculating merit-function in candidate l1_infeas = primalInfeasibility(x_cand_, lbx, ubx, gk_cand_, lbg, ubg); L1merit_cand = fk_cand + sigma_ * l1_infeas; // Calculating maximal merit function value so far double meritmax = *max_element(merit_mem_.begin(), merit_mem_.end()); if (L1merit_cand <= meritmax + t * c1_ * L1dir){ // Accepting candidate log("Line-search completed, candidate accepted"); break; } // Line-search not successful, but we accept it. if(ls_iter == maxiter_ls_){ ls_success = false; log("Line-search completed, maximum number of iterations"); break; } // Backtracking t = beta_ * t; } } // Candidate accepted, update dual variables for(int i=0; i<m_; ++i) mu_[i] = t * qp_DUAL_A_[i] + (1 - t) * mu_[i]; for(int i=0; i<n_; ++i) mu_x_[i] = t * qp_DUAL_X_[i] + (1 - t) * mu_x_[i]; if( hess_mode_ == HESS_BFGS){ // Evaluate the gradient of the Lagrangian with the old x but new mu (for BFGS) copy(gf_.begin(),gf_.end(),gLag_old_.begin()); if(m_>0) DMatrix::mul_no_alloc_tn(Jk_,mu_,gLag_old_); // gLag_old += mu_x_; transform(gLag_old_.begin(),gLag_old_.end(),mu_x_.begin(),gLag_old_.begin(),plus<double>()); } // Candidate accepted, update the primal variable copy(x_.begin(),x_.end(),x_old_.begin()); copy(x_cand_.begin(),x_cand_.end(),x_.begin()); // Evaluate the constraint Jacobian log("Evaluating jac_g"); eval_jac_g(x_,gk_,Jk_); // Evaluate the gradient of the objective function log("Evaluating grad_f"); eval_grad_f(x_,fk_,gf_); // Evaluate the gradient of the Lagrangian with the new x and new mu copy(gf_.begin(),gf_.end(),gLag_.begin()); if(m_>0) DMatrix::mul_no_alloc_tn(Jk_,mu_,gLag_); // gLag += mu_x_; transform(gLag_.begin(),gLag_.end(),mu_x_.begin(),gLag_.begin(),plus<double>()); // Updating Lagrange Hessian if( hess_mode_ == HESS_BFGS){ log("Updating Hessian (BFGS)"); // BFGS with careful updates and restarts if (iter % lbfgs_memory_ == 0){ // Reset Hessian approximation by dropping all off-diagonal entries const vector<int>& rowind = Bk_.rowind(); // Access sparsity (row offset) const vector<int>& col = Bk_.col(); // Access sparsity (column) vector<double>& data = Bk_.data(); // Access nonzero elements for(int i=0; i<rowind.size()-1; ++i){ // Loop over the rows of the Hessian for(int el=rowind[i]; el<rowind[i+1]; ++el){ // Loop over the nonzero elements of the row if(i!=col[el]) data[el] = 0; // Remove if off-diagonal entries } } } // Pass to BFGS update function bfgs_.setInput(Bk_,BFGS_BK); bfgs_.setInput(x_,BFGS_X); bfgs_.setInput(x_old_,BFGS_X_OLD); bfgs_.setInput(gLag_,BFGS_GLAG); bfgs_.setInput(gLag_old_,BFGS_GLAG_OLD); // Update the Hessian approximation bfgs_.evaluate(); // Get the updated Hessian bfgs_.getOutput(Bk_); } else { // Exact Hessian log("Evaluating hessian"); eval_h(x_,mu_,1.0,Bk_); } } // Save results to outputs output(NLP_COST).set(fk_); output(NLP_X_OPT).set(x_); output(NLP_LAMBDA_G).set(mu_); output(NLP_LAMBDA_X).set(mu_x_); output(NLP_G).set(gk_); // Save statistics stats_["iter_count"] = iter; }
void LiftedSQPInternal::evaluate(int nfdir, int nadir){ casadi_assert(nfdir==0 && nadir==0); checkInitialBounds(); // Objective value double f_k = numeric_limits<double>::quiet_NaN(); // Current guess for the primal solution DMatrix &x_k = output(NLP_SOLVER_X); const DMatrix &x_init = input(NLP_SOLVER_X0); copy(x_init.begin(),x_init.end(),x_k.begin()); // Current guess for the dual solution DMatrix &lam_x_k = output(NLP_SOLVER_LAM_X); DMatrix &lam_g_k = output(NLP_SOLVER_LAM_G); // Bounds const DMatrix &x_min = input(NLP_SOLVER_LBX); const DMatrix &x_max = input(NLP_SOLVER_UBX); const DMatrix &g_min = input(NLP_SOLVER_LBG); const DMatrix &g_max = input(NLP_SOLVER_UBG); int k=0; // Does G depend on the multipliers? bool has_lam_x = !rfcn_.input(G_LAM_X).empty(); bool has_lam_g = !rfcn_.input(G_LAM_G).empty(); bool has_lam_f2 = !efcn_.input(EXP_DLAM_F2).empty(); while(true){ // Evaluate residual rfcn_.setInput(x_k,G_X); if(has_lam_x) rfcn_.setInput(lam_x_k,G_LAM_X); if(has_lam_g) rfcn_.setInput(lam_g_k,G_LAM_G); rfcn_.evaluate(); rfcn_.getOutput(d_k_,G_D); f_k = rfcn_.output(G_F).toScalar(); const DMatrix& g_k = rfcn_.output(G_G); // Construct the QP lfcn_.setInput(x_k,LIN_X); if(has_lam_x) lfcn_.setInput(lam_x_k,LIN_LAM_X); if(has_lam_g) lfcn_.setInput(lam_g_k,LIN_LAM_G); lfcn_.setInput(d_k_,LIN_D); lfcn_.evaluate(); DMatrix& B1_k = lfcn_.output(LIN_J1); const DMatrix& b1_k = lfcn_.output(LIN_F1); const DMatrix& B2_k = lfcn_.output(LIN_J2); const DMatrix& b2_k = lfcn_.output(LIN_F2); // Regularization double reg = 0; bool regularization = true; // Check the smallest eigenvalue of the Hessian if(regularization && nu==2){ double a = B1_k.elem(0,0); double b = B1_k.elem(0,1); double c = B1_k.elem(1,0); double d = B1_k.elem(1,1); // Make sure no not a numbers casadi_assert(a==a && b==b && c==c && d==d); // Make sure symmetric if(b!=c){ casadi_assert_warning(fabs(b-c)<1e-10,"Hessian is not symmetric: " << b << " != " << c); B1_k.elem(1,0) = c = b; } double eig_smallest = (a+d)/2 - std::sqrt(4*b*c + (a-d)*(a-d))/2; double threshold = 1e-8; if(eig_smallest<threshold){ // Regularization reg = threshold-eig_smallest; std::cerr << "Regularization with " << reg << " to ensure positive definite Hessian." << endl; B1_k(0,0) += reg; B1_k(1,1) += reg; } } // Solve the QP qp_solver_.setInput(B1_k,QP_H); qp_solver_.setInput(b1_k,QP_G); qp_solver_.setInput(B2_k,QP_A); std::transform(x_min.begin(),x_min.begin()+nu,x_k.begin(),qp_solver_.input(QP_LBX).begin(),std::minus<double>()); std::transform(x_max.begin(),x_max.begin()+nu,x_k.begin(),qp_solver_.input(QP_UBX).begin(),std::minus<double>()); std::transform(g_min.begin()+nv,g_min.end(), b2_k.begin(),qp_solver_.input(QP_LBA).begin(),std::minus<double>()); std::transform(g_max.begin()+nv,g_max.end(), b2_k.begin(),qp_solver_.input(QP_UBA).begin(),std::minus<double>()); qp_solver_.evaluate(); const DMatrix& du_k = qp_solver_.output(QP_PRIMAL); const DMatrix& dlam_u_k = qp_solver_.output(QP_LAMBDA_X); const DMatrix& dlam_f2_k = qp_solver_.output(QP_LAMBDA_A); // Expand the step for(int i=0; i<LIN_NUM_IN; ++i){ efcn_.setInput(lfcn_.input(i),i); } efcn_.setInput(du_k,EXP_DU); if(has_lam_f2) efcn_.setInput(dlam_f2_k,EXP_DLAM_F2); efcn_.evaluate(); const DMatrix& dv_k = efcn_.output(); // Expanded primal step copy(du_k.begin(),du_k.end(),dx_k_.begin()); copy(dv_k.begin(),dv_k.begin()+nv,dx_k_.begin()+nu); // Expanded dual step copy(dlam_u_k.begin(),dlam_u_k.end(),dlam_x_k_.begin()); copy(dlam_f2_k.begin(),dlam_f2_k.end(),dlam_g_k_.begin()+nv); copy(dv_k.rbegin(),dv_k.rbegin()+nv,dlam_g_k_.begin()); // Take a full step transform(dx_k_.begin(),dx_k_.end(),x_k.begin(),x_k.begin(),plus<double>()); copy(dlam_x_k_.begin(),dlam_x_k_.end(),lam_x_k.begin()); transform(dlam_g_k_.begin(),dlam_g_k_.end(),lam_g_k.begin(),lam_g_k.begin(),plus<double>()); // Step size double norm_step=0; for(vector<double>::const_iterator it=dx_k_.begin(); it!=dx_k_.end(); ++it) norm_step += *it**it; if(!gauss_newton_){ for(vector<double>::const_iterator it=dlam_g_k_.begin(); it!=dlam_g_k_.end(); ++it) norm_step += *it**it; } norm_step = sqrt(norm_step); // Constraint violation double norm_viol = 0; for(int i=0; i<x_k.size(); ++i){ double d = fmax(x_k.at(i)-x_max.at(i),0.) + fmax(x_min.at(i)-x_k.at(i),0.); norm_viol += d*d; } for(int i=0; i<g_k.size(); ++i){ double d = fmax(g_k.at(i)-g_max.at(i),0.) + fmax(g_min.at(i)-g_k.at(i),0.); norm_viol += d*d; } norm_viol = sqrt(norm_viol); // Print progress (including the header every 10 rows) if(k % 10 == 0){ cout << setw(4) << "iter" << setw(20) << "objective" << setw(20) << "norm_step" << setw(20) << "norm_viol" << endl; } cout << setw(4) << k << setw(20) << f_k << setw(20) << norm_step << setw(20) << norm_viol << endl; // Check if stopping criteria is satisfied if(norm_viol + norm_step < toldx_){ cout << "Convergence achieved!" << endl; break; } // Increase iteration count k = k+1; // Check if number of iterations have been reached if(k >= max_iter_){ cout << "Maximum number of iterations (" << max_iter_ << ") reached" << endl; break; } } // Store optimal value output(NLP_SOLVER_F).set(f_k); // Save statistics stats_["iter_count"] = k; }
void WorhpInternal::evaluate(){ log("WorhpInternal::evaluate"); if (gather_stats_) { Dictionary iterations; iterations["iter_sqp"] = std::vector<int>(); iterations["inf_pr"] = std::vector<double>(); iterations["inf_du"] = std::vector<double>(); iterations["obj"] = std::vector<double>(); iterations["alpha_pr"] = std::vector<double>(); stats_["iterations"] = iterations; } // Prepare the solver reset(); if (inputs_check_) checkInputs(); checkInitialBounds(); // Reset the counters t_eval_f_ = t_eval_grad_f_ = t_eval_g_ = t_eval_jac_g_ = t_eval_h_ = t_callback_fun_ = t_callback_prepare_ = t_mainloop_ = 0; n_eval_f_ = n_eval_grad_f_ = n_eval_g_ = n_eval_jac_g_ = n_eval_h_ = 0; // Get inputs log("WorhpInternal::evaluate: Reading user inputs"); const DMatrix& x0 = input(NLP_SOLVER_X0); const DMatrix& lbx = input(NLP_SOLVER_LBX); const DMatrix& ubx = input(NLP_SOLVER_UBX); const DMatrix& lam_x0 = input(NLP_SOLVER_LAM_X0); const DMatrix& lbg = input(NLP_SOLVER_LBG); const DMatrix& ubg = input(NLP_SOLVER_UBG); const DMatrix& lam_g0 = input(NLP_SOLVER_LAM_G0); double inf = numeric_limits<double>::infinity(); for (int i=0;i<nx_;++i) { casadi_assert_message(lbx.at(i)!=ubx.at(i),"WorhpSolver::evaluate: Worhp cannot handle the case when LBX == UBX. You have that case at non-zero " << i << " , which has value " << ubx.at(i) << ". Reformulate your problem by using a parameter for the corresponding variable."); } for (int i=0;i<lbg.size();++i) { casadi_assert_message(!(lbg.at(i)==-inf && ubg.at(i) == inf),"WorhpSolver::evaluate: Worhp cannot handle the case when both LBG and UBG are infinite. You have that case at non-zero " << i << ". Reformulate your problem eliminating the corresponding constraint."); } // Pass inputs to WORHP data structures x0.getArray(worhp_o_.X,worhp_o_.n); lbx.getArray(worhp_o_.XL,worhp_o_.n); ubx.getArray(worhp_o_.XU,worhp_o_.n); lam_x0.getArray(worhp_o_.Lambda,worhp_o_.n); if (worhp_o_.m>0){ lam_g0.getArray(worhp_o_.Mu,worhp_o_.m); lbg.getArray(worhp_o_.GL,worhp_o_.m); ubg.getArray(worhp_o_.GU,worhp_o_.m); } // Replace infinite bounds with worhp_p_.Infty for(int i=0; i<nx_; ++i) if(worhp_o_.XL[i]==-inf) worhp_o_.XL[i] = -worhp_p_.Infty; for(int i=0; i<nx_; ++i) if(worhp_o_.XU[i]== inf) worhp_o_.XU[i] = worhp_p_.Infty; for(int i=0; i<ng_; ++i) if(worhp_o_.GL[i]==-inf) worhp_o_.GL[i] = -worhp_p_.Infty; for(int i=0; i<ng_; ++i) if(worhp_o_.GU[i]== inf) worhp_o_.GU[i] = worhp_p_.Infty; log("WorhpInternal::starting iteration"); double time1 = clock(); // Reverse Communication loop while(worhp_c_.status < TerminateSuccess && worhp_c_.status > TerminateError) { if (GetUserAction(&worhp_c_, callWorhp)) { Worhp(&worhp_o_, &worhp_w_, &worhp_p_, &worhp_c_); } if (GetUserAction(&worhp_c_, iterOutput)) { if (!worhp_w_.FirstIteration) { if (gather_stats_) { Dictionary & iterations = stats_["iterations"]; static_cast<std::vector<int> &>(iterations["iter_sqp"]).push_back(worhp_w_.MinorIter); static_cast<std::vector<double> &>(iterations["inf_pr"]).push_back(worhp_w_.NormMax_CV); static_cast<std::vector<double> &>(iterations["inf_du"]).push_back(worhp_w_.ScaledKKT); static_cast<std::vector<double> &>(iterations["obj"]).push_back(worhp_o_.F); static_cast<std::vector<double> &>(iterations["alpha_pr"]).push_back(worhp_w_.ArmijoAlpha); } if (!callback_.isNull()) { double time1 = clock(); // Copy outputs if (!output(NLP_SOLVER_X).isEmpty()) output(NLP_SOLVER_X).setArray(worhp_o_.X,worhp_o_.n); if (!output(NLP_SOLVER_F).isEmpty()) output(NLP_SOLVER_F).set(worhp_o_.F); if (!output(NLP_SOLVER_G).isEmpty()) output(NLP_SOLVER_G).setArray(worhp_o_.G,worhp_o_.m); if (!output(NLP_SOLVER_LAM_X).isEmpty()) output(NLP_SOLVER_LAM_X).setArray(worhp_o_.Lambda,worhp_o_.n); if (!output(NLP_SOLVER_LAM_G).isEmpty()) output(NLP_SOLVER_LAM_G).setArray(worhp_o_.Mu,worhp_o_.m); Dictionary iteration; iteration["iter"] = worhp_w_.MajorIter; iteration["iter_sqp"] = worhp_w_.MinorIter; iteration["inf_pr"] = worhp_w_.NormMax_CV; iteration["inf_du"] = worhp_w_.ScaledKKT; iteration["obj"] = worhp_o_.F; iteration["alpha_pr"] = worhp_w_.ArmijoAlpha; stats_["iteration"] = iteration; double time2 = clock(); t_callback_prepare_ += double(time2-time1)/CLOCKS_PER_SEC; time1 = clock(); int ret = callback_(ref_,user_data_); time2 = clock(); t_callback_fun_ += double(time2-time1)/CLOCKS_PER_SEC; if(ret) worhp_c_.status = TerminatedByUser; } } IterationOutput(&worhp_o_, &worhp_w_, &worhp_p_, &worhp_c_); DoneUserAction(&worhp_c_, iterOutput); } if (GetUserAction(&worhp_c_, evalF)) { eval_f(worhp_o_.X, worhp_w_.ScaleObj, worhp_o_.F); DoneUserAction(&worhp_c_, evalF); } if (GetUserAction(&worhp_c_, evalG)) { eval_g(worhp_o_.X, worhp_o_.G); DoneUserAction(&worhp_c_, evalG); } if (GetUserAction(&worhp_c_, evalDF)) { eval_grad_f(worhp_o_.X, worhp_w_.ScaleObj, worhp_w_.DF.val); DoneUserAction(&worhp_c_, evalDF); } if (GetUserAction(&worhp_c_, evalDG)) { eval_jac_g(worhp_o_.X,worhp_w_.DG.val); DoneUserAction(&worhp_c_, evalDG); } if (GetUserAction(&worhp_c_, evalHM)) { eval_h(worhp_o_.X, worhp_w_.ScaleObj, worhp_o_.Mu, worhp_w_.HM.val); DoneUserAction(&worhp_c_, evalHM); } if (GetUserAction(&worhp_c_, fidif)) { WorhpFidif(&worhp_o_, &worhp_w_, &worhp_p_, &worhp_c_); } } double time2 = clock(); t_mainloop_ += double(time2-time1)/CLOCKS_PER_SEC; // Copy outputs output(NLP_SOLVER_X).setArray(worhp_o_.X,worhp_o_.n,DENSE); output(NLP_SOLVER_F).set(worhp_o_.F); output(NLP_SOLVER_G).setArray(worhp_o_.G,worhp_o_.m,DENSE); output(NLP_SOLVER_LAM_X).setArray(worhp_o_.Lambda,worhp_o_.n); output(NLP_SOLVER_LAM_G).setArray(worhp_o_.Mu,worhp_o_.m,DENSE); StatusMsg(&worhp_o_, &worhp_w_, &worhp_p_, &worhp_c_); if (hasOption("print_time") && bool(getOption("print_time"))) { // Write timings cout << "time spent in eval_f: " << t_eval_f_ << " s."; if (n_eval_f_>0) cout << " (" << n_eval_f_ << " calls, " << (t_eval_f_/n_eval_f_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_grad_f: " << t_eval_grad_f_ << " s."; if (n_eval_grad_f_>0) cout << " (" << n_eval_grad_f_ << " calls, " << (t_eval_grad_f_/n_eval_grad_f_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_g: " << t_eval_g_ << " s."; if (n_eval_g_>0) cout << " (" << n_eval_g_ << " calls, " << (t_eval_g_/n_eval_g_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_jac_g: " << t_eval_jac_g_ << " s."; if (n_eval_jac_g_>0) cout << " (" << n_eval_jac_g_ << " calls, " << (t_eval_jac_g_/n_eval_jac_g_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_h: " << t_eval_h_ << " s."; if (n_eval_h_>1) cout << " (" << n_eval_h_ << " calls, " << (t_eval_h_/n_eval_h_)*1000 << " ms. average)"; cout << endl; cout << "time spent in main loop: " << t_mainloop_ << " s." << endl; cout << "time spent in callback function: " << t_callback_fun_ << " s." << endl; cout << "time spent in callback preparation: " << t_callback_prepare_ << " s." << endl; } stats_["t_eval_f"] = t_eval_f_; stats_["t_eval_grad_f"] = t_eval_grad_f_; stats_["t_eval_g"] = t_eval_g_; stats_["t_eval_jac_g"] = t_eval_jac_g_; stats_["t_eval_h"] = t_eval_h_; stats_["t_mainloop"] = t_mainloop_; stats_["t_callback_fun"] = t_callback_fun_; stats_["t_callback_prepare"] = t_callback_prepare_; stats_["n_eval_f"] = n_eval_f_; stats_["n_eval_grad_f"] = n_eval_grad_f_; stats_["n_eval_g"] = n_eval_g_; stats_["n_eval_jac_g"] = n_eval_jac_g_; stats_["n_eval_h"] = n_eval_h_; stats_["iter_count"] = worhp_w_.MajorIter; stats_["return_code"] = worhp_c_.status; stats_["return_status"] = flagmap[worhp_c_.status]; }
void IpoptInternal::evaluate(){ if (inputs_check_) checkInputs(); checkInitialBounds(); if (gather_stats_) { Dictionary iterations; iterations["inf_pr"] = std::vector<double>(); iterations["inf_du"] = std::vector<double>(); iterations["mu"] = std::vector<double>(); iterations["d_norm"] = std::vector<double>(); iterations["regularization_size"] = std::vector<double>(); iterations["obj"] = std::vector<double>(); iterations["ls_trials"] = std::vector<int>(); iterations["alpha_pr"] = std::vector<double>(); iterations["alpha_du"] = std::vector<double>(); iterations["obj"] = std::vector<double>(); stats_["iterations"] = iterations; } // Reset the counters t_eval_f_ = t_eval_grad_f_ = t_eval_g_ = t_eval_jac_g_ = t_eval_h_ = t_callback_fun_ = t_callback_prepare_ = t_mainloop_ = 0; n_eval_f_ = n_eval_grad_f_ = n_eval_g_ = n_eval_jac_g_ = n_eval_h_ = n_iter_ = 0; // Get back the smart pointers Ipopt::SmartPtr<Ipopt::TNLP> *userclass = static_cast<Ipopt::SmartPtr<Ipopt::TNLP>*>(userclass_); Ipopt::SmartPtr<Ipopt::IpoptApplication> *app = static_cast<Ipopt::SmartPtr<Ipopt::IpoptApplication>*>(app_); double time1 = clock(); // Ask Ipopt to solve the problem Ipopt::ApplicationReturnStatus status = (*app)->OptimizeTNLP(*userclass); double time2 = clock(); t_mainloop_ = double(time2-time1)/CLOCKS_PER_SEC; #ifdef WITH_SIPOPT if(run_sens_ || compute_red_hessian_){ // Calculate parametric sensitivities Ipopt::SmartPtr<Ipopt::SensApplication> *app_sens = static_cast<Ipopt::SmartPtr<Ipopt::SensApplication>*>(app_sens_); (*app_sens)->SetIpoptAlgorithmObjects(*app, status); (*app_sens)->Run(); // Access the reduced Hessian calculator #ifdef WITH_CASADI_PATCH if(compute_red_hessian_){ // Get the reduced Hessian std::vector<double> red_hess = (*app_sens)->ReducedHessian(); // Get the dimensions int N; for(N=0; N*N<red_hess.size(); ++N); casadi_assert(N*N==red_hess.size()); // Store to statistics red_hess_ = DMatrix(Sparsity::dense(N,N),red_hess); } #endif // WITH_CASADI_PATCH } #endif // WITH_SIPOPT if (hasOption("print_time") && bool(getOption("print_time"))) { // Write timings cout << "time spent in eval_f: " << t_eval_f_ << " s."; if (n_eval_f_>0) cout << " (" << n_eval_f_ << " calls, " << (t_eval_f_/n_eval_f_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_grad_f: " << t_eval_grad_f_ << " s."; if (n_eval_grad_f_>0) cout << " (" << n_eval_grad_f_ << " calls, " << (t_eval_grad_f_/n_eval_grad_f_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_g: " << t_eval_g_ << " s."; if (n_eval_g_>0) cout << " (" << n_eval_g_ << " calls, " << (t_eval_g_/n_eval_g_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_jac_g: " << t_eval_jac_g_ << " s."; if (n_eval_jac_g_>0) cout << " (" << n_eval_jac_g_ << " calls, " << (t_eval_jac_g_/n_eval_jac_g_)*1000 << " ms. average)"; cout << endl; cout << "time spent in eval_h: " << t_eval_h_ << " s."; if (n_eval_h_>1) cout << " (" << n_eval_h_ << " calls, " << (t_eval_h_/n_eval_h_)*1000 << " ms. average)"; cout << endl; cout << "time spent in main loop: " << t_mainloop_ << " s." << endl; cout << "time spent in callback function: " << t_callback_fun_ << " s." << endl; cout << "time spent in callback preparation: " << t_callback_prepare_ << " s." << endl; } if (status == Solve_Succeeded) stats_["return_status"] = "Solve_Succeeded"; if (status == Solved_To_Acceptable_Level) stats_["return_status"] = "Solved_To_Acceptable_Level"; if (status == Infeasible_Problem_Detected) stats_["return_status"] = "Infeasible_Problem_Detected"; if (status == Search_Direction_Becomes_Too_Small) stats_["return_status"] = "Search_Direction_Becomes_Too_Small"; if (status == Diverging_Iterates) stats_["return_status"] = "Diverging_Iterates"; if (status == User_Requested_Stop) stats_["return_status"] = "User_Requested_Stop"; if (status == Maximum_Iterations_Exceeded) stats_["return_status"] = "Maximum_Iterations_Exceeded"; if (status == Restoration_Failed) stats_["return_status"] = "Restoration_Failed"; if (status == Error_In_Step_Computation) stats_["return_status"] = "Error_In_Step_Computation"; if (status == Not_Enough_Degrees_Of_Freedom) stats_["return_status"] = "Not_Enough_Degrees_Of_Freedom"; if (status == Invalid_Problem_Definition) stats_["return_status"] = "Invalid_Problem_Definition"; if (status == Invalid_Option) stats_["return_status"] = "Invalid_Option"; if (status == Invalid_Number_Detected) stats_["return_status"] = "Invalid_Number_Detected"; if (status == Unrecoverable_Exception) stats_["return_status"] = "Unrecoverable_Exception"; if (status == NonIpopt_Exception_Thrown) stats_["return_status"] = "NonIpopt_Exception_Thrown"; if (status == Insufficient_Memory) stats_["return_status"] = "Insufficient_Memory"; stats_["t_eval_f"] = t_eval_f_; stats_["t_eval_grad_f"] = t_eval_grad_f_; stats_["t_eval_g"] = t_eval_g_; stats_["t_eval_jac_g"] = t_eval_jac_g_; stats_["t_eval_h"] = t_eval_h_; stats_["t_mainloop"] = t_mainloop_; stats_["t_callback_fun"] = t_callback_fun_; stats_["t_callback_prepare"] = t_callback_prepare_; stats_["n_eval_f"] = n_eval_f_; stats_["n_eval_grad_f"] = n_eval_grad_f_; stats_["n_eval_g"] = n_eval_g_; stats_["n_eval_jac_g"] = n_eval_jac_g_; stats_["n_eval_h"] = n_eval_h_; stats_["iter_count"] = n_iter_-1; }