/* Voglio avvalermi di AMPL+Solver per trovare una collocazione ottima di torri su una scacchiera in modo che non ve ne siano due che si "vedano". Questo modello AMPL e' stato creato da Romeo Rizzi, romeo.rizzi@univr.it a scopi didattici. */ param NUM_ROWS integer, >= 1, default 8; # Numero di righe della scacchiera param NUM_COLS integer, >= 1, default 8; # Numero di colonne della scacchiera set Rows = 1..NUM_ROWS; # Insieme degli indici di riga set Cols = 1..NUM_COLS; # Insieme degli indici di colonna set CELL = {Rows, Cols}; # Insieme delle caselle della scacchiera param VALORE{CELL} >= 0, integer, default 1; # Valori delle celle. var metto{CELL} binary; # introduciamo una variabile di scelta binaria per ogni cella, essa vale 1 se vi colloco una torre, 0 altrimenti # Definizione della funzione obiettivo: maximize MaxVal: sum{(i,j) in CELL} VALORE[i,j] * metto[i,j]; # prima famiglia di vincoli: al piu' una torre per riga: subject to alPiuUnaSuRiga{i in Rows}: sum{j in Cols} metto[i,j] <= 1; # seconda famiglia di vincoli: al piu' una torre per colonna: subject to alPiuUnaSuColonna{j in Cols}: sum{i in Rows} metto[i,j] <= 1; # terza famiglia di vincoli: le diagonali: #set RminusC = (1-NUM_COLS)..(NUM_ROWS-1); subject to alPiuUnaSuDiag{d in (1-NUM_COLS)..(NUM_ROWS-1)}: sum{(i,j) in CELL : i-j = d} metto[i,j] <= 1; # quarta famiglia di vincoli: le antidiagonali: #set RplusC = 2..NUM_ROWS+NUM_COLS; subject to alPiuUnaSuAntidiag{d in 2..NUM_ROWS+NUM_COLS}: sum{(i,j) in CELL : i+j = d} metto[i,j] <= 1; # volendo potremmo proseguire qui con i dati specifici dell'istanza qualora essi si discostino dai valori di default (in questo caso sufficienti a descrivere completamente l'istanza principe). # il modo migliore di specificare istanze specifiche e variabili e' farlo da un file separato da includere qui con: # include torri_ampl_dat.txt; # oppure: # data torri_ampl_dat.txt; # noi lo facciamo ancora piu' migliorissimo, includendo direttamente da foglio excel o da database: # CHI MI SCRIVE QUESTO PEZZO DELLA LETTURA DA EXCEL? (UNO CHE LAVORI SOTTO WINDOWS COSI' PUO' TESTARLO) Fare riferimento al Capitolo 10 del libro AMPL. table valoriCelleASCII IN "scacchieraPrezzolata.tab": [r ~ Rows], {c in Cols} < VALORE[r,c] ~ ('Col' & c) >; read table valoriCelleASCII; # questa volta, in teoria, non sarebbe a rigore necessario un Solver che gestisca i vincoli di interezza: option solver cplex; # cplex gestisce anche i vincoli di interezza. # tuttavia, se sperimentiamo il seguente, con quella di ottenere soluzioni intere a GRATIS! ... abbiamo un malfunzionamento. #option solver minos; # solo PL, non gestisce la PLI # lanciamo il Solver: solve; # Stampa della soluzione: # option omit_zero_rows 1; # non voglio vengano visualizzate variabili a zero display metto; printf "VALORE TOTALE = "; display sum{(i,j) in CELL} VALORE[i,j] * metto[i,j]; print "Torri che metto:"; printf "Riga\tColonna\t\tValore\t\tValore Cum.\n"; param valoreCumulato default 0; for {(i,j) in CELL: metto[i,j] > 0} { let valoreCumulato := valoreCumulato + VALORE[i,j]; printf "%0s\t%0s\t\t%3d\t\t%3d\n", i, j, VALORE[i,j], valoreCumulato; }; printf "\n"; # se siete su Windows probabilmente le seguenti righe vi funzionano: #table scacchieraEXCEL OUT "ODCB" "torri.xls": # {r in Rows} -> [Row], # {c in Cols} < metto[r,c] ~ ('Col' & c) >; #write table scacchieraEXCEL; # (SE UNO CHE LAVORA SOTTO WINDOWS ME LO POTESSE TESTARE ... ) table scacchieraASCII OUT "torri_output.tab": {r in Rows} -> [Row], {c in Cols} < metto[r,c] ~ ('Col' & c) >; write table scacchieraASCII; quit;