From 49a0d3a56e95d117afb2c1f0cab8c2995d786193 Mon Sep 17 00:00:00 2001 From: Stefan Vigerske Date: Tue, 23 Mar 2021 15:06:44 +0100 Subject: [PATCH] allow original NLPs without free variables - do not catch this case in TNLPAdapter, but let Ipopt initialize all its structures and detect optimality/infeasibility in the convergence check - this way, we get a proper solution report and statistics (ref #417) - get rid of NO_FREE_VARIABLES_... exceptions --- src/Algorithm/IpOptErrorConvCheck.cpp | 7 +++ src/Algorithm/IpOrigIpoptNLP.cpp | 1 - src/Interfaces/IpAlgTypes.hpp | 2 - src/Interfaces/IpIpoptApplication.cpp | 16 ------ src/Interfaces/IpTNLPAdapter.cpp | 82 --------------------------- 5 files changed, 7 insertions(+), 101 deletions(-) diff --git a/src/Algorithm/IpOptErrorConvCheck.cpp b/src/Algorithm/IpOptErrorConvCheck.cpp index d8a25982a..0ad0cc686 100644 --- a/src/Algorithm/IpOptErrorConvCheck.cpp +++ b/src/Algorithm/IpOptErrorConvCheck.cpp @@ -227,6 +227,13 @@ ConvergenceCheck::ConvergenceStatus OptimalityErrorConvergenceCheck::CheckConver return ConvergenceCheck::CONVERGED; } + if( IpData().curr()->x()->Dim() == 0 ) + { + if( constr_viol <= constr_viol_tol_ ) + return ConvergenceCheck::CONVERGED; + THROW_EXCEPTION(LOCALLY_INFEASIBLE, "All variables are fixed and constraint violation is above tolerance. The problem is infeasible."); + } + if( acceptable_iter_ > 0 && CurrentIsAcceptable() ) { IpData().Append_info_string("A"); diff --git a/src/Algorithm/IpOrigIpoptNLP.cpp b/src/Algorithm/IpOrigIpoptNLP.cpp index 75c035f63..a7941831a 100644 --- a/src/Algorithm/IpOrigIpoptNLP.cpp +++ b/src/Algorithm/IpOrigIpoptNLP.cpp @@ -296,7 +296,6 @@ bool OrigIpoptNLP::InitializeStructures( c_space_->Dim(), x_space_->Dim()); THROW_EXCEPTION(TOO_FEW_DOF, msg); } - ASSERT_EXCEPTION(x_space_->Dim() > 0, TOO_FEW_DOF, "Too few degrees of freedom (no free variables)!"); // cannot have any null pointers, want zero length vectors // instead of null - this will later need to be changed for _h; diff --git a/src/Interfaces/IpAlgTypes.hpp b/src/Interfaces/IpAlgTypes.hpp index 39fe7a7b3..51a341397 100644 --- a/src/Interfaces/IpAlgTypes.hpp +++ b/src/Interfaces/IpAlgTypes.hpp @@ -47,8 +47,6 @@ DECLARE_STD_EXCEPTION(ACCEPTABLE_POINT_REACHED); DECLARE_STD_EXCEPTION(FEASIBILITY_PROBLEM_SOLVED); DECLARE_STD_EXCEPTION(INVALID_WARMSTART); DECLARE_STD_EXCEPTION(INTERNAL_ABORT); -DECLARE_STD_EXCEPTION(NO_FREE_VARIABLES_BUT_FEASIBLE); -DECLARE_STD_EXCEPTION(NO_FREE_VARIABLES_AND_INFEASIBLE); DECLARE_STD_EXCEPTION(INCONSISTENT_BOUNDS); /** Exception FAILED_INITIALIZATION for problem during * initialization of a strategy object (or other problems). diff --git a/src/Interfaces/IpIpoptApplication.cpp b/src/Interfaces/IpIpoptApplication.cpp index 287a85106..1d7fb9f78 100644 --- a/src/Interfaces/IpIpoptApplication.cpp +++ b/src/Interfaces/IpIpoptApplication.cpp @@ -1131,22 +1131,6 @@ ApplicationReturnStatus IpoptApplication::call_optimize() retValue = Invalid_Option; status = INVALID_OPTION; } - catch( NO_FREE_VARIABLES_BUT_FEASIBLE& exc ) - { - exc.ReportException(*jnlst_, J_MOREDETAILED); - jnlst_->Printf(J_SUMMARY, J_MAIN, "\nEXIT: Optimal Solution Found.\n"); - retValue = Solve_Succeeded; - status = SUCCESS; - skip_finalize_solution_call = true; /* has already been called by TNLPAdapter (and we don't know the correct primal solution) */ - } - catch( NO_FREE_VARIABLES_AND_INFEASIBLE& exc ) - { - exc.ReportException(*jnlst_, J_MOREDETAILED); - jnlst_->Printf(J_SUMMARY, J_MAIN, "\nEXIT: Problem has only fixed variables and constraints are infeasible.\n"); - retValue = Infeasible_Problem_Detected; - status = LOCAL_INFEASIBILITY; - skip_finalize_solution_call = true; /* has already been called by TNLPAdapter (and we don't know the correct primal solution) */ - } catch( INCONSISTENT_BOUNDS& exc ) { exc.ReportException(*jnlst_, J_MOREDETAILED); diff --git a/src/Interfaces/IpTNLPAdapter.cpp b/src/Interfaces/IpTNLPAdapter.cpp index 7da83d1a5..510064d43 100644 --- a/src/Interfaces/IpTNLPAdapter.cpp +++ b/src/Interfaces/IpTNLPAdapter.cpp @@ -605,88 +605,6 @@ bool TNLPAdapter::GetSpaces( } } // while (!done) - if( n_x_var == 0 ) - { - // Check of all constraints are satisfied: - for( Index i = 0; i < n_full_x_; i++ ) - { - DBG_ASSERT(x_l[i] == x_u[i]); - full_x_[i] = x_l[i]; - } - bool retval = tnlp_->eval_g(n_full_x_, full_x_, true, n_full_g_, full_g_); - ASSERT_EXCEPTION(retval, IpoptNLP::Eval_Error, - "All variables are fixed, but constraints cannot be evaluated at fixed point."); - Number max_viol = 0.; - for( Index i = 0; i < n_full_g_; i++ ) - { - //printf("%d %23.16e %23.16e %23.16e\n",i,full_g_[i], g_l[i], g_u[i]); - max_viol = Max(max_viol, full_g_[i] - g_u[i], g_l[i] - full_g_[i]); - } - - SolverReturn status; - if( max_viol <= tol_ ) //ToDo: base also on (acceptable) (constraint violation) tolerance - { - status = SUCCESS; - } - else - { - status = LOCAL_INFEASIBILITY; - } - - Number obj_value; - retval = tnlp_->eval_f(n_full_x_, full_x_, false, obj_value); - ASSERT_EXCEPTION(retval, IpoptNLP::Eval_Error, - "All variables are fixed, but objective cannot be evaluated at fixed point."); - // Call finalize_solution so that user has required information - Number* full_z_L = new Number[n_full_x_]; - Number* full_z_U = new Number[n_full_x_]; - Number* full_lambda = new Number[n_full_g_]; - // For now, we return zeros as multipliers... (ToDo?) - const Number zero = 0.; - IpBlasCopy(n_full_x_, &zero, 0, full_z_L, 1); - IpBlasCopy(n_full_x_, &zero, 0, full_z_U, 1); - IpBlasCopy(n_full_g_, &zero, 0, full_lambda, 1); - tnlp_->finalize_solution(status, n_full_x_, full_x_, full_z_L, full_z_U, n_full_g_, full_g_, full_lambda, - obj_value, NULL, NULL); - delete[] full_z_L; - delete[] full_z_U; - delete[] full_lambda; - - // Free memory - delete[] x_not_fixed_map; - delete[] x_l_map; - delete[] x_u_map; - delete[] c_map; - delete[] d_map; - delete[] d_l_map; - delete[] d_u_map; - delete[] x_l; - delete[] x_u; - delete[] g_l; - delete[] g_u; - - // NOTE: we have passed the primal solution to the user, but not to Ipopt - // that is, Ipopt's data object still holds none or another solution - // However, since IpoptApplication will not call finalize_solution with this point if - // it gets a NO_FREE_VARIABLES_* exception, this should be good enough. - char string[128]; - Snprintf(string, 127, "All variables are fixed, and constraint violation is %e", max_viol); - if( status == SUCCESS ) - { - jnlst_->Printf(J_WARNING, J_INITIALIZATION, - "All variables are fixed and constraint violation %e\n is below tolerance %e. Declaring success.\n", - max_viol, tol_); - THROW_EXCEPTION(NO_FREE_VARIABLES_BUT_FEASIBLE, string); - } - else - { - jnlst_->Printf(J_WARNING, J_INITIALIZATION, - "All variables are fixed and constraint violation %e\n is above tolerance %e. Declaring that problem is infeasible.\n", - max_viol, tol_); - THROW_EXCEPTION(NO_FREE_VARIABLES_AND_INFEASIBLE, string); - } - } - // If requested, check if there are linearly dependent equality // constraints if( n_c > 0 && IsValid(dependency_detector_) )