Skip to content
Snippets Groups Projects
Commit ff95967e authored by Emil Karlsson's avatar Emil Karlsson
Browse files

Log m_values for MIP-formulations

parent ab98fc04
Branches master
No related tags found
No related merge requests found
......@@ -144,8 +144,9 @@ try:
logger.info(f"Building model {args.model}")
m_values = None
if args.model == "combined":
model = combined(machine)
model, m_values = combined(machine)
elif args.model == "gecode":
model = minizinc(machine, "gecode")
elif args.model == "chuffed":
......@@ -153,7 +154,7 @@ try:
elif args.model == "ilog":
model = ilog(machine)
elif args.model == "compact":
model = compact(machine)
model, m_values = compact(machine)
elif args.model == "offset":
model = offset(machine)
else:
......@@ -170,6 +171,14 @@ try:
optimal = None
bound = None
if m_values:
import matplotlib.pyplot as plt
plt.hist(m_values, bins=30)
plt.ylabel("M-values")
plt.title(folder_name)
plot_path = folder_name + "/m_values.pdf"
plt.savefig(plot_path)
logger.info(f"M-values plotted to {plot_path}")
class ResultListener(CpoSolverListener):
def __init__(self):
......
......@@ -67,23 +67,30 @@ def combined(machine: Machine):
# Constraints
# Disjunctive
m_values = list()
for task_i in machine.tasks:
for task_j in machine.tasks:
if task_i != task_j:
index = (ConstraintType.DISJUNCTIVE, task_i.name, task_j.name, )
xi = vars[VarType.X, task_i.name]
pi = task_i.processing_time
xj = vars[VarType.X, task_j.name]
yij = vars[VarType.Y, task_i.name, task_j.name]
M = task_i.interval.end + task_i.processing_time - task_j.interval.start # Large M
expr = xi + pi <= xj + (1 - yij)*M
constr[index] = model.addConstr(expr, name=to_name(index))
if not (task_i.interval.end + task_i.processing_time <= task_j.interval.start or
task_j.interval.end + task_j.processing_time <= task_i.interval.start):
index = (ConstraintType.DISJUNCTIVE, task_i.name, task_j.name, )
xi = vars[VarType.X, task_i.name]
pi = task_i.processing_time
xj = vars[VarType.X, task_j.name]
yij = vars[VarType.Y, task_i.name, task_j.name]
M = task_i.interval.end + task_i.processing_time - task_j.interval.start # Large M
m_values.append(M)
if M < 0:
logger.info(f"M ({M})<0: \ntask i: {task_i}\ntask j: {task_j}")
raise RuntimeError
expr = xi + pi <= xj + (1 - yij)*M
constr[index] = model.addConstr(expr, name=to_name(index))
# Order left
for task_i in machine.tasks:
for task_j in machine.tasks:
if task_i != task_j:
if task_i.name < task_j.name:
index = (ConstraintType.ORDER_LEFT, task_i.name, task_j.name,)
yij = vars[VarType.Y, task_i.name, task_j.name]
yji = vars[VarType.Y, task_j.name, task_i.name]
......@@ -96,7 +103,7 @@ def combined(machine: Machine):
# Order right
for task_i in machine.tasks:
for task_j in machine.tasks:
if task_i != task_j:
if task_i.name < task_j.name:
index = (ConstraintType.ORDER_RIGHT, task_i.name, task_j.name,)
yij = vars[VarType.Y, task_i.name, task_j.name]
yji = vars[VarType.Y, task_j.name, task_i.name]
......@@ -167,4 +174,4 @@ def combined(machine: Machine):
model.setObjective(obj_expr, gurobipy.GRB.MINIMIZE)
return model
return model, m_values
......@@ -106,58 +106,64 @@ def compact(machine: Machine):
# constr[index] = model.addConstr(x_var == expr + o_var, name=to_name(index))
# Disjunctive
m_values = list()
for task_i in machine.tasks:
for task_j in machine.tasks:
if task_i != task_j:
index = (ConstraintType.DISJUNCTIVE, task_i.name, task_j.name, )
# Calculate sub-interval offset times for task_i and task_j
change_points = list()
for start, end in chain([(s, e + task_i.processing_time) for s, e in task_i.interval],
[(s, e + task_j.processing_time) for s, e in task_j.interval]):
change_points.append((start, 1))
change_points.append((end, -1))
change_points.sort()
# Calculated interval stack and extract segments where all intervals
# are represented
start = 0
prev_point = 0
count = 0
constant_dict = {}
for time, change in change_points:
count += change
if change == 1 and count == 1:
if not (task_i.interval.end + task_i.processing_time <= task_j.interval.start or
task_j.interval.end + task_j.processing_time <= task_i.interval.start):
index = (ConstraintType.DISJUNCTIVE, task_i.name, task_j.name, )
# Calculate sub-interval offset times for task_i and task_j
change_points = list()
for start, end in chain([(s, e + task_i.processing_time) for s, e in task_i.interval],
[(s, e + task_j.processing_time) for s, e in task_j.interval]):
change_points.append((start, 1))
change_points.append((end, -1))
change_points.sort()
# Calculated interval stack and extract segments where all intervals
# are represented
start = 0
prev_point = 0
count = 0
constant_dict = {}
for time, change in change_points:
count += change
if change == 1 and count == 1:
prev_point = time
start += time - prev_point
constant_dict[time] = start
prev_point = time
start += time - prev_point
constant_dict[time] = start
prev_point = time
task_i_offset_expr = 0
for s, e, in task_i.interval:
alpha_var = vars[VarType.ALPHA, task_i.name, s, e]
alpha_constant = constant_dict[s]
task_i_offset_expr += alpha_constant * alpha_var
task_j_offset_expr = 0
for s, e, in task_j.interval:
alpha_var = vars[VarType.ALPHA, task_j.name, s, e]
alpha_constant = constant_dict[s]
task_j_offset_expr += alpha_constant * alpha_var
pi = task_i.processing_time
oi = vars[VarType.O, task_i.name]
oj = vars[VarType.O, task_j.name]
yij = vars[VarType.Y, task_i.name, task_j.name]
M = max(constant_dict.values()) # Large M
expr = task_i_offset_expr + oi + pi <= task_j_offset_expr + oj + (1 - yij) * M
constr[index] = model.addConstr(expr, name=to_name(index))
task_i_offset_expr = 0
for s, e, in task_i.interval:
alpha_var = vars[VarType.ALPHA, task_i.name, s, e]
alpha_constant = constant_dict[s]
task_i_offset_expr += alpha_constant * alpha_var
task_j_offset_expr = 0
for s, e, in task_j.interval:
alpha_var = vars[VarType.ALPHA, task_j.name, s, e]
alpha_constant = constant_dict[s]
task_j_offset_expr += alpha_constant * alpha_var
pi = task_i.processing_time
oi = vars[VarType.O, task_i.name]
oj = vars[VarType.O, task_j.name]
yij = vars[VarType.Y, task_i.name, task_j.name]
M = max(constant_dict.values()) # Large M
if M < 0:
logger.info(f"M ({M})<0: \ntask i: {task_i}\ntask j: {task_j}")
raise RuntimeError
expr = task_i_offset_expr + oi + pi <= task_j_offset_expr + oj + (1 - yij) * M
m_values.append(M)
constr[index] = model.addConstr(expr, name=to_name(index))
# Order left
for task_i in machine.tasks:
for task_j in machine.tasks:
if task_i != task_j:
if task_i.name < task_j.name:
index = (ConstraintType.ORDER_LEFT, task_i.name, task_j.name,)
yij = vars[VarType.Y, task_i.name, task_j.name]
yji = vars[VarType.Y, task_j.name, task_i.name]
......@@ -170,7 +176,7 @@ def compact(machine: Machine):
# Order right
for task_i in machine.tasks:
for task_j in machine.tasks:
if task_i != task_j:
if task_i.name < task_j.name:
index = (ConstraintType.ORDER_RIGHT, task_i.name, task_j.name,)
yij = vars[VarType.Y, task_i.name, task_j.name]
yji = vars[VarType.Y, task_j.name, task_i.name]
......@@ -221,4 +227,4 @@ def compact(machine: Machine):
model.setObjective(obj_expr, gurobipy.GRB.MINIMIZE)
return model
return model, m_values
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment