I am new to pyomo. I would like to ask if there is a way to achieved this requirement.
Currently my code shown below, yet it is not producing the correct results. Some of the items assigned can be more than the capacity.
from pyomo.opt import SolverFactory
value_asset = {'J': 2, 'B': 4, 'D': 18, 'C': 34, 'A': 20, 'E': 31}
bins = {'y1': 50, 'y2': 20, 'y3': 30, 'y4': 70, 'y5': 40}
Assets = {'A': ['y1', 'y2'], 'J': ['y1', 'y2'], 'E': ["y4", "y5"], 'B': ["y4", "y5"],
'D': ['y5', "y4", "y3"],
'C': ["y1", "y2", 'y3', 'y4', 'y5']}
model = pyo.ConcreteModel()
model.Assets = pyo.Set(initialize=Assets.keys())
model.budget = pyo.Set(initialize=bins.keys())
model.x = pyo.Var(model.Assets, model.budget, within=pyo.Integers, bounds=(0, None))
model.less_budget = pyo.ConstraintList()
# make sure that all the total are always less than or equal to the budget
for b in model.budget:
model.less_budget.add(expr=sum([model.x[asset, b] for asset in model.Assets]) <= bins[b])
# we want to exclude certain year that some assets cannot do
model.excluded = pyo.ConstraintList()
for asset in model.Assets:
inc = Assets[asset]
exc = list(bins.keys() - inc)
for t in exc:
model.excluded.add(expr=model.x[asset, t] == 0)
# each item can only go to 1 bin
model.one_bins = pyo.ConstraintList()
for asset in model.Assets:
model.one_bins.add(expr=sum(model.x[asset, b] for b in (model.budget )) <= 1)
model.obj = pyo.Objective(expr=sum(model.x[asset, b] for asset in model.Assets for b in model.budget),sense=pyo.maximize)
solver = pyo.SolverFactory('cbc', executable=r'C:\Users\cc\Downloads\Cbc-2.10-win64-msvc15-md\bin\cbc.exe')
solver.solve(model)
model.x.display()
You are on the right track. You just missed multiplying the selection variable (times) the value of the item in your constraint. So update that constraint to this:
for b in model.budget:
model.less_budget.add(expr=sum(model.x[asset, b]*value_asset[asset] for asset in model.Assets) <= bins[b])
also note: you do not need to use a list comprehension inside the sum()
generator...makes code a little cleaner
And if you are having trouble with a constraint, display it like you were doing with x
, the problem tends to stand out rather quickly:
model.less_budget.display()
A couple other small things....
Your selection variable is binary, so you could clean up your code a bit and it within=pyo.Binary
and eliminate the bounds. You'll still need to keep your "assign once" constraint to ensure it is only assigned once.
And you might like this little trick to clean up the display of your variable... You can make a quick little loop and only display the ones that have a non-zero value like so:
# cleaner way do display only the positive results
for idx in model.x.index_set():
if model.x[idx]:
print (f'assign: {idx}')
And (best for last... :) ) You absolutely must check and read the solver results before proceeding, or else you never know if the model is infeasible, unbounded, or optimally solved. Get in the habit of doing this:
result = solver.solve(model)
print(result)