! Using Lagrangean relaxation to try to get
better bounds, and perhaps solve a
Task to Machine assignment problem;
!Reference:
Geoffrion, A. (1974),"Lagrangean Relaxation for Integer Programming",
Math. Programming Study 2, pp.82-114;
! Keywords: Lagrangean relaxation, Task Assignment;
SETS:
TASK: LAMBDA;
MACH: TIMEA;
TXM( TASK, MACH): VAL, USAGE, Y, YCUR;
ENDSETS DATA:
! A set of tasks...;
TASK = T01 T02 T03 T04 T05 T06 T07;
! and machines to which tasks can be assigned;
MACH = M01 M02 M03;
! Time capacity available on each machine;
TIMEA = 40 40 60;
! Value of assigning task i to machine j;
VAL = 24 43 41
17 52 28
81 73 74
39 48 47
55 62 58
73 71 68
29 38 36;
! Usage by task i of machine j capacity;
USAGE = 24 28 19
32 31 29
21 18 15
17 14 21
11 13 19
17 12 17
15 15 17;
ENDDATA
SUBMODEL REAL_PROB:
! The original, full model is...;
MAX = OBJ;
OBJ = @SUM( TASK(i):
@SUM( MACH(j): VAL(i,j)*Y(i,j)));
! Cannot assign more work to machine j than capacity available;
@FOR( MACH(j):
[CAP] @SUM( TASK(i): USAGE(i, j)*Y(i,j)) <= TIMEA(j)
);
! Can assign task i to at most one machine.
These constraints will be relaxed vial Lagrange multipliers;
@FOR( TASK(i):
[ATMOST1] @SUM( MACH(j): Y(i,j)) <= 1; ! Apply muliplier LAMBD(i);
);
! The Y(i,j) must be 0 or 1. Can turn this off by
setting NORELAX = 0;
@FOR( TXM( i,j) | NORELAX : @BIN( Y(i,j)));
! End of original full model;
ENDSUBMODEL
SUBMODEL SOLVE_MACH:
! Relaxed problem for machine jnow if the ATMOST1 constraints
are relaxed. The problem decomposes into a separate problem
for each machine;
! Inputs:
jnow = machine for which we are solving knapsack/loading problem;
! Maximize value minus lagrange multiplier charge of tasks assigned to machine jnow;
MAX = OBJ;
OBJ = @SUM( TASK(i): VAL(i,jnow)*Y(i,jnow))
- @SUM( TASK(i): LAMBDA(i)*Y(i,jnow));
! Cannot assign more work to machine jnow than time available;
[CAPJ] @SUM( TASK(i): USAGE(i, jnow)*Y(i,jnow)) <= TIMEA(jnow);
! The Y(i,j) must be 0 or 1, i.e., binary;
@FOR( TASK(i): @BIN( Y(i,jnow)));
ENDSUBMODEL
CALC:
@SET('TERSEO',2); ! Output level (0:verb, 1:terse, 2:errors, 3:none);
@SET('OROUTE',1); ! Route every line immediately to the window;
! If we want to cheat and solve the orginal problem, turn this on;
! NORELAX = 0; ! @SOLVE( REAL_PROB);
! @WRITE(' True optimal value= ', OBJ, @NEWLINE(1));
! Guess initial multipliers;
@FOR( TASK(i):
LAMBDA(i) = 0;
);
! Initial multiplier adjustment factor;
DELTA = 10;
! Max iteration limit;
ITERMX = 100;
! Current interation number;
iter = 0;
@WRITE(' Iteration Upper bound Lower bound Step size', @NEWLINE(1));
! Main loop, adjusting Lagrange multipliers each pass.
One may wish to add additional termination conditions
besides a max iterations limit;
@WHILE( iter #LT# ITERMX:
iter = iter + 1;
! For given set of Lagrange Multipliers, solve current relaxed problem.
The relaxation separates into independent problems for each machine;
UBOUND = @SUM( TASK(i): LAMBDA(i)*1);
@FOR( MACH( j):
jnow = j;
@SOLVE( SOLVE_MACH);
UBOUND = UBOUND + OBJ;
! Save the current Y values;
@FOR( TASK(i):
YCUR(i,jnow) = Y(i,jnow);
);
);
! Begin code to adjust the multipliers;
@FOR( TASK(i):
! Compute the LHS of the relaxed constraint;
LHS = @SUM( MACH(j) | YCUR(i,j) #GT# 0.5: 1);
! Begin code to adjust multiplier based on the amount of constraint violation.
Increase LAMBDA(i) if violated, decrease if there is slack.
There may be better ways to do this;
LAMBDA(i) = @SMAX(0, LAMBDA(i) + DELTA*(LHS - 1));
! @WRITE(i,' LHS=', LHS,' Adjust multiplier to ', LAMBDA(i),@NEWLINE(1));
);
! Multiplier adjustment step size adjustment.
The stepsize must decrease towards 0 to get convergence.
There may be better ways to this;
DELTA = DELTA*(iter+1)/(iter+2);
! End code to adjust multipliers and stepsize;
! Begin code to try to find a feasible solution from
the relaxed solution.
There may be better ways of guessing a feasible solution;
@FOR( TASK(i):
! Compute the LHS of the relaxed constraint;
LHS = @SUM( MACH(j) | YCUR(i,j) #GT# 0.5: 1);
! If LHS > 1, then decrease LHS by setting some of the YCUR(i,j)
= 0 until constraint is feasible;
@FOR( MACH(j) | YCUR(i,j) #GE# 0.5 #AND# LHS #GT# 1:
YCUR(i,j) = 0;
LHS = LHS - 1;
);
);
! Compute the objective value of this feasible solution;
LBOUND = @SUM( TXM(i,j): VAL(i,j)*YCUR(i,j));
! End code to try to find a feasible solution;
! If the original problem is nonconvex, e.g., has integer variables,
then it is generally impossible to reduce the gap between
UBOUND and LBOUND to 0;
@WRITE(@FORMAT(iter,'5.0f'),' ', @FORMAT( UBOUND,'12.2f'),
' ', @FORMAT(LBOUND,'12.2f'),' ',@FORMAT(DELTA,'10.3f'),@NEWLINE(1));
); ! @WHILE( iter...;
ENDCALC
|