1 // Copyright (C) 2004, 2006 International Business Machines and others.
2 // All Rights Reserved.
3 // This code is published under the Common Public License.
4 //
5 // $Id: IpOptErrorConvCheck.cpp 759 2006-07-07 03:07:08Z andreasw $
6 //
7 // Authors:  Carl Laird, Andreas Waechter     IBM    2004-08-13
8 
9 #include "IpOptErrorConvCheck.hpp"
10 
11 namespace SimTKIpopt
12 {
13 #ifdef IP_DEBUG
14   static const Index dbg_verbosity = 0;
15 #endif
16 
OptimalityErrorConvergenceCheck()17   OptimalityErrorConvergenceCheck::OptimalityErrorConvergenceCheck()
18   {}
19 
~OptimalityErrorConvergenceCheck()20   OptimalityErrorConvergenceCheck::~OptimalityErrorConvergenceCheck()
21   {}
22 
RegisterOptions(SmartPtr<RegisteredOptions> roptions)23   void OptimalityErrorConvergenceCheck::RegisterOptions(SmartPtr<RegisteredOptions> roptions)
24   {
25     roptions->AddLowerBoundedIntegerOption(
26       "max_iter",
27       "Maximum number of iterations.",
28       0, 3000,
29       "The algorithm terminates with an error message if the number of "
30       "iterations exceeded this number.");
31     roptions->AddLowerBoundedNumberOption(
32       "dual_inf_tol",
33       "Desired threshold for the dual infeasibility.",
34       0.0, true, 1e-4,
35       "Absolute tolerance on the dual infeasibility. Successful termination "
36       "requires that the max-norm of the (unscaled) dual infeasibility is less than this "
37       "threshold.");
38     roptions->AddLowerBoundedNumberOption(
39       "constr_viol_tol",
40       "Desired threshold for the constraint violation.",
41       0.0, true, 1e-4,
42       "Absolute tolerance on the constraint violation. Successful termination "
43       "requires that the max-norm of the (unscaled) constraint violation is less than this "
44       "threshold.");
45     roptions->AddLowerBoundedNumberOption(
46       "compl_inf_tol",
47       "Desired threshold for the complementarity conditions.",
48       0.0, true, 1e-4,
49       "Absolute tolerance on the complementarity. Successful termination "
50       "requires that the max-norm of the (unscaled) complementarity is less than this "
51       "threshold.");
52     roptions->AddLowerBoundedNumberOption(
53       "acceptable_tol",
54       "\"Acceptable\" convergence tolerance (relative).",
55       0.0, true,  1e-6,
56       "Determines which (scaled) overall optimality error is considered to be"
57       " \"acceptable.\" There are two levels of termination criteria.  If the "
58       "usual \"desired\" tolerances (see tol, dual_inf_tol etc) are satisfied "
59       "at an iteration, the algorithm immediately terminates with a success "
60       "message.  On the other hand, if the algorithm encounters "
61       "\"acceptable_iter\" many iterations in a row that are considered "
62       "\"acceptable\", it will terminate before the desired convergence "
63       "tolerance is met. This is useful in cases where the algorithm might "
64       "not be able to achieve the \"desired\" level of accuracy.");
65     roptions->AddLowerBoundedIntegerOption(
66       "acceptable_iter",
67       "Number of \"acceptable\" iterates before triggering termination.",
68       0, 15,
69       "If the algorithm encounters this many successive \"acceptable\" iterates "
70       "(see \"acceptable_tol\"), it terminates, assuming that the problem "
71       "has been solved to best possible accuracy given round-off.  If it is "
72       "set to zero, this heuristic is disabled.");
73     roptions->AddLowerBoundedNumberOption(
74       "acceptable_dual_inf_tol",
75       "\"Acceptance\" threshold for the dual infeasibility.",
76       0.0, true, 1e-2,
77       "Absolute tolerance on the dual infeasibility. \"Acceptable\" termination "
78       "requires that the (max-norm of the unscaled) dual infeasibility is less than this "
79       "threshold; see also acceptable_tol.");
80     roptions->AddLowerBoundedNumberOption(
81       "acceptable_constr_viol_tol",
82       "\"Acceptance\" threshold for the constraint violation.",
83       0.0, true, 1e-2,
84       "Absolute tolerance on the constraint violation. \"Acceptable\" termination "
85       "requires that the max-norm of the (unscaled) constraint violation is less than this "
86       "threshold; see also acceptable_tol.");
87     roptions->AddLowerBoundedNumberOption(
88       "acceptable_compl_inf_tol",
89       "\"Acceptance\" threshold for the complementarity conditions.",
90       0.0, true, 1e-2,
91       "Absolute tolerance on the complementarity. \"Acceptable\" termination "
92       "requires that the max-norm of the (unscaled) complementarity is less than this "
93       "threshold; see also acceptable_tol.");
94     roptions->AddLowerBoundedNumberOption(
95       "diverging_iterates_tol",
96       "Threshold for maximal value of primal iterates.",
97       0.0, true, 1e20,
98       "If any component of the primal iterates exceeded this value (in "
99       "absolute terms), the optimization is aborted with the exit message "
100       "that the iterates seem to be diverging.");
101   }
102 
103   bool
InitializeImpl(const OptionsList & options,const std::string & prefix)104   OptimalityErrorConvergenceCheck::InitializeImpl(const OptionsList& options,
105       const std::string& prefix)
106   {
107     options.GetIntegerValue("max_iter", max_iterations_, prefix);
108     options.GetNumericValue("dual_inf_tol", dual_inf_tol_, prefix);
109     options.GetNumericValue("constr_viol_tol", constr_viol_tol_, prefix);
110     options.GetNumericValue("compl_inf_tol", compl_inf_tol_, prefix);
111     options.GetIntegerValue("acceptable_iter", acceptable_iter_, prefix);
112     options.GetNumericValue("acceptable_tol", acceptable_tol_, prefix);
113     options.GetNumericValue("acceptable_dual_inf_tol", acceptable_dual_inf_tol_, prefix);
114     options.GetNumericValue("acceptable_constr_viol_tol", acceptable_constr_viol_tol_, prefix);
115     options.GetNumericValue("acceptable_compl_inf_tol", acceptable_compl_inf_tol_, prefix);
116     options.GetNumericValue("diverging_iterates_tol", diverging_iterates_tol_, prefix);
117     acceptable_counter_ = 0;
118 
119     return true;
120   }
121 
122   ConvergenceCheck::ConvergenceStatus
CheckConvergence(bool call_intermediate_callback)123   OptimalityErrorConvergenceCheck::CheckConvergence(bool call_intermediate_callback /*= true*/)
124   {
125     DBG_START_METH("OptimalityErrorConvergenceCheck::CheckConvergence", dbg_verbosity);
126 
127     if (call_intermediate_callback) {
128       // Check if user requested termination by calling the intermediate
129       // user callback function
130       AlgorithmMode mode = RegularMode;
131       // Gather the information also used in the iteration output
132       Index iter = IpData().iter_count();
133       Number inf_pr = IpCq().curr_primal_infeasibility(NORM_MAX);
134       Number inf_du = IpCq().curr_dual_infeasibility(NORM_MAX);
135       Number mu = IpData().curr_mu();
136       Number dnrm;
137       if (IsValid(IpData().delta()) && IsValid(IpData().delta()->x()) && IsValid(IpData().delta()->s())) {
138         dnrm = Max(IpData().delta()->x()->Amax(), IpData().delta()->s()->Amax());
139       }
140       else {
141         // This is the first iteration - no search direction has been
142         // computed yet.
143         dnrm = 0.;
144       }
145       Number alpha_primal = IpData().info_alpha_primal();
146       Number alpha_dual = IpData().info_alpha_dual();
147       Number regu_x = IpData().info_regu_x();
148       Number unscaled_f = IpCq().unscaled_curr_f();
149       Index ls_count = IpData().info_ls_count();
150       bool request_stop =
151         !IpNLP().IntermediateCallBack(mode, iter, unscaled_f, inf_pr, inf_du,
152                                       mu, dnrm, regu_x, alpha_dual,
153                                       alpha_primal, ls_count,
154                                       &IpData(), &IpCq());
155 
156       if (request_stop) {
157         return ConvergenceCheck::USER_STOP;
158       }
159     }
160 
161     if (IpData().iter_count() >= max_iterations_) {
162       return ConvergenceCheck::MAXITER_EXCEEDED;
163     }
164 
165     Number overall_error = IpCq().curr_nlp_error();
166     Number dual_inf = IpCq().unscaled_curr_dual_infeasibility(NORM_MAX);
167     Number constr_viol = IpCq().unscaled_curr_nlp_constraint_violation(NORM_MAX);
168     Number compl_inf = IpCq().unscaled_curr_complementarity(0., NORM_MAX);
169 
170     if (IpData().curr()->x()->Dim()==IpData().curr()->y_c()->Dim()) {
171       // the problem is square, there is no point in looking at dual
172       // infeasibility and complementarity as termination criterion
173       dual_inf_tol_ = 1e300;
174       compl_inf_tol_ = 1e300;
175     }
176 
177     if (overall_error <= IpData().tol() &&
178         dual_inf <= dual_inf_tol_ &&
179         constr_viol <= constr_viol_tol_ &&
180         compl_inf <= compl_inf_tol_) {
181       return ConvergenceCheck::CONVERGED;
182     }
183 
184     if (acceptable_iter_>0 && CurrentIsAcceptable()) {
185       IpData().Append_info_string("A");
186       acceptable_counter_++;
187       if (acceptable_counter_ >= acceptable_iter_) {
188         return ConvergenceCheck::CONVERGED_TO_ACCEPTABLE_POINT;
189       }
190     }
191     else {
192       acceptable_counter_ = 0;
193     }
194 
195     if (IpData().curr()->x()->Amax() > diverging_iterates_tol_) {
196       return ConvergenceCheck::DIVERGING;
197     }
198 
199     return ConvergenceCheck::CONTINUE;
200   }
201 
CurrentIsAcceptable()202   bool OptimalityErrorConvergenceCheck::CurrentIsAcceptable()
203   {
204     DBG_START_METH("OptimalityErrorConvergenceCheck::CurrentIsAcceptable",
205                    dbg_verbosity);
206 
207     Number overall_error = IpCq().curr_nlp_error();
208     Number dual_inf = IpCq().unscaled_curr_dual_infeasibility(NORM_MAX);
209     Number constr_viol = IpCq().unscaled_curr_nlp_constraint_violation(NORM_MAX);
210     Number compl_inf = IpCq().unscaled_curr_complementarity(0., NORM_MAX);
211 
212     DBG_PRINT((1, "overall_error = %e\n", overall_error));
213     DBG_PRINT((1, "dual_inf = %e\n", dual_inf));
214     DBG_PRINT((1, "constr_viol = %e\n", constr_viol));
215     DBG_PRINT((1, "compl_inf = %e\n", compl_inf));
216 
217     DBG_PRINT((1, "acceptable_tol_ = %e\n", acceptable_tol_));
218     DBG_PRINT((1, "acceptable_dual_inf_tol_ = %e\n", acceptable_dual_inf_tol_));
219     DBG_PRINT((1, "acceptable_constr_viol_tol_ = %e\n", acceptable_constr_viol_tol_));
220     DBG_PRINT((1, "acceptable_compl_inf_tol_ = %e\n", acceptable_compl_inf_tol_));
221 
222     if (IpData().curr()->x()->Dim()==IpData().curr()->y_c()->Dim()) {
223       // the problem is square, there is no point in looking at dual
224       // infeasibility and complementarity as termination criterion
225       acceptable_dual_inf_tol_ = 1e300;
226       acceptable_compl_inf_tol_ = 1e300;
227     }
228 
229     return (overall_error <= acceptable_tol_ &&
230             dual_inf <= acceptable_dual_inf_tol_ &&
231             constr_viol <= acceptable_constr_viol_tol_ &&
232             compl_inf <= acceptable_compl_inf_tol_);
233   }
234 
235 
236 } // namespace Ipopt
237