-
Notifications
You must be signed in to change notification settings - Fork 70
Description
Hello!
I'm trying to use CyCbcModel to solve a supply/demand problem with the enforcement of minimum supply. The most desirable outcome of the model is the marginal price. In case when I use CyClpSimplex to solve the problem without the minimum supply thresholds (so, without integer variables), I just take the elements of dualConstraintSolution that correspond to demand constraints. But CyCbcModel doesn't have that property.
I found a way to retrieve the dualConstraintSolution via cbcModel.osiSolverInteface.clpModel but this leads to an error when the script exits: pointer being freed was not allocated. Please advise what would be the right way to make dualConstraintSolution available in CyCbcModel.
I wrote a simple script, so you could easily reproduce the memory issue:
from cylp.cy import CyClpSimplex
from cylp.py.modeling.CyLPModel import CyLPModel
#
# The very simplistic scenario in which the two suppliers have
# a minimum supply threshold. Intentionally, the one with lower
# threshold supplies at a higher cost. The model is supposed
# to choose which of the two will satisfy the demand.
#
# supplier 1
capacity_1 = 100
threshold_1 = 50
cost_1 = 10
# supplier 2
capacity_2 = 100
threshold_2 = 70
cost_2 = 8
# demand
demand = 60
# model
model = CyLPModel()
supply_1 = model.addVariable('supply_1', 1)
model += 0 <= supply_1 <= capacity_1
supply_2 = model.addVariable('supply_2', 1)
model += 0 <= supply_2 <= capacity_2
switch_1 = model.addVariable('switch_1', 1, isInt=True)
model += 0 <= switch_1 <= 1
switch_2 = model.addVariable('switch_2', 1, isInt=True)
model += 0 <= switch_2 <= 1
# enforce threshold
model += supply_1 - threshold_1 * switch_1 >= 0
model += supply_1 - capacity_1 * switch_1 <= 0
model += supply_2 - threshold_2 * switch_2 >= 0
model += supply_2 - capacity_2 * switch_2 <= 0
# demand
model += supply_1 + supply_2 == demand
# minimise cost
model.objective = cost_1 * supply_1 + cost_2 * supply_2
clpModel = CyClpSimplex(model)
cbcModel = clpModel.getCbcModel()
cbcModel.solve()
# So far everything works and we can see which supplier has been chosen
print(cbcModel.primalVariableSolution)
# I need to retrieve the dualConstraintSolution, which is necessary to get the marginal price.
# The only way I found is via cbcModel.osiSolverInteface.clpModel
# and it prints the right value
print(cbcModel.osiSolverInteface.clpModel.dualConstraintSolution[-1]) # for demand constraint
#
# but in the end of the script python fails with the error:
# pointer being freed was not allocated
#
# It seems that just accessing cbcModel.osiSolverInteface.clpModel
# somewhere in the code causes this failure upon objects destruction
# when the script is about to terminate$ python --version
Python 3.9.7
$ pip list cylp
Package Version
---------- -------
cylp 0.91.4
numpy 1.21.2
pip 21.1.2
scipy 1.7.1
setuptools 57.0.0
wheel 0.36.2
$ cbc
Welcome to the CBC MILP Solver
Version: 2.10.3