Reputation: 1
I have been working with OR-Tools to create a schedule for a basketball tournament.
I am having trouble finding the ideal way to express certain optimizations/constraints that I want to impose on the model.
Both come from a pretty straight-forward thought process: I want to make it so related games (with the same poolIDs playing or same teamIds plating) can't happen back-to-back.
My main questions are: How do I impose a restriction that means consecutive games for a team must be 120 minutes apart on a given day. For example, team y is scheduled to play at 1PM. Then, if they have another game that day, it must be at 11 AM or 3PM.
How can I reduce the number of variables/time added to the solver when trying to minimize the penalties for the optimization. I've tried to narrow it down to have as few relationships as possible, but it still seems incredibly large.
My variables look like this:
for g in unscheduled_games:
for slot in game_slots:
var_name = f"game_{g.Id}_slot_{slot.Id}"
game_vars[(g.Id, slot.Id)] = model.NewBoolVar(var_name)
And my optimization looks like this:
def get_associated_optimization(model, game_vars, unscheduled_games, game_slots):
penalty_vars = []
minutes since a fixed start:
slot_time_map = {}
base_time = min(s.DateTime for s in game_slots)
for slot in game_slots:
delta = slot.DateTime - base_time
slot_time_map[slot.Id] = int(delta.total_seconds() // 60)
conflict_graph = {}
all_games = unscheduled_games[:] # so we can index them
for i in range(len(all_games)):
for j in range(i+1, len(all_games)):
gameA = all_games[i]
gameB = all_games[j]
order = deduce_relationship(gameA, gameB)
if order is not None:
conflict_graph[(gameA.Id, gameB.Id)] = order
for (gameA_id, gameB_id), rel in conflict_graph.items():
for slotA in game_slots:
gameA_var = game_vars.get((gameA_id, slotA.Id))
if gameA_var is None:
continue
for slotB in game_slots:
gameB_var = game_vars.get((gameB_id, slotB.Id))
if gameB_var is None:
continue
if slotA.Date != slotB.Date:
continue
timeA = slot_time_map[slotA.Id]
timeB = slot_time_map[slotB.Id]
if rel == 'na':
time_difference = abs(timeA - timeB)
if time_difference >=240 or time_difference <= 60:
penalty_var = model.NewBoolVar(f'penalty_{gameA_id}_{slotA.Id}_{gameB_id}_{slotB.Id}')
model.AddMultiplicationEquality(penalty_var, [gameA_var, gameB_var])
penalty_vars.append((penalty_var, 20))
elif time_difference >= 180:
penalty_var = model.NewBoolVar(f'penalty_{gameA_id}_{slotA.Id}_{gameB_id}_{slotB.Id}')
model.AddMultiplicationEquality(penalty_var, [gameA_var, gameB_var])
penalty_vars.append((penalty_var, 4))
elif rel == 'this_first':
time_difference = timeB - timeA
if time_difference >=240:
penalty_var = model.NewBoolVar(f'penalty_{gameA_id}_{slotA.Id}_{gameB_id}_{slotB.Id}')
model.AddMultiplicationEquality(penalty_var, [gameA_var, gameB_var])
penalty_vars.append((penalty_var, 20))
elif time_difference >= 180:
penalty_var = model.NewBoolVar(f'penalty_{gameA_id}_{slotA.Id}_{gameB_id}_{slotB.Id}')
model.AddMultiplicationEquality(penalty_var, [gameA_var, gameB_var])
penalty_vars.append((penalty_var, 4))
elif rel == 'other_first':
time_difference = timeA - timeB
if time_difference >=240:
penalty_var = model.NewBoolVar(f'penalty_{gameA_id}_{slotA.Id}_{gameB_id}_{slotB.Id}')
model.AddMultiplicationEquality(penalty_var, [gameA_var, gameB_var])
penalty_vars.append((penalty_var, 20))
elif time_difference >= 180:
penalty_var = model.NewBoolVar(f'penalty_{gameA_id}_{slotA.Id}_{gameB_id}_{slotB.Id}')
model.AddMultiplicationEquality(penalty_var, [gameA_var, gameB_var])
penalty_vars.append((penalty_var, 4))
return penalty_vars
Upvotes: 0
Views: 50