proof of concept knapsack optimizer

This commit is contained in:
Khalim Conn-Kowlessar 2023-06-25 22:40:05 +01:00
parent c116adf3c0
commit eccf0d0bfd
2 changed files with 75 additions and 1 deletions

View file

@ -0,0 +1,73 @@
from mip import Model, xsum, maximize, BINARY
# Example parts
wall = [
{"id": 1, "cost": 2000, "gain": 5, "type": "wall"},
{"id": 2, "cost": 2300, "gain": 6, "type": "wall"}
]
floor = [
{"id": 1, "cost": 1500, "gain": 3, "type": "floor"},
{"id": 2, "cost": 1600, "gain": 3.1, "type": "floor"}
]
roof = [
{"id": 1, "cost": 1000, "gain": 2, "type": "roof"},
{"id": 2, "cost": 1100, "gain": 2.3, "type": "roof"}
]
# To solve this, we are solving a constrained Knapsack problem
# Maximize sum(gain_g . x_g) for g in groups
# subject to sum(cost_g . x_g) <= C
# subject to sum(x_g) <= 1 for g in groups
# x_g in {0, 1} for g in groups
#
# The first sum, which is the objective of the optimisation provlem, ensures that we are maximising the gain
# for the selected parts
# The second sum (and the first constraint) ensures that the cost of the selected parts is less than or equal to C
# The third sum (and the second constraint) ensures that at most one part from each group is selected
# The last constraint ensures that the decision variables are binary
C = 4000
# group all the parts
groups = [wall, floor, roof]
# Initialize Model
m = Model("knapsack")
# Create variables
vars = [[m.add_var(var_type=BINARY, name=str(component["id"])) for component in group] for group in groups]
# Set objective
# This objective is the sum
# gain_ig * x_ig, where gain_ig represents the gain for ith part in group g
# and x_ig is the binary decision variable for the ith part in group g
m.objective = maximize(
xsum(
component['gain'] * var for group, group_vars in zip(groups, vars) for component, var in zip(group, group_vars)
)
)
# Add constraints
# This constrain ensures that sum of cost_ig * x_ig <= C, where cost_ig represents the cost for the ith component
# in group g, and x_ig is the binary decision variable for the ith component in group g
m += xsum(item['cost'] * var for group, group_vars in zip(groups, vars) for item, var in zip(group, group_vars)) <= C
# At most one item from each group
# This constraint ensures that at most one item from each group is selected
# This is expressed by summing up the decision variables for each group and ensuring that the sum is <= 1
for group_vars in vars:
m += xsum(var for var in group_vars) <= 1
# Solve the problem
m.optimize()
# Get the selected items
selected_items = [
item for group, group_vars in zip(groups, vars) for item, var in zip(group, group_vars) if var.x >= 0.99
]
total_gain = m.objective.x
actual_cost = sum([component['cost'] for component in selected_items])
print("Selected items:", selected_items)

View file

@ -12,4 +12,5 @@ python-Levenshtein
dbfread
pyproj
pint
geopandas
geopandas
mip