$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