The tool mcfilter (https://www.gams.com/35/docs/T_MCFILTER.html) allows to extract from a list of multi-dimensional points to non-dominated points. This can be handy to approximate the Pareto frontier for multi-objective models. There are open source alternatives to mcfilter that give you more insight what happens and allow you to fine tune the algorithm (e.g. if you want to work with tolerances in the comparison). The following GAMS program from the mcfiler documentation shows the use of a Python open source program pareto.py (https://github.com/matthewjwoodruff/pareto.py) to accomplish the same as mcfilter:
* Generate random data to test dominated sorting via pareto.py and mcfilter
Set
Ri / R1*R65535 /
Xi / X1*X16 /
Fi / F1*F5 /;
Parameter
X(Ri,Xi) 'the binary variables'
F(Ri,Fi) 'calculated F variables'
S(Fi) 'sign on the F variables';
* The following points will be unique
X(Ri,Xi) = mod(floor(Ri.ord/power(2, Xi.off)), 2);
F(Ri,Fi) = uniform(1,2);
S(Fi) = -1 + 2$(uniform(0,1) <= 0.5);
* Generate text file with X and F
file ftd / testdata.txt /; put ftd 'Data File with solutions';
loop(Ri,
put / Ri.tl:0;
loop(Xi, put ' ' X(Ri,Xi):0:0);
loop(Fi, put ' ' F(Ri,Fi):0:16);
);
putclose;
* Prepare GAMS file with table header to read results
file ftdr / testdata_res.gms /; put ftdr 'Table result(*,*)' / '$ondelim' /;
put 'R'; loop(Xi, put ' ' Xi.tl:0); loop(Fi, put ' ' Fi.tl:0);
putclose;
* The objectives to maximize need to be given in list form to the command line to we build this up
* in the element text of a singleton set
singleton set FMax / '' /;
loop(Fi, put_utility$(S(Fi)>0) 'assignText' / 'FMax' / FMax.te(FMax) ' ' (card(Fi)-ord(Fi)):0:0);
* Now we call the pareto.py, download from https://github.com/matthewjwoodruff/pareto.py
put_utility 'shell' / '"%gams.sysdir%GMSPython/python" pareto.py testdata.txt --reverse-column-indices '
'--header 1 -o 0-' (card(Fi)-1):0:0 ' -m ' FMax.te(FMax) ' >> testdata_res.gms';
* Now turn the GAMS file into a GDX file so we can load at runtime
put_utility 'exec.checkErrorLevel' / 'gams testdata_res.gms lo=0 gdx=result';
* Load the result and split up into X and F portions
parameter result(Ri,*), Fr(Ri,Fi), Xr(Ri,Xi);
execute_load 'result', result;
Fr(Ri,Fi) = result(Ri,Fi);
Xr(Ri,Xi) = result(Ri,Xi);
* Unload to GDX so we can compare with the results of mcfiler:
execute_unload 'testdata_res_py.gdx', Xr=X, Fr=F, S;
* Now compare to MCFilter tool
execute_unload 'testdata.gdx', X F S;
* The file testdata_res.gdx will contain the results
execute.checkErrorLevel 'mcfilter testdata.gdx';
execute 'gdxdiff testdata_res.gdx testdata_res_py.gdx' eps=1e-6 releps=1e-6';
abort$errorlevel 'GDX files are different, that should not happen';