$Title XPRESS test suite - solution enumerator example (XPRESS04,SEQ=550) $ontext Test the XPRESS solution enumerator - in this case, it should return the set of all MIP solutions, exactly as computed by cutting and repeated solves. Contributor: Steve Dirkse, Jan 2012 $offtext $set GAMSlo %GAMS.lo% $if %GAMS.ide% == 1 $set GAMSlo 2 $set FLAGS lo=%GAMSlo% $if %DEMOSIZE% == 1 $set FLAGS --DEMOSIZE=1 %FLAGS% $if not exist mip05.gms $call testlib -q mip05 * first generate all solutions using GAMS, cuts, and solves in a loop $call gams mip05.gms mip=xpress %FLAGS% $if errorlevel 1 $abort Generating solutions with cuts failed * should have solution info in queensSolsCuts.gdx * next generate all solutions using the XPRESS MIP solution enumerator $onecho > xpress.322 solnpool queensSolsPool.gdx solnpoolDupPolicy 0 solnpoolPop 2 * Disable symmetry reductions symmetry 0 * with XPRESS 26.01 we need to do a little more to get all 92 solutions, * as described in an email from FICO's Michael Perregaard, May 2014: * The controls you should set to prevent the Optimizer from dropping any * symmetric or dominated solutions are: * In PRESOLVEOPS clear the following bits: * 0 – singleton column removal * 3 – dual reductions * 5 – duplicated column reductions * so set PRESOLVEOPS = 438 presolveops 438 * In PRESOLVEOPS clear the following bits: * Disable dual reductions in node-to-node presolving by clearing bit 4 * of MIPPRESOLVE. That is, set MIPPRESOLVE=-17 mippresolve -17 * Disable in-tree presolve by setting TREEPRESOLVE = 0 treepresolve 0 $offecho $call gams mip05.gms mip=xpress optfile=322 --SKIPCUTS=1 %FLAGS% $if errorlevel 1 $abort Generating solutions with XPRESS enumerator failed * finally read in the GDX files and verify content is the same set cuts 'solutions generated by cutting' pool 'solutions generated by enumerator & solnpool' p2(pool) i 'size of chess board' ; alias(i,j); alias(pool,ppool); parameter found(cuts) solsCuts(cuts,i,j) 'solutions generated by cutting' sol(i,j) 'solution generated by enumerator & solnpool' tmp(i,j) ; scalars nCuts 'number of solutions generated with cuts' nPool 'number of solutions generated with enumerator & solnpool' done ; binary variable x(i,j) 'square is occupied by a queen'; $gdxin queensSolsCuts $load cuts=n i solsCuts=sols $gdxin $gdxin queensSolsPool $load pool=index $gdxin nCuts = card(cuts); nPool = card(pool); abort$[nPool <> nCuts] 'different number of solutions', nPool, nCuts; file fpool; found(cuts) = 0; x.l(i,j) = 0; loop{pool, p2(ppool) = no; p2(pool) = yes; put_utility fpool 'gdxin' / pool.te(pool); execute_loadpoint; sol(i,j) = round(x.l(i,j)); display sol; * now loop over the solutions from the cut set to find a match done = 0; loop{cuts$[not done], tmp(i,j) = sol(i,j) - solsCuts(cuts,i,j); if {(0 eq card(tmp)), * we have a match abort$[found(cuts)] 'solnpool solution matches already-matched cut solution', p2, sol; found(cuts) = 1; done = 1; }; }; abort$[not done] 'solnpool solution not found in solsCuts', p2, sol; }; abort$[card(found) <> nCuts] 'solution from cuts not found in pool', found; * for debugging you can skip the cleanup, o/w this test leaves a mess * $goto alldone execute 'rm -f queensSols*.gdx soln_queens_p*.gdx'; $label alldone