%%ampl_eval
reset;
# Blocks
set B;
# Time periods
set T ordered;
# Containers
set C dimen 2; # (block, container)
# Machines
set M;
# Cost per container
param move_cost{C};
param total_move := sum{(i,c) in C} move_cost[i,c];
# Work capacity of the crane
param work_cap {M};
# Vars #
# Container in progress, container is finished, container progress units
var c_moving{M,C,T} binary;
var c_end{C,T} binary;
var c_progress{m in M,C,T} >= 0 <= work_cap[m];
# Constraints #
## Container completion
# Cant progress more than available in the container
subject to progress_limit_container{(i,c) in C}:
sum{m in M, t in T} c_progress[m,i,c,t] <= move_cost[i,c];
# Cant progress more than available by the machine
subject to progress_limit{m in M, t in T}:
sum{(i,c) in C} c_progress[m,i,c,t] <= work_cap[m];
## Containers logic
# Active iff in progress:
subject to active_work{m in M, (i,c) in C, t in T}:
c_moving[m,i,c,t] = 1 <==> c_progress[m,i,c,t] > 0;
# c_moving[m,i,c,t] = 1 <==> c_progress[m,i,c,t] >= 1e-9;
# if completely moved then finish container.
subject to finish{(i,c) in C, t in T}:
c_end[i,c,t] = 1 <==> sum{m in M, t_ in 1..t} c_progress[m,i,c,t_] >= move_cost[i,c];
# A container is not active unless previous has finished:
subject to previous_container{m in M, (i,c) in C, t in T: c > 1}:
c_moving[m,i,c,t] <= c_end[i,c-1,t];
# A container is not active if it already finished:
subject to already_finished{m in M, (i,c) in C, t in T: t <> last(T)}:
c_end[i,c,t] = 1 ==> c_moving[m,i,c,t+1] = 0;
subject to finish_all{(i,c) in C}:
c_end[i,c,last(T)] = 1;
# Finished container can't go unfinished
subject to remain_finished{(i,c) in C, t in T: t <> last(T)}:
c_end[i,c,t] <= c_end[i,c,t+1];
# Cant go to other blocks
subject to only_one_block{m in M, i in B, t in T}:
sum{(i_,c) in C: i == i_} c_moving[m,i,c,t] >= 1 ==> forall{(i_, c) in C: i != i_} c_moving[m,i_,c,t] = 0;
# Cant forget containers
subject to cant_forget_active_containers{m in M, (i,c) in C, t in T: t != last(T)}:
c_moving[m,i,c,t] = 1 ==> c_moving[m,i,c,t+1] = 1 or c_end[i,c,t] = 1;
# One machine per container atmost
subject to one_mach_per_container{(i,c) in C, t in T}:
sum{m in M} c_moving[m,i,c,t] <= 1;
# Objective #
var delay_penalty = sum{(i,c) in C, t in T} (1-c_end[i,c,t]);
#var delay_penalty_scaled = sum{c in C, t in T} (1-c_end[c,t])/card({C,T});
# Scaled!!
var unused_cap_penalty = sum{m in M, (i,c) in C, t in T} t/card(T)*c_progress[m,i,c,t]/total_move;
minimize penalty: unused_cap_penalty + delay_penalty;