Skip to content

Commit

Permalink
sol:chk:round, :prec #200
Browse files Browse the repository at this point in the history
We cannot AMPL's settings for solution_round and solution_precision, so need own options

Added Motivation section in docu (thanks Dave)
  • Loading branch information
glebbelov committed Sep 19, 2023
1 parent d8afa4f commit a88e8ee
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 43 deletions.
80 changes: 62 additions & 18 deletions doc/rst/solution-check.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,61 @@ a tolerance. In "idealistic" mode, all expression trees
are recomputed.


Motivation
**********************

Consider the disjunction constraint

.. code-block:: ampl
C: y<=6 or z>=10;
With ``y=6.0000000001`` and ``z=9.9999999999``, and assuming the solver's
feasibility tolerance is at a typical value (such as :math:`10^{-6}`),
most Mathematical Programming solvers consider the disjunction satisfied.
And, from a practical viewpoint, it is (given finite-precision
computations).

Our "realistic" checking mode does exactly this: it trusts the solver results
up to a tolerance.

In contrast, AMPL reports the constraint violated:

.. code-block:: ampl
ampl: let y:=6.0000000001;
ampl: let z:=9.9999999999;
ampl: display C.val;
C.val = 0
That is, when expressions ``y<=6`` and ``z>=10`` are re-evaluated
and their results substituted into ``C``, ``C`` holds false.

The role of the "idealistic" checking mode is to warn the user about the fact,
that even if the solver has a correct solution up to its tolerances
(which is examined by the "realistic" mode),
it can be wrong for a tolerance-unaware checker.

By default, "idealistic" check is performed for objective values only,
see example below. To enable it for constraints, use
:ref:`option <solver-options>` ``chk:mode``.



"Realistic" solution check
******************************

In this mode, variable values are taken as they were reported by the solver
(with possible modifications using AMPL's options
``solution_round`` and ``solution_precision``, see driver options
``sol:chk:no...``.). This check is enough for most practical situations.
(with possible modifications via options
``sol:chk:round`` and ``sol:chk:prec``.)
This check is enough for most practical situations.

.. code-block:: ampl
------------ WARNINGS ------------
WARNING: "Solution Check"
[ sol:chk:feastol=1e-06, sol:chk:inttol=1e-05,
solution_round='', solution_precision='' ]
[ sol:chk:feastol=1e-06, :feastolrel=1e-06, :inttol=1e-05,
:round='', :prec='' ]
Algebraic expression violations:
- 1 original expression(s) of type ':quadrange',
up to 1E+00 (item 'socp[13]')
Expand Down Expand Up @@ -70,11 +111,12 @@ Most solvers apply a constraint feasibility tolerance of the order :math:`10^{-6
------------ WARNINGS ------------
WARNING: "Solution Check (Idealistic)"
[ sol:chk:feastol=1e-06, sol:chk:inttol=1e-05,
solution_round='', solution_precision='' ]
[ sol:chk:feastol=1e-06, :feastolrel=1e-06, :inttol=1e-05,
:round='', :prec='' ]
Objective value violations:
- 1 objective value(s) violated,
up to 1E+01
up to 1E+01 (abs)
Idealistic check is an indicator only, see documentation.
ampl: display x;
x = 5
Expand Down Expand Up @@ -105,16 +147,17 @@ use driver option ``chk:mode``:
------------ WARNINGS ------------
WARNING: "Solution Check (Idealistic)"
[ sol:chk:feastol=1e-06, sol:chk:inttol=1e-05,
solution_round='', solution_precision='' ]
[ sol:chk:feastol=1e-06, :feastolrel=1e-06, :inttol=1e-05,
:round='', :prec='' ]
Algebraic expression violations:
- 1 original expression(s) of type ':ifthen',
up to 1E+01
up to 1E+01 (abs)
Logical expression violations:
- 1 original expression(s) of type ':and'
Objective value violations:
- 1 objective value(s) violated,
up to 1E+01
up to 1E+01 (abs)
Idealistic check is an indicator only, see documentation.
*Hint*: to display AMPL model names,
set ``option (solver_)auxfiles rc;`` as follows:
Expand All @@ -129,17 +172,18 @@ set ``option (solver_)auxfiles rc;`` as follows:
------------ WARNINGS ------------
WARNING: "Solution Check (Idealistic)"
[ sol:chk:feastol=1e-06, sol:chk:inttol=1e-05,
solution_round='', solution_precision='' ]
[ sol:chk:feastol=1e-06, :feastolrel=1e-06, :inttol=1e-05,
:round='', :prec='' ]
Algebraic expression violations:
- 1 original expression(s) of type ':ifthen',
up to 1E+01 (item 'Total_11_')
up to 1E+01 (abs, item 'Total_11_')
Logical expression violations:
- 1 original expression(s) of type ':and'
(item 'Total_7_')
- 1 original expression(s) of type ':and',
(item 'Total_7_')
Objective value violations:
- 1 objective value(s) violated,
up to 1E+01 (item 'Total')
up to 1E+01 (abs, item 'Total')
Idealistic check is an indicator only, see documentation.
Remedies
Expand Down
14 changes: 7 additions & 7 deletions include/mp/flat/constr_keeper.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class VarInfoImpl {
ArrayRef<double> x_raw,
ArrayRef<var::Type> type,
ArrayRef<double> lb, ArrayRef<double> ub,
const char* sol_rnd, const char* sol_prec)
int sol_rnd, int sol_prec)
: feastol_(ft), recomp_vals_(recomp_vals),
x_(std::move(x)), x_raw_(x_raw),
type_(type), lb_(lb), ub_(ub) {
Expand Down Expand Up @@ -200,19 +200,19 @@ class VarInfoImpl {

protected:
void apply_precision_options(
const char* sol_rnd, const char* sol_prec) {
int sol_rnd, int sol_prec) {
try { // Apply sol_rnd
if (sol_rnd) {
sol_rnd_ = std::stoi(sol_rnd);
if (sol_rnd<100) {
sol_rnd_ = (sol_rnd);
auto scale = std::pow(10, sol_rnd_);
auto scale_rec = 1.0/scale;
for (auto& x: x_)
x = std::round(x * scale) * scale_rec;
}
} catch (...) { sol_rnd_=100; } // Could add a warning
try { // Apply sol_prec
if (sol_prec) {
sol_prec_ = std::stoi(sol_prec);
if (sol_prec<100) {
sol_prec_ = (sol_prec);
for (auto& x: x_)
x = round_to_digits(x, sol_prec_);
}
Expand Down Expand Up @@ -258,7 +258,7 @@ struct SolCheck {
ArrayRef<var::Type> vtype,
ArrayRef<double> lb, ArrayRef<double> ub,
double feastol, double feastolrel,
const char* sol_rnd, const char* sol_prec,
int sol_rnd, int sol_prec,
bool recomp_vals, int chk_mode)
: x_(feastol, recomp_vals,
x, x_raw, vtype, lb, ub, sol_rnd, sol_prec),
Expand Down
37 changes: 19 additions & 18 deletions include/mp/flat/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ class FlatConverter :
GetModel().var_type_vec(),
GetModel().var_lb_vec(),
GetModel().var_ub_vec(),
nullptr, nullptr
options_.sol_round_, options_.sol_prec_
};
vir.get_x().set_p_var_info(&vir);
for (auto i=vir.size(); i--; )
Expand All @@ -698,10 +698,8 @@ class FlatConverter :
GetModel().var_ub_vec(),
options_.solfeastol_,
options_.solfeastolrel_,
options_.dont_use_sol_round_
? "" : std::getenv("solution_round"),
options_.dont_use_sol_prec_
? "" : std::getenv("solution_precision"),
options_.sol_round_,
options_.sol_prec_,
if_recomp_vals,
if_recomp_vals
? (options_.solcheckmode_ >> 5)
Expand All @@ -720,7 +718,7 @@ class FlatConverter :
// Should be fine - warning by default,
// fail if requested explicitly.
// If warning, we should add the report
// to that solutions' solve message, and
// to that solution's solve message, and
// a summary in the final solve message.
// For now, do this via warnings?
if (chk.HasAnyViols()) {
Expand Down Expand Up @@ -787,7 +785,7 @@ class FlatConverter :
if (chk.HasAnyViols())
wrt.write(
" [ sol:chk:feastol={}, :feastolrel={}, :inttol={},\n"
" solution_round='{}', solution_precision='{}' ]\n",
" :round='{}', :prec='{}' ]\n",
options_.solfeastol_, options_.solfeastolrel_,
options_.solinttol_,
chk.x_ext().solution_round(),
Expand Down Expand Up @@ -1183,8 +1181,8 @@ class FlatConverter :
double solfeastol_ = 1e-6;
double solfeastolrel_ = 1e-6;
double solinttol_ = 1e-5;
bool dont_use_sol_round_ = false;
bool dont_use_sol_prec_ = false;
int sol_round_ = 100;
int sol_prec_ = 100;
int solchkoutlev_ = 0;
};
Options options_;
Expand Down Expand Up @@ -1282,27 +1280,30 @@ class FlatConverter :
"\n"
"Default: 1+2+16+512.",
options_.solcheckmode_, 0, 1024);
GetEnv().AddOption("sol:chk:feastol sol:chk:eps chk:eps chk:tol",
GetEnv().AddOption("sol:chk:feastol sol:chk:eps chk:eps chk:feastol",
"Absolute tolerance to check objective values, variable "
"and constraint bounds. Default 1e-6.",
options_.solfeastol_, 0.0, 1e100);
GetEnv().AddOption("sol:chk:feastolrel sol:chk:epsrel chk:epsrel chk:tolrel",
GetEnv().AddOption("sol:chk:feastolrel sol:chk:epsrel chk:epsrel chk:feastolrel",
"Relative tolerance to check objective values, variable "
"and constraint bounds. Default 1e-6.",
options_.solfeastolrel_, 0.0, 1e100);
GetEnv().AddOption("sol:chk:inttol sol:chk:inteps sol:inteps chk:inteps",
GetEnv().AddOption("sol:chk:inttol sol:chk:inteps sol:inteps chk:inttol",
"Solution checking tolerance for variables' integrality. "
"Default 1e-5.",
options_.solinttol_, 0.0, 1e100);
GetEnv().AddOption("sol:chk:fail chk:fail checkfail",
"Fail on solution checking violations.",
options_.solcheckfail_, false, true);
GetEnv().AddOption("sol:chk:noround chk:noround chk:no_solution_round",
"Don't use AMPL solution_round option when checking.",
options_.dont_use_sol_round_, false, true);
GetEnv().AddOption("sol:chk:noprec chk:noprec chk:no_solution_precision",
"Don't use AMPL solution_precision option when checking.",
options_.dont_use_sol_prec_, false, true);
GetEnv().AddOption("sol:chk:round chk:round chk:rnd",
"AMPL solution_round option when checking: "
"round to this number of decimals after comma "
"(before comma if negative.)",
options_.sol_round_, -1000, 1000);
GetEnv().AddOption("sol:chk:prec chk:prec chk:precision",
"AMPL solution_precision option when checking: "
"number of significant digits.",
options_.sol_prec_, -1000, 1000);
}


Expand Down

0 comments on commit a88e8ee

Please sign in to comment.