Skip to content

Add support for SOS1 constraints #984

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

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased
### Added
- Added support for SOS1-constraints
- Added getLinearConsIndicator
- Added SCIP_LPPARAM, setIntParam, setRealParam, getIntParam, getRealParam, isOptimal, getObjVal, getRedcost for lpi
- Added isFeasPositive
Expand Down
13 changes: 13 additions & 0 deletions src/pyscipopt/scip.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,19 @@ cdef extern from "scip/cons_sos1.h":
SCIP_CONS* cons,
SCIP_VAR* var)

int SCIPgetNVarsSOS1(SCIP* scip, SCIP_CONS* cons)

SCIP_VAR** SCIPgetVarsSOS1(SCIP* scip, SCIP_CONS* cons)

SCIP_Real* SCIPgetWeightsSOS1(SCIP* scip, SCIP_CONS* cons)

int SCIPgetNSOS1Vars(SCIP_CONSHDLR* conshdlr)

SCIP_RETCODE SCIPmakeSOS1Feasible(SCIP* scip,
SCIP_CONSHDLR* conshdlr,
SCIP_SOL* solution,
SCIP_Bool* changed,
SCIP_Bool* success)

cdef extern from "scip/cons_sos2.h":
SCIP_RETCODE SCIPcreateConsSOS2(SCIP* scip,
Expand Down
217 changes: 187 additions & 30 deletions src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,43 @@ cdef class Variable(Expr):
else:
mayround = SCIPvarMayRoundUp(self.scip_var)
return mayround

def varIsSOS1(self, Conshdlr conshdlr, Variable var):
"""
Returns whether variable is part of the SOS1 conflict graph

Parameters
----------
conshdlr : Conshdlr
SOS1 constraint handler
var : Variable
variable to check

Returns
-------
bool
True if variable is part of the SOS1 conflict graph, False otherwise

"""
return SCIPvarIsSOS1(conshdlr.scip_conshdlr, var.scip_var)

def varGetNodeSOS1(self, Conshdlr conshdlr, Variable var):
"""
Returns SOS1 index of variable or -1 if variable is not part of the SOS1 conflict graph

Parameters
----------
conshdlr : Conshdlr
SOS1 constraint handler
var : Variable
variable

Returns
-------
int

"""
return SCIPvarGetNodeSOS1(conshdlr.scip_conshdlr, var.scip_var)

class MatrixVariable(MatrixExpr):

Expand Down Expand Up @@ -5853,6 +5890,156 @@ cdef class Model:

return Constraint.create(scip_cons)

def addVarSOS1(self, Constraint cons, Variable var, weight):
"""
Add variable to SOS1 constraint.

Parameters
----------
cons : Constraint
SOS1 constraint
var : Variable
new variable
weight : weight
weight of new variable

"""
PY_SCIP_CALL(SCIPaddVarSOS1(self._scip, cons.scip_cons, var.scip_var, weight))

def appendVarSOS1(self, Constraint cons, Variable var):
"""
Append variable to SOS1 constraint.

Parameters
----------
cons : Constraint
SOS1 constraint
var : Variable
variable to append

"""
PY_SCIP_CALL(SCIPappendVarSOS1(self._scip, cons.scip_cons, var.scip_var))

def getNVarsSOS1(self, Constraint cons):
"""
Get number of variables in SOS1 constraint.

Parameters
----------
cons : Constraint
SOS1 constraint

Returns
-------
int
number of variables in SOS1 constraint

"""
return SCIPgetNVarsSOS1(self._scip, cons.scip_cons)

def getVarsSOS1(self, Constraint cons):
"""
Get variables in SOS1 constraint.

Parameters
----------
cons : Constraint
SOS1 constraint

Returns
-------
list of Variable
list of variables in SOS1 constraint

"""
cdef SCIP_VAR** _vars
cdef int nvars
cdef int i
cdef Variable var
cdef list vars = []
cdef size_t ptr
nvars = SCIPgetNVarsSOS1(self._scip, cons.scip_cons)
_vars = SCIPgetVarsSOS1(self._scip, cons.scip_cons)
for i in range(nvars):
ptr = <size_t>(_vars[i])
# check whether the corresponding variable exists already
if ptr in self._modelvars:
vars.append(self._modelvars[ptr])
else:
# create a new variable
var = Variable.create(_vars[i])
assert var.ptr() == ptr
self._modelvars[ptr] = var
vars.append(var)
return vars

def getWeightsSOS1(self, Constraint cons):
"""
Get array of weights in SOS1 constraint (or NULL if not existent).

Parameters
----------
cons : Constraint
SOS1 constraint

Returns
-------
list of float
list of weights in SOS1 constraint

"""
cdef SCIP_VAR** vars
cdef SCIP_Real* weights
cdef int i

constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(cons.scip_cons))).decode('UTF-8')
if not constype == 'SOS1':
raise Warning("Weights not available for constraints of type ", constype)

vals = SCIPgetValsSOS1(self._scip, cons.scip_cons)
vars = SCIPgetVarsSOS1(self._scip, cons.scip_cons)

valsdict = {}
for i in range(SCIPgetNVarsSOS1(self._scip, cons.scip_cons)):
valsdict[bytes(SCIPvarGetName(vars[i])).decode('utf-8')] = vals[i]

return valsdict

def getNSOS1Vars(self, Conshdlr conshdlr):
"""
Gets number of problem variables that are part of the SOS1 conflict graph

Parameters
----------
conshdlr : Conshdlr
constraint handler

Returns
-------
int
number of SOS1 variables in constraint handler

"""
return SCIPgetNSOS1Vars(conshdlr.scip_conshdlr)

def makeSOS1Feasible(self, Conshdlr conshdlr, Solution sol):
"""
Makes the SOS1 conflict graph feasible

Parameters
----------
conshdlr : Conshdlr
constraint handler
sol : Solution
solution to be made feasible

"""
cdef SCIP_Bool changed
cdef SCIP_Bool success
PY_SCIP_CALL(SCIPmakeSOS1Feasible(self._scip, conshdlr.scip_conshdlr, sol.scip_sol, &changed, &success))
if not success:
raise Warning("SOS1 conflict graph could not be made feasible")

def addConsSOS2(self, vars, weights=None, name="SOS2cons",
initial=True, separate=True, enforce=True, check=True,
propagate=True, local=False, dynamic=False,
Expand Down Expand Up @@ -6317,36 +6504,6 @@ cdef class Model:
PY_SCIP_CALL(SCIPaddCons(self._scip, cons.scip_cons))
Py_INCREF(cons)

def addVarSOS1(self, Constraint cons, Variable var, weight):
"""
Add variable to SOS1 constraint.

Parameters
----------
cons : Constraint
SOS1 constraint
var : Variable
new variable
weight : weight
weight of new variable

"""
PY_SCIP_CALL(SCIPaddVarSOS1(self._scip, cons.scip_cons, var.scip_var, weight))

def appendVarSOS1(self, Constraint cons, Variable var):
"""
Append variable to SOS1 constraint.

Parameters
----------
cons : Constraint
SOS1 constraint
var : Variable
variable to append

"""
PY_SCIP_CALL(SCIPappendVarSOS1(self._scip, cons.scip_cons, var.scip_var))

def addVarSOS2(self, Constraint cons, Variable var, weight):
"""
Add variable to SOS2 constraint.
Expand Down