cns12.gms : CNS model - unsolvable model, scaling issues

Description

The following model and its scaled variant are both infeasible.
E2 and e3 uniquely determines x2 = x3 = 0, and e1 is then
impossible to satisfy.
The scaling in the second model may force a solver based on
monotonicity of the infeasibilities to adjust x1 gradually as
x2 and x3 are moved towards zero, and the solution process may end
with a very large x1 value and therefore also a very large
derivative.


Small Model of Type : CNS


Category : GAMS Test library


Main file : cns12.gms

$title CNS model - unsolvable model, scaling issues (cns12,SEQ=102)

$onText
  The following model and its scaled variant are both infeasible.
  E2 and e3 uniquely determines x2 = x3 = 0, and e1 is then
  impossible to satisfy.
  The scaling in the second model may force a solver based on
  monotonicity of the infeasibilities to adjust x1 gradually as
  x2 and x3 are moved towards zero, and the solution process may end
  with a very large x1 value and therefore also a very large
  derivative.
$offText

$if not set TESTTOL $set TESTTOL 1e-6
scalar tol / %TESTTOL% /;
$if not set SLOWOK $set SLOWOK 0
scalar slowOK 'slow solves are OK: just abort.noerror in this case' / %SLOWOK% /;

Scalar scale / 1 /;

variable x1, x2, x3;
equation e1, e2, e3;

e1 .. scale * x1 * x2 =e= scale;
e2 .. x2 + x3 =e= 0;
e3 .. x2 - x3 =e= 0;

x1.l = 1;
x2.l = 1;
x3.l = 1;

model m / all /;


*  Case 1: without bounds, a solver may get within tolerance with
*          a large x1 and small x2,x3
x1.l = 1; x2.l = 1; x3.l = 1;
solve m using cns;
abort.noError$[slowOK and %solveStat.ResourceInterrupt% = m.solvestat] 'Solve too slow';
abort$(m.solvestat <> %solveStat.normalCompletion%) 'bad solvestat', m.solvestat;
if {(m.modelstat = %modelStat.solved%),
* solver found a "solution": check that it is within tolerance
  abort$(abs(e1.l-scale) > tol)                   'bad e1.l';
  abort$(abs(e2.l-0) > tol)                       'bad e2.l';
  abort$(abs(e3.l-0) > tol)                       'bad e3.l';
else
  abort$(m.modelstat <> %modelStat.locallyInfeasible% and m.modelstat <> %modelStat.infeasibleNoSolution%)
     'bad modelstat', m.modelstat;
  abort$((m.numinfes < 1)$(m.modelstat = %modelStat.locallyInfeasible%))                          'wrong .numinfes';
};

*  Case 2: bound x2, this makes the model infeasible
x1.lo = -1e5; x1.up = 1e5;
x1.l = 1; x2.l = 1; x3.l = 1;
solve m using cns;
abort.noError$[slowOK and %solveStat.resourceInterrupt% = m.solvestat] 'Solve too slow';
abort$(m.solvestat <> %solveStat.normalCompletion% or (m.modelstat <> %modelStat.locallyInfeasible% and m.modelstat <> %modelStat.infeasibleNoSolution%))
   'bad return codes', m.solvestat, m.modelstat;
abort$((m.numinfes < 1)$(m.modelstat = %modelStat.locallyInfeasible%))                            'wrong .numinfes';
x1.lo = -INF; x1.up = INF;


*  Case 3: scaled version of case 1
scale = 5;
x1.l = 1; x2.l = 1; x3.l = 1;
solve m using cns;
abort.noError$[slowOK and %solveStat.resourceInterrupt% = m.solvestat] 'Solve too slow';
abort$(m.solvestat <> %solveStat.normalCompletion%) 'bad solvestat', m.solvestat;
if {(m.modelstat = %modelStat.solved%),
* solver found a "solution": check that it is within tolerance
  abort$(abs(e1.l-scale) > tol)                   'bad e1.l';
  abort$(abs(e2.l-0) > tol)                       'bad e2.l';
  abort$(abs(e3.l-0) > tol)                       'bad e3.l';
else
  abort$(m.modelstat <> %modelStat.locallyInfeasible% and m.modelstat <> %modelStat.infeasibleNoSolution%)
     'bad modelstat', m.modelstat;
  abort$((m.numinfes < 1)$(m.modelstat = %modelStat.locallyInfeasible%))                          'wrong .numinfes';
};


*  Case 4: bound x2, this makes the model infeasible
scale = 5;
x1.lo = -1e5; x1.up = 1e5;
x1.l = 1; x2.l = 1; x3.l = 1;
solve m using cns;
abort.noError$[slowOK and %solveStat.resourceInterrupt% = m.solvestat] 'Solve too slow';
abort$(m.solvestat <> %solveStat.normalCompletion% or (m.modelstat <> %modelStat.locallyInfeasible% and m.modelstat <> %modelStat.infeasibleNoSolution%))
   'bad return codes', m.solvestat, m.modelstat;
abort$((m.numinfes < 1)$(m.modelstat = %modelStat.locallyInfeasible%))                            'wrong .numinfes';
x1.up = INF;
x1.lo = -INF; x1.up = INF;