Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get the dualConstraintSolution from cbcModel? #130

Open
grinya007 opened this issue Oct 19, 2021 · 0 comments
Open

How to get the dualConstraintSolution from cbcModel? #130

grinya007 opened this issue Oct 19, 2021 · 0 comments

Comments

@grinya007
Copy link

grinya007 commented Oct 19, 2021

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant