$title Simple test of SEMICONT variables (SEMICON1,SEQ=109) $onText Simple test of semicont variables We want to minimize the distance between x and xbar, subject to x + s = 10, s semicontinuous. Depending on how the bounds on s are set, the minimum distance is acheived when s = 0 or s is in its nonzero range. $offText $eolCom // $if not set TESTTOL $set TESTTOL 1e-6 $if not set SLOWOK $set SLOWOK 0 scalar slowOK 'slow solves are OK: just abort.noerror in this case' / %SLOWOK% /; scalar mchecks / 0 /; $if not %MIPMCHECKS% == 0 mchecks = 1; scalar failed / 0 /; $escape = $echo if{%=1, display '%=1 failed', '%=2'; failed=1}; > gtest.gms $escape % scalar tol / %TESTTOL% /, center / 8.9 /; variable z; semicont variable s; positive variables pup 'penalty on x > center', plo 'penalty on x < center' x; equations cost, bigx 'prevents big x', smallx 'prevents small x' f; cost.. z =e= pup + plo; bigx.. x - pup =l= center; smallx..plo + x =g= center; f.. x + s =e= 10; model m / cost, bigx, smallx, f /; m.optcr = 0.001; m.optca = 0; s.up = 10; set sloVals 'lower bounds on s' / 'slo=0', 'slo=1' 'slo=1.5' 'slo=2.1' 'slo=2.8' /; parameter slo(sloVals) / 'slo=0' 0 'slo=1' 1 'slo=1.5' 1.5 'slo=2.1' 2.1 'slo=2.8' 2.8 /; table levl(sloVals,*) s z pup plo x cost f 'slo=0' 1.1 0 0 0 8.9 0 10 'slo=1' 1.1 0 0 0 8.9 0 10 'slo=1.5' 1.5 .4 0 .4 8.5 0 10 'slo=2.1' 2.1 1 0 1.0 7.9 0 10 'slo=2.8' 0 1.1 1.1 0 10 0 10 ; table marg(sloVals,*) s z pup plo x cost f 'slo=0' 0 0 1 1 0 1 0 'slo=1' 0 0 1 1 0 1 0 'slo=1.5' 1 0 1 1 0 1 -1 'slo=2.1' 1 0 1 1 0 1 -1 'slo=2.8' -1 0 1 1 0 1 1 ; parameter sl(sloVals), zl(sloVals), pupl(sloVals), plol(sloVals), xl(sloVals), costl(sloVals), fl(sloVals), sm(sloVals), zm(sloVals), pupm(sloVals), plom(sloVals), xm(sloVals), costm(sloVals), fm(sloVals); sl (sloVals) = levl(sloVals,'s'); zl (sloVals) = levl(sloVals,'z'); pupl (sloVals) = levl(sloVals,'pup'); plol (sloVals) = levl(sloVals,'plo'); xl (sloVals) = levl(sloVals,'x'); costl(sloVals) = levl(sloVals,'cost'); fl (sloVals) = levl(sloVals,'f'); sm (sloVals) = marg(sloVals,'s'); zm (sloVals) = marg(sloVals,'z'); pupm (sloVals) = marg(sloVals,'pup'); plom (sloVals) = marg(sloVals,'plo'); xm (sloVals) = marg(sloVals,'x'); costm(sloVals) = marg(sloVals,'cost'); fm (sloVals) = marg(sloVals,'f'); loop {sloVals$[ord(sloVals) <= INF], s.lo = slo(sloVals); solve m using MIP minimizing z; display m.solvestat, m.modelstat; abort.noError$[slowOK and %solveStat.resourceInterrupt% = m.solvestat] 'Solve too slow'; if {(m.solvestat = %solveStat.capabilityProblems%), abort$(m.modelstat <> %modelStat.noSolutionReturned%) 'bad modelstat', m.modelstat; // skip checks if the solver is not SEMICONT-capable else $ batInclude gtest "(m.solvestat <> %solveStat.normalCompletion% or (m.modelstat <> %modelStat.optimal% and m.modelstat <> %modelStat.integerSolution%) )" "wrong status codes" $ batInclude gtest "(abs(m.objval-z.l) > tol)" "z.l <> m.objval"; $ batInclude gtest "(abs( s.l- sl(sloVals)) > tol)" " s.l <> sl"; $ batInclude gtest "(abs( z.l- zl(sloVals)) > tol)" " z.l <> zl"; $ batInclude gtest "(abs( pup.l- pupl(sloVals)) > tol)" " pup.l <> pupl"; $ batInclude gtest "(abs( plo.l- plol(sloVals)) > tol)" " plo.l <> plol"; $ batInclude gtest "(abs( x.l- xl(sloVals)) > tol)" " x.l <> xl"; $ batInclude gtest "(abs(cost.l-costl(sloVals)) > tol)" "cost.l <> costl"; $ batInclude gtest "(abs( f.l- fl(sloVals)) > tol)" " f.l <> fl"; if {mchecks, $ batInclude gtest "(abs( s.m- sm(sloVals)) > tol)" " s.m <> sm"; $ batInclude gtest "(abs( z.m- zm(sloVals)) > tol)" " z.m <> zm"; $ batInclude gtest "(abs( x.m- xm(sloVals)) > tol)" " x.m <> xm"; $ batInclude gtest "(abs(cost.m- costm(sloVals)) > tol)" "cost.m <> costm"; $ batInclude gtest "(abs( f.m- fm(sloVals)) > tol)" " f.m <> fm"; $ batInclude gtest "(abs( pup.m-bigx.m -pupm(sloVals)) > tol)" "pup.m-bigx.m <> pupm"; $ batInclude gtest "(abs( plo.m+smallx.m-plom(sloVals)) > tol)" "plo.m+smallx.m <> plom"; }; $if set doscalar if (failed, option mip=convert; solve m using mip min z;); abort$failed 'test failed', s.lo; }; };