I have an assignment problem where I have $N$ locations and $M$ dates for each location, and the goal is to choose $K$ location-date pairs that maximize revenue. There are a number of constraints, for example a location can only be chosen once, a date can only be chosen once, etc.
Here is a dummy example of how I'm setting up the problem in PuLP:
import random
import pulp as pl
# Dummy revenue calculation
def get_revenue(location, date):
return random.randint(100, 1000)
def optimize(max_choices=4):
# Dummy data
locations = ['a', 'b', 'c', 'd']
dates = ['2023-01-01', '2023-02-01', '2023-03-01', '2024-04-01']
prob = pl.LpProblem('RevenueMaximization', pl.LpMaximize)
# Variable setup
pairs = [(location, date) for location in locations for date in dates]
choices = pl.LpVariable.dicts('LocationDates', pairs, cat=pl.LpBinary)
# Objective function
prob += pl.lpSum([choices[pair]*get_revenue(pair[0], pair[1]) for pair in pairs])
# Desired choices constraint
prob += pl.lpSum([choices[pair] for pair in pairs]) == max_choices, 'MaxChoices'
# One date per location constraint
for location in locations:
prob += pl.lpSum([
choices[(location, date)]
for date in dates
]) <= 1, f'OneDatePerLocation_{location}'
# One location per date constraint
for date in dates:
prob += pl.lpSum([
choices[(location, date)]
for location in locations
]) <= 1, f'OneLocationPerDate_{date}'
# Other constraints...
# Solve and print results
prob.solve()
if pl.LpStatus[prob.status] == 'Optimal':
for v in prob.variables():
if v.value() > 0:
print(v.name, '=', v.dj)
else:
print('Problem is infeasible')
if __name__ == '__main__':
optimize()
This works fine, but there are two constraints that I have left out that are stumping me. I want to allow a user to specify a first and/or last location, meaning if a user selects a
as the first location, then no other location can have a date earlier than the date chosen for a
. Similarly, if a user selects d
as the last location, then no locations can have a date after the date chosen for d
.
In the real world, I have a few thousand locations and a dynamic range of dates that spans ~1.5 years, so I think brute forcing is out of the equation. I'd like to solve these constraints directly with PuLP, but I am having trouble wrapping my head around how to formulate, let alone implement them.
I am fairly new to linear programming and using PuLP, so I'm not sure if there is some trick I'm missing, or if this is complicated and requires additional indicator variables. Any help would be greatly appreciated!