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 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 18.2 shows the output from the mixed integer linear programming solver.
Figure 18.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 |
Performance Information | |
---|---|
Execution Mode | Single-Machine |
Number of Threads | 1 |
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 | 2056 |
Iterations | 26069 |
Presolve Time | 0.00 |
Solution Time | 1.53 |
assigned_color | |||
---|---|---|---|
1 | 2 | 3 | |
1 | 1 | 1 | 2 |
2 | 1 | 2 | 1 |
3 | 1 | 2 | 2 |
assigned_color | |||
---|---|---|---|
1 | 2 | 3 | |
1 | 1 | 2 | 1 |
2 | 2 | 1 | 1 |
3 | 2 | 1 | 2 |
assigned_color | |||
---|---|---|---|
1 | 2 | 3 | |
1 | 2 | 1 | 2 |
2 | 2 | 1 | 2 |
3 | 1 | 2 | 2 |
Figure 18.3 shows the output from the PUT statement.
Figure 18.3: Output from PUT Statement
The OPTMODEL Procedure CELLS_line[10]={<1,1,1>,<1,2,1>,<1,3,1>} CELLS_line[18]={<3,1,3>,<3,2,3>,<3,3,3>} CELLS_line[27]={<1,3,3>,<2,3,3>,<3,3,3>} CELLS_line[35]={<1,1,3>,<2,1,2>,<3,1,1>} |