I am trying to solve this minimization problem with Pulp.
We have packets of mangoes each having a category, age, and count of mangoes in it.
# Packet Names and the count, category and age of mangoes in each packet.
mango_packs = {
"pack_1": {
"count": 5,
"category": "pack",
"age": 10
},
"pack_2": {
"count": 9,
"category": "pack",
"age": 10
},
"bag_2": {
"count": 5,
"category": "bag",
"age": 20
},
"sack_1": {
"count": 5,
"category": "sack",
"age": 5
},
}
We will have demand for a number of mangoes. (Which will be a whole number). Our objective is to serve the packets in a way that there are fewer remnants of mangoes. For example, if the demand is 10, we serve the packet with 10 mangoes. If not, serve 2 packets with 5 mangoes each. If we have only 3 packets with 5, 7 and 6 mangoes each, we serve packets with 5 and 6 so we have only 1 remnant. The below code is working exactly what we need here.
For demand 15, it will give the following output.
Status: Optimal
OpenPack_bag_2? yes
OpenPack_pack_1? yes
OpenPack_pack_2? no
OpenPack_sack_1? yes
import pulp
def optimise(mango_packs, mango_count):
pack_names = list(mango_packs.keys())
prob = pulp.LpProblem("MangoPacks", pulp.LpMinimize)
# variables: names of the mango packs. We can either open them or not (0/1)
lp_pack_vars = pulp.LpVariable.dicts("OpenPack", pack_names, 0, 1, "Integer")
# objective: minimise total count of mangoes in the selected packs (so to
# minimise remnants). In case of a tie, minimise the number of opened packs.
prob += (
pulp.lpSum([mango_packs[name]["count"] * lp_pack_vars[name]
for name in pack_names]) * len(mango_packs) + pulp.lpSum(
[lp_pack_vars[name] for name in pack_names]))
# constraint 1: the opened packs need to amount to a minimum number of mangos
prob += pulp.lpSum(
[mango_packs[name]["count"] * lp_pack_vars[name]
for name in pack_names]) >= mango_count
# Packets should not be from more than 2 category.
# prob += len(set([mango_packs[name]["category"] for name in pack_names if lp_pack_vars[name] == 1 ])) <= 1
prob.solve()
print("Status:", pulp.LpStatus[prob.status])
# Each of the variables is printed with it's resolved optimum value
for i, v in enumerate(prob.variables()):
print("{}? {}".format(v.name, ("no", "yes")[int(v.varValue)]))
# Packet Names and the count of mangoes in each packet.
mango_packs = {
"pack_1": {
"count": 5,
"category": "pack",
"age": 10
},
"pack_2": {
"count": 9,
"category": "pack",
"age": 10
},
"bag_2": {
"count": 5,
"category": "bag",
"age": 20
},
"sack_1": {
"count": 5,
"category": "sack",
"age": 5
},
}
optimise(mango_packs, 15)
But we have 2 more constrains now:
- Packets picked should not be from more than 2 categories.
- The age difference between any 2 packets picked should not be greater than 25
I added below constraint to restrict the number of categories. Which is basically counting the unique categories and making sure it should be less than or equal to 2.
prob += len(set([mango_packs[name]["category"] for name in pack_names if lp_pack_vars[name] == 1 ])) <= 2
But this is not working, while doing this it's giving a stage output as open all mangoes and then an exception.
Status: Optimal
OpenPack_bag_2? yes
OpenPack_pack_1? yes
OpenPack_pack_2? yes
OpenPack_sack_1? yes Traceback (most recent call last):
File "main.py", line 61, in
optimise(mango_packs, 15)
File "main.py", line 34, in optimise
print("{}? {}".format(v.name, ("no", "yes")[int(v.varValue)]))TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
Looks like the if condition inside the generator expression is always returning True for some reason. Not very sure.
How to fix this problem? We need to add our new 2 constrains.
The working code without the 2 new constrains can be run from here: https://repl.it/@VinodM1/OptimumMangoes
Edited: Same Data represented differently here if it helps someone trying for a solution, as I believe we need to restructure the model to find a solution.
mango_packs_cat = {
"cat_pack": {
"packets": {
"pack_1": {
"name": "pack_1",
"count": 5
},
"pack_2": {
"name": "pack_2",
"count": 9
}
},
"age": 10
},
"cat_bag": {
"packets":{
"bag_1":{
"name": "bag_1",
"count": 5
}
},
"age": 20
},
"cat_sack": {
"packets":{
"sack_1":{
"name": "sack_1",
"count": 5
}
},
"age": 5
}
}