The first several PROC OPTMODEL statements declare parameters and index sets and then read the input data:
proc optmodel; num n = &n; set CELLS = 1..n cross 1..n cross 1..n; set COLORS; num num_balls {COLORS}; read data color_data into COLORS=[_N_] num_balls;
The following statements declare the IsColor
variables and the first two families of constraints:
var IsColor {CELLS, COLORS} binary; con IsColor_con {<i,j,k> in CELLS}: sum {color in COLORS} IsColor[i,j,k,color] = 1; con Num_balls_con {color in COLORS}: sum {<i,j,k> in CELLS} IsColor[i,j,k,color] = num_balls[color];
The following statements declare the IsMonochromatic
variables and the objective:
num num_lines init 0; set LINES = 1..num_lines; var IsMonochromatic {LINES} binary; min NumMonochromaticLines = sum {line in LINES} IsMonochromatic[line];
The following SET statement declares (but does not populate) an index set that will contain the cells for each line:
set <num,num,num> CELLS_line {LINES};
The following FOR loops use the SETOF operator to populate CELLS_line for each row:
for {i in 1..n, j in 1..n} do; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {k in 1..n} <i,j,k>; end; for {i in 1..n, k in 1..n} do; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {j in 1..n} <i,j,k>; end; for {j in 1..n, k in 1..n} do; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {i in 1..n} <i,j,k>; end;
The following FOR loops use the SETOF operator to populate CELLS_line for each face diagonal:
for {i in 1..n} do; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {j in 1..n} <i,j,j>; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {j in 1..n} <i,j,n+1-j>; end; for {j in 1..n} do; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {i in 1..n} <i,j,i>; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {i in 1..n} <i,j,n+1-i>; end; for {k in 1..n} do; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {i in 1..n} <i,i,k>; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {i in 1..n} <i,n+1-i,k>; end;
The following statements use the SETOF operator to populate CELLS_line for each cube diagonal:
num_lines = num_lines + 1; CELLS_line[num_lines] = setof {t in 1..n} <t,t,t>; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {t in 1..n} <t,t,n+1-t>; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {t in 1..n} <t,n+1-t,t>; num_lines = num_lines + 1; CELLS_line[num_lines] = setof {t in 1..n} <t,n+1-t,n+1-t>;
The following PUT statements demonstrate that num_lines is , which is 49 when .
put num_lines=; put (((n+2)^3 - n^3) / 2)=;
The following CON statement enforces the rule that if all cells in a line are the same color, then :
con Link_con {line in LINES, color in COLORS}: sum {<i,j,k> in CELLS_line[line]} IsColor[i,j,k,color] - card(CELLS_line[line]) + 1 <= IsMonochromatic[line];
The following statements call the mixed integer linear programming solver and use the .sol
variable suffix to populate assigned_color[i,j,k]:
solve; num assigned_color {CELLS}; for {<i,j,k> in CELLS} do; for {color in COLORS: IsColor[i,j,k,color].sol > 0.5} do; assigned_color[i,j,k] = color; leave; end; end;
The following statements print the values of assigned_color[i,j,k] for each i and display in the log which cells make up each monochromatic line:
for {i in 1..n} print {j in 1..n, k in 1..n} assigned_color[i,j,k]; for {line in LINES: IsMonochromatic[line].sol > 0.5} put CELLS_line[line]=;
By default, the PUT statement writes to the log. You can use the following FILE statement to redirect log output to the listing:
file print; for {line in LINES: IsMonochromatic[line].sol > 0.5} put CELLS_line[line]=; quit;
Figure 17.2 shows the output from the mixed integer linear programming solver.
Figure 17.2: Output from Mixed Integer Linear Programming Solver
Problem Summary | |
---|---|
Objective Sense | Minimization |
Objective Function | NumMonochromaticLines |
Objective Type | Linear |
Number of Variables | 103 |
Bounded Above | 0 |
Bounded Below | 0 |
Bounded Below and Above | 103 |
Free | 0 |
Fixed | 0 |
Binary | 103 |
Integer | 0 |
Number of Constraints | 127 |
Linear LE (<=) | 98 |
Linear EQ (=) | 29 |
Linear GE (>=) | 0 |
Linear Range | 0 |
Constraint Coefficients | 500 |
Solution Summary | |
---|---|
Solver | MILP |
Algorithm | Branch and Cut |
Objective Function | NumMonochromaticLines |
Solution Status | Optimal |
Objective Value | 4 |
Relative Gap | 0 |
Absolute Gap | 0 |
Primal Infeasibility | 0 |
Bound Infeasibility | 0 |
Integer Infeasibility | 0 |
Best Bound | 4 |
Nodes | 523 |
Iterations | 6034 |
Presolve Time | 0.00 |
Solution Time | 0.16 |
Figure 17.3 shows the output from the PUT statement.