qcp11.gms : Test dual solution of SOCP

Description

Essentially maximizes x+y such that sqr(x) + sqr(y) <= 8.
Thus, x = y = 2.

However, to test conic constraints, we write the constraint
as sqr(x) + sqr(y) <= sqr(z), 0 <= z <= sqrt(8).

Contributor: Stefan Vigerske


Small Model of Type : QCP


Category : GAMS Test library


Main file : qcp11.gms

$title Test dual solution of SOCP

$onText
Essentially maximizes x+y such that sqr(x) + sqr(y) <= 8.
Thus, x = y = 2.

However, to test conic constraints, we write the constraint
as sqr(x) + sqr(y) <= sqr(z), 0 <= z <= sqrt(8).

Contributor: Stefan Vigerske
$offText

$if not set TESTTOL $set TESTTOL 1e-6

scalar mchecks / 0 /;
$if not %QPMCHECKS% == 0 $if not %QCPMCHECKS% == 0 mchecks = 1;

Variables x, y, z, objvar;
Equation e1, e2, obj;

e1..  sqr(x) + sqr(y) =L=  sqr(z);
e2.. -sqr(x) - sqr(y) =G= -sqr(z);
z.lo = 0;
z.up = sqrt(8);

obj.. objvar =E= x + y;

Model m1 / e1, obj /;
Model m2 / e2, obj /;

* don't less GAMS mess around with the solution
m1.tolproj = 0;
m2.tolproj = 0;

* from global solvers, we want optimal solutions
m1.optcr = 0;
m2.optcr = 0;

* for local solvers, the problem might look nonconvex, so lets start close to optimum
x.l = 1.9;
y.l = 1.9;
z.l = sqrt(sqr(x.l) + sqr(y.l));

Solve m1 max objvar using QCP;

abort$(m1.solvestat <> %solveStat.normalCompletion%)  'solve status is not normal';
abort$(m1.modelstat <> %modelStat.locallyOptimal% and m1.modelstat <> %modelStat.optimal%) 'model status does not indicate (local) optimality';

abort$(abs(x.l - 2) > sqrt(%TESTTOL%))       'wrong primal solution for x, expected 2';
abort$(abs(y.l - 2) > sqrt(%TESTTOL%))       'wrong primal solution for y, expected 2';
abort$(abs(z.l - sqrt(8)) > sqrt(%TESTTOL%)) 'wrong primal value for z, expected sqrt(8)';
abort$(abs(objvar.l - 4) > %TESTTOL%)  'wrong optimal value, expected 4';
abort$(abs(e1.l) > %TESTTOL%)          'wrong activity for e1, expected 0';

if( m1.marginals and mchecks,
  abort$(abs(x.m) > %TESTTOL%)           'wrong dual solution for x, expected 0';
  abort$(abs(y.m) > %TESTTOL%)           'wrong dual solution for y, expected 0';
  abort$(abs(z.m - sqrt(2)) > %TESTTOL%) 'wrong dual solution for z, expected sqrt(2)';
  abort$(abs(e1.m - 0.25) > %TESTTOL%)   'wrong dual solution for e1, expected 0.25';
);


Solve m2 max objvar using QCP;

abort$(m2.solvestat <> %solveStat.normalCompletion%)  'solve status is not normal';
abort$(m2.modelstat <> %modelStat.locallyOptimal% and m2.modelstat <> %modelStat.optimal%) 'model status does not indicate (local) optimality';

abort$(abs(x.l - 2) > sqrt(%TESTTOL%))       'wrong primal solution for x, expected 2';
abort$(abs(y.l - 2) > sqrt(%TESTTOL%))       'wrong primal solution for y, expected 2';
abort$(abs(z.l - sqrt(8)) > sqrt(%TESTTOL%)) 'wrong primal value for z, expected sqrt(8)';
abort$(abs(objvar.l - 4) > %TESTTOL%)  'wrong optimal value, expected 4';
abort$(abs(e2.l) > %TESTTOL%)          'wrong activity for e2, expected 0';

if( m2.marginals and mchecks,
  abort$(abs(x.m) > %TESTTOL%)           'wrong dual solution for x, expected 0';
  abort$(abs(y.m) > %TESTTOL%)           'wrong dual solution for y, expected 0';
  abort$(abs(z.m - sqrt(2)) > %TESTTOL%) 'wrong dual solution for z, expected sqrt(2)';
  abort$(abs(e2.m + 0.25) > %TESTTOL%)   'wrong dual solution for e2, expected -0.25';
);


* do another solve of m1 where the SOCP constraint e1 must not be active
* solution should be x = y = 1 and some z >= 2, thus sqr(x) + sqr(y) = 2 < 4 <= sqr(z)
x.up = 1;
y.up = 1;
z.lo = 2;
Solve m1 max objvar using QCP;

abort$(m1.solvestat <> %solveStat.normalCompletion%)  'solve status is not normal';
abort$(m1.modelstat <> %modelStat.locallyOptimal% and m1.modelstat <> %modelStat.optimal%) 'model status does not indicate (local) optimality';

abort$(abs(x.l - 1) > sqrt(%TESTTOL%))       'wrong primal solution for x, expected 1';
abort$(abs(y.l - 1) > sqrt(%TESTTOL%))       'wrong primal solution for y, expected 1';
abort$(abs(objvar.l - 2) > %TESTTOL%)  'wrong optimal value, expected 2';
abort$(e1.l > -2 + %TESTTOL%)          'wrong activity for e1, expected at most -2';

if( m1.marginals and mchecks,
  abort$(abs(x.m - 1) > %TESTTOL%)  'wrong dual solution for x, expected 1';
  abort$(abs(y.m - 1) > %TESTTOL%)  'wrong dual solution for y, expected 1';
  abort$(abs(z.m) > %TESTTOL%)      'wrong dual solution for z, expected 0';
  abort$(abs(e1.m) > %TESTTOL%)     'wrong dual solution for e1, expected 0';
);