diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d9cd532..efd8ed922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Unreleased ### Added - Added support for knapsack constraints +- Added isPositive(), isNegative(), isFeasLE(), isFeasLT(), isFeasGE(), isFeasGT(), isHugeValue(), and tests +- Added SCIP_LOCKTYPE, addVarLocksType(), getNLocksDown(), getNLocksUp(), getNLocksDownType(), getNLocksUpType(), and tests ### Fixed ### Changed ### Removed diff --git a/src/pyscipopt/__init__.py b/src/pyscipopt/__init__.py index 3f18cb1bf..506ecd2a2 100644 --- a/src/pyscipopt/__init__.py +++ b/src/pyscipopt/__init__.py @@ -48,6 +48,7 @@ from pyscipopt.scip import PY_SCIP_PRESOLTIMING as SCIP_PRESOLTIMING from pyscipopt.scip import PY_SCIP_HEURTIMING as SCIP_HEURTIMING from pyscipopt.scip import PY_SCIP_EVENTTYPE as SCIP_EVENTTYPE +from pyscipopt.scip import PY_SCIP_LOCKTYPE as SCIP_LOCKTYPE from pyscipopt.scip import PY_SCIP_LPSOLSTAT as SCIP_LPSOLSTAT from pyscipopt.scip import PY_SCIP_BRANCHDIR as SCIP_BRANCHDIR from pyscipopt.scip import PY_SCIP_BENDERSENFOTYPE as SCIP_BENDERSENFOTYPE diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index f00f9a664..9453750e3 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -295,7 +295,6 @@ cdef extern from "scip/scip.h": SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWEVENT - ctypedef int SCIP_LPSOLQUALITY cdef extern from "lpi/type_lpi.h": SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_ESTIMCONDITION @@ -541,9 +540,9 @@ cdef extern from "scip/scip.h": ctypedef union SCIP_DOMCHG: pass - ctypedef void (*messagecallback) (SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *msg) noexcept - ctypedef void (*errormessagecallback) (void *data, FILE *file, const char *msg) - ctypedef SCIP_RETCODE (*messagehdlrfree) (SCIP_MESSAGEHDLR *messagehdlr) + ctypedef void (*messagecallback) (SCIP_MESSAGEHDLR* messagehdlr, FILE* file, const char* msg) noexcept + ctypedef void (*errormessagecallback) (void* data, FILE* file, const char* msg) + ctypedef SCIP_RETCODE (*messagehdlrfree) (SCIP_MESSAGEHDLR* messagehdlr) # General SCIP Methods SCIP_RETCODE SCIPcreate(SCIP** scip) @@ -569,15 +568,15 @@ cdef extern from "scip/scip.h": SCIP_Bool* valid) SCIP_RETCODE SCIPcopyOrigVars(SCIP* sourcescip, SCIP* targetscip, SCIP_HASHMAP* varmap, SCIP_HASHMAP* consmap, SCIP_VAR** fixedvars, SCIP_Real* fixedvals, int nfixedvars ) SCIP_RETCODE SCIPcopyOrigConss(SCIP* sourcescip, SCIP* targetscip, SCIP_HASHMAP* varmap, SCIP_HASHMAP* consmap, SCIP_Bool enablepricing, SCIP_Bool* valid) - SCIP_RETCODE SCIPmessagehdlrCreate(SCIP_MESSAGEHDLR **messagehdlr, + SCIP_RETCODE SCIPmessagehdlrCreate(SCIP_MESSAGEHDLR** messagehdlr, SCIP_Bool bufferedoutput, - const char *filename, + const char* filename, SCIP_Bool quiet, messagecallback, messagecallback, messagecallback, messagehdlrfree, - SCIP_MESSAGEHDLRDATA *messagehdlrdata) + SCIP_MESSAGEHDLRDATA* messagehdlrdata) SCIP_RETCODE SCIPsetMessagehdlr(SCIP* scip, SCIP_MESSAGEHDLR* messagehdlr) void SCIPsetMessagehdlrQuiet(SCIP* scip, SCIP_Bool quiet) @@ -787,6 +786,11 @@ cdef extern from "scip/scip.h": SCIP_RETCODE SCIPtransformVar(SCIP* scip, SCIP_VAR* var, SCIP_VAR** transvar) SCIP_RETCODE SCIPgetTransformedVar(SCIP* scip, SCIP_VAR* var, SCIP_VAR** transvar) SCIP_RETCODE SCIPaddVarLocks(SCIP* scip, SCIP_VAR* var, int nlocksdown, int nlocksup) + SCIP_RETCODE SCIPaddVarLocksType(SCIP* scip, SCIP_VAR* var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup) + int SCIPvarGetNLocksDown(SCIP_VAR* var) + int SCIPvarGetNLocksUp(SCIP_VAR* var) + int SCIPvarGetNLocksDownType(SCIP_VAR* var, SCIP_LOCKTYPE locktype) + int SCIPvarGetNLocksUpType(SCIP_VAR* var, SCIP_LOCKTYPE locktype) SCIP_VAR** SCIPgetVars(SCIP* scip) SCIP_VAR** SCIPgetOrigVars(SCIP* scip) const char* SCIPvarGetName(SCIP_VAR* var) @@ -813,11 +817,11 @@ cdef extern from "scip/scip.h": void SCIPvarSetData(SCIP_VAR* var, SCIP_VARDATA* vardata) SCIP_VARDATA* SCIPvarGetData(SCIP_VAR* var) SCIP_Real SCIPvarGetAvgSol(SCIP_VAR* var) - SCIP_Real SCIPgetVarPseudocost(SCIP* scip, SCIP_VAR *var, SCIP_BRANCHDIR dir) + SCIP_Real SCIPgetVarPseudocost(SCIP* scip, SCIP_VAR* var, SCIP_BRANCHDIR dir) SCIP_Real SCIPvarGetCutoffSum(SCIP_VAR* var, SCIP_BRANCHDIR dir) SCIP_Longint SCIPvarGetNBranchings(SCIP_VAR* var, SCIP_BRANCHDIR dir) SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR* var) - SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR * var) + SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR* var) # LP Methods SCIP_RETCODE SCIPgetLPColsData(SCIP* scip, SCIP_COL*** cols, int* ncols) @@ -831,8 +835,8 @@ cdef extern from "scip/scip.h": SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP* scip) int SCIPgetNLPRows(SCIP* scip) int SCIPgetNLPCols(SCIP* scip) - SCIP_COL** SCIPgetLPCols(SCIP *scip) - SCIP_ROW** SCIPgetLPRows(SCIP *scip) + SCIP_COL** SCIPgetLPCols(SCIP* scip) + SCIP_ROW** SCIPgetLPRows(SCIP* scip) SCIP_Bool SCIPallColsInLP(SCIP* scip) # Cutting Plane Methods @@ -872,11 +876,11 @@ cdef extern from "scip/scip.h": const char* SCIPconshdlrGetName(SCIP_CONSHDLR* conshdlr) SCIP_RETCODE SCIPdelConsLocal(SCIP* scip, SCIP_CONS* cons) SCIP_RETCODE SCIPdelCons(SCIP* scip, SCIP_CONS* cons) - SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check) - SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable) - SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial) - SCIP_RETCODE SCIPsetConsModifiable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool modifiable) - SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce) + SCIP_RETCODE SCIPsetConsChecked(SCIP* scip, SCIP_CONS* cons, SCIP_Bool check) + SCIP_RETCODE SCIPsetConsRemovable(SCIP* scip, SCIP_CONS* cons, SCIP_Bool removable) + SCIP_RETCODE SCIPsetConsInitial(SCIP* scip, SCIP_CONS* cons, SCIP_Bool initial) + SCIP_RETCODE SCIPsetConsModifiable(SCIP* scip, SCIP_CONS* cons, SCIP_Bool modifiable) + SCIP_RETCODE SCIPsetConsEnforced(SCIP* scip, SCIP_CONS* cons, SCIP_Bool enforce) # Primal Solution Methods SCIP_SOL** SCIPgetSols(SCIP* scip) @@ -906,8 +910,8 @@ cdef extern from "scip/scip.h": SCIP_Real SCIPgetGap(SCIP* scip) int SCIPgetDepth(SCIP* scip) SCIP_RETCODE SCIPcutoffNode(SCIP* scip, SCIP_NODE* node) - SCIP_Bool SCIPhasPrimalRay(SCIP * scip) - SCIP_Real SCIPgetPrimalRayVal(SCIP * scip, SCIP_VAR * var) + SCIP_Bool SCIPhasPrimalRay(SCIP* scip) + SCIP_Real SCIPgetPrimalRayVal(SCIP* scip, SCIP_VAR* var) SCIP_RETCODE SCIPaddSolFree(SCIP* scip, SCIP_SOL** sol, SCIP_Bool* stored) SCIP_RETCODE SCIPaddSol(SCIP* scip, SCIP_SOL* sol, SCIP_Bool* stored) SCIP_RETCODE SCIPreadSol(SCIP* scip, const char* filename) @@ -1051,7 +1055,7 @@ cdef extern from "scip/scip.h": SCIP_RETCODE (*consgetnvars) (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS* cons, int* nvars, SCIP_Bool* success), SCIP_RETCODE (*consgetdivebdchgs) (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_DIVESET* diveset, SCIP_SOL* sol, SCIP_Bool* success, SCIP_Bool* infeasible), SCIP_RETCODE (*consgetpermsymgraph)(SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS* cons, SYM_GRAPH* graph, SCIP_Bool* success), - SCIP_RETCODE (*consgetsignedpermsymgraph)(SCIP * scip, SCIP_CONSHDLR * conshdlr, SCIP_CONS * cons, SYM_GRAPH * graph, SCIP_Bool * success), + SCIP_RETCODE (*consgetsignedpermsymgraph)(SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS* cons, SYM_GRAPH* graph, SCIP_Bool* success), SCIP_CONSHDLRDATA* conshdlrdata) SCIP_CONSHDLRDATA* SCIPconshdlrGetData(SCIP_CONSHDLR* conshdlr) SCIP_CONSHDLR* SCIPfindConshdlr(SCIP* scip, const char* name) @@ -1339,13 +1343,17 @@ cdef extern from "scip/scip.h": SCIP_Bool SCIPisLT(SCIP* scip, SCIP_Real val1, SCIP_Real val2) SCIP_Bool SCIPisGE(SCIP* scip, SCIP_Real val1, SCIP_Real val2) SCIP_Bool SCIPisGT(SCIP* scip, SCIP_Real val1, SCIP_Real val2) - SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2) - SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2) - SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val) - SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val) - SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val) - SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val) - SCIP_Real SCIPgetTreesizeEstimation(SCIP *scip) + SCIP_Bool SCIPisEQ(SCIP* scip, SCIP_Real val1, SCIP_Real val2) + SCIP_Bool SCIPisFeasEQ(SCIP* scip, SCIP_Real val1, SCIP_Real val2) + SCIP_Bool SCIPisFeasLT(SCIP* scip, SCIP_Real val1, SCIP_Real val2) + SCIP_Bool SCIPisFeasGT(SCIP* scip, SCIP_Real val1, SCIP_Real val2) + SCIP_Bool SCIPisFeasLE(SCIP* scip, SCIP_Real val1, SCIP_Real val2) + SCIP_Bool SCIPisFeasGE(SCIP* scip, SCIP_Real val1, SCIP_Real val2) + SCIP_Bool SCIPisHugeValue(SCIP* scip, SCIP_Real val) + SCIP_Bool SCIPisPositive(SCIP* scip, SCIP_Real val) + SCIP_Bool SCIPisNegative(SCIP* scip, SCIP_Real val) + SCIP_Bool SCIPisIntegral(SCIP* scip, SCIP_Real val) + SCIP_Real SCIPgetTreesizeEstimation(SCIP* scip) # Statistic Methods SCIP_RETCODE SCIPprintStatistics(SCIP* scip, FILE* outfile) @@ -1611,12 +1619,12 @@ cdef extern from "scip/cons_sos2.h": SCIP_VAR* var) cdef extern from "scip/cons_disjunction.h": - SCIP_RETCODE SCIPcreateConsDisjunction(SCIP *scip, - SCIP_CONS **cons, - const char *name, + SCIP_RETCODE SCIPcreateConsDisjunction(SCIP* scip, + SCIP_CONS** cons, + const char* name, int nconss, - SCIP_CONS **conss, - SCIP_CONS *relaxcons, + SCIP_CONS** conss, + SCIP_CONS* relaxcons, SCIP_Bool initial, SCIP_Bool enforce, SCIP_Bool check, @@ -1624,9 +1632,9 @@ cdef extern from "scip/cons_disjunction.h": SCIP_Bool modifiable, SCIP_Bool dynamic) - SCIP_RETCODE SCIPaddConsElemDisjunction(SCIP *scip, - SCIP_CONS *cons, - SCIP_CONS *addcons) + SCIP_RETCODE SCIPaddConsElemDisjunction(SCIP* scip, + SCIP_CONS* cons, + SCIP_CONS* addcons) cdef extern from "scip/cons_and.h": SCIP_RETCODE SCIPcreateConsAnd(SCIP* scip, @@ -1963,7 +1971,7 @@ cdef extern from "scip/pub_lp.h": SCIP_Real* SCIPcolGetVals(SCIP_COL* col) int SCIPcolGetAge(SCIP_COL* col) int SCIPcolGetIndex(SCIP_COL* col) - SCIP_Real SCIPcolGetObj(SCIP_COL *col) + SCIP_Real SCIPcolGetObj(SCIP_COL* col) cdef extern from "scip/scip_tree.h": SCIP_RETCODE SCIPgetOpenNodesData(SCIP* scip, SCIP_NODE*** leaves, SCIP_NODE*** children, SCIP_NODE*** siblings, int* nleaves, int* nchildren, int* nsiblings) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 900a8c1fb..53bed228f 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -255,6 +255,9 @@ cdef class PY_SCIP_EVENTTYPE: ROWCHANGED = SCIP_EVENTTYPE_ROWCHANGED ROWEVENT = SCIP_EVENTTYPE_ROWEVENT +cdef class PY_SCIP_LOCKTYPE: + MODEL = SCIP_LOCKTYPE_MODEL + CONFLICT = SCIP_LOCKTYPE_CONFLICT cdef class PY_SCIP_LPSOLSTAT: NOTSOLVED = SCIP_LPSOLSTAT_NOTSOLVED @@ -1671,6 +1674,60 @@ cdef class Variable(Expr): """ return SCIPvarGetAvgSol(self.scip_var) + def getNLocksDown(self): + """ + Returns the number of locks for rounding down. + + Returns + ------- + int + + """ + return SCIPvarGetNLocksDown(self.scip_var) + + def getNLocksUp(self): + """ + Returns the number of locks for rounding up. + + Returns + ------- + int + + """ + return SCIPvarGetNLocksUp(self.scip_var) + + def getNLocksDownType(self, locktype): + """ + Returns the number of locks for rounding down of a certain type. + + Parameters + ---------- + locktype : SCIP_LOCKTYPE + type of variable locks + + Returns + ------- + int + + """ + return SCIPvarGetNLocksDownType(self.scip_var, locktype) + + def getNLocksUpType(self, locktype): + """ + Returns the number of locks for rounding up of a certain type. + + Parameters + ---------- + locktype : SCIP_LOCKTYPE + type of variable locks + + Returns + ------- + int + + """ + return SCIPvarGetNLocksUpType(self.scip_var, locktype) + def varMayRound(self, direction="down"): """ Checks whether it is possible to round variable up / down and stay feasible for the relaxation. @@ -3070,7 +3127,7 @@ cdef class Model: def isFeasEQ(self, val1, val2): """ - Checks, if relative difference of values is in range of feasibility tolerance. + Returns if relative difference between val1 and val2 is in range of feasibility tolerance. Parameters ---------- @@ -3083,6 +3140,70 @@ cdef class Model: """ return SCIPisFeasEQ(self._scip, val1, val2) + + def isFeasLT(self, val1, val2): + """ + Returns whether relative difference between val1 and val2 is lower than minus feasibility tolerance. + + Parameters + ---------- + val1 : float + val2 : float + + Returns + ------- + bool + + """ + return SCIPisFeasLT(self._scip, val1, val2) + + def isFeasLE(self, val1, val2): + """ + Returns whether relative difference between val1 and val2 is not greater than feasibility tolerance. + + Parameters + ---------- + val1 : float + val2 : float + + Returns + ------- + bool + + """ + return SCIPisFeasLE(self._scip, val1, val2) + + def isFeasGT(self, val1, val2): + """ + Returns whether relative difference between val1 and val2 is greater than feasibility tolerance. + + Parameters + ---------- + val1 : float + val2 : float + + Returns + ------- + bool + + """ + return SCIPisFeasGT(self._scip, val1, val2) + + def isFeasGE(self, val1, val2): + """ + Returns whether relative difference of val1 and val2 is not lower than minus feasibility tolerance. + + Parameters + ---------- + val1 : float + val2 : float + + Returns + ------- + bool + + """ + return SCIPisFeasGE(self._scip, val1, val2) def isLE(self, val1, val2): """ @@ -3792,7 +3913,7 @@ cdef class Model: return Variable.create(_tvar) - def addVarLocks(self, Variable var, nlocksdown, nlocksup): + def addVarLocks(self, Variable var, int nlocksdown, int nlocksup): """ Adds given values to lock numbers of variable for rounding. @@ -3808,6 +3929,24 @@ cdef class Model: """ PY_SCIP_CALL(SCIPaddVarLocks(self._scip, var.scip_var, nlocksdown, nlocksup)) + def addVarLocksType(self, Variable var, int locktype, int nlocksdown, int nlocksup): + """ + adds given values to lock numbers of type locktype of variable for rounding + + Parameters + ---------- + var : Variable + variable to adjust the locks for + locktype : SCIP_LOCKTYPE + type of variable locks + nlocksdown : int + modification in number of down locks + nlocksup : int + modification in number of up locks + + """ + PY_SCIP_CALL(SCIPaddVarLocksType(self._scip, var.scip_var, locktype, nlocksdown, nlocksup)) + def fixVar(self, Variable var, val): """ Fixes the variable var to the value val if possible. diff --git a/tests/helpers/utils.py b/tests/helpers/utils.py index c9e63f4f4..8aadfbbe8 100644 --- a/tests/helpers/utils.py +++ b/tests/helpers/utils.py @@ -51,17 +51,20 @@ def random_mip_1(disable_sepa=True, disable_heur=True, disable_presolve=True, no def random_lp_1(): - return random_mip_1().relax() + model = random_mip_1() + model.relax() + + return model def random_nlp_1(): model = Model() - v = model.addVar() - w = model.addVar() - x = model.addVar() - y = model.addVar() - z = model.addVar() + v = model.addVar(name="v") + w = model.addVar(name="w") + x = model.addVar(name="x") + y = model.addVar(name="y", ub=1.4) + z = model.addVar(name="z", ub=4) model.addCons(exp(v) + log(w) + sqrt(x) + sin(y) + z ** 3 * y <= 5) model.setObjective(v + w + x + y + z, sense='maximize') @@ -87,7 +90,7 @@ def knapsack_model(weights=[4, 2, 6, 3, 7, 5], costs=[7, 2, 5, 4, 3, 4], knapsac knapsackVars.append(s.addVar(varNames[i], vtype='I', obj=costs[i], ub=1.0)) # adding a linear constraint for the knapsack constraint - s.addCons(quicksum(w * v for (w, v) in zip(weights, knapsackVars)) <= knapsackSize) + s.addCons(quicksum(w * v for (w, v) in zip(weights, knapsackVars)) <= knapsack_size) return s @@ -241,12 +244,19 @@ def gastrans_model(): def knapsack_lp(weights, costs): - return knapsack_model(weights, costs).relax() + model = knapsack_model(weights, costs) + model.relax() + return model def bin_packing_lp(sizes, capacity): - return bin_packing_model(sizes, capacity).relax() + model = bin_packing_model(sizes, capacity) + model.relax() + return model def gastrans_lp(): - return gastrans_model().relax() + model = gastrans_model() + model.relax() + + return model diff --git a/tests/test_conshdlr.py b/tests/test_conshdlr.py index 9b27a8c2d..480b5adec 100644 --- a/tests/test_conshdlr.py +++ b/tests/test_conshdlr.py @@ -1,4 +1,4 @@ -from pyscipopt import Model, Conshdlr, SCIP_RESULT, SCIP_PRESOLTIMING, SCIP_PROPTIMING +from pyscipopt import Model, Conshdlr, SCIP_RESULT, SCIP_PRESOLTIMING, SCIP_PROPTIMING, SCIP_LOCKTYPE from sys import version_info if version_info >= (3, 3): @@ -68,6 +68,30 @@ def conslock(self, constraint, locktype, nlockspos, nlocksneg): calls.add("conslock") assert id(constraint) in ids + try: + var = self.model.data["x"] + except ReferenceError: + return + + n_locks_down = var.getNLocksDown() + n_locks_up = var.getNLocksUp() + n_locks_down_model = var.getNLocksDownType(SCIP_LOCKTYPE.MODEL) + n_locks_down_conflict = var.getNLocksDownType(SCIP_LOCKTYPE.CONFLICT) + n_locks_up_model = var.getNLocksUpType(SCIP_LOCKTYPE.MODEL) + n_locks_up_conflict = var.getNLocksUpType(SCIP_LOCKTYPE.CONFLICT) + + self.model.addVarLocksType(var, locktype, nlockspos, nlocksneg) + if locktype == SCIP_LOCKTYPE.MODEL: + assert var.getNLocksDownType(SCIP_LOCKTYPE.MODEL) != n_locks_down_model or var.getNLocksUpType(SCIP_LOCKTYPE.MODEL) != n_locks_up_model + assert var.getNLocksDownType(SCIP_LOCKTYPE.CONFLICT) == n_locks_down_conflict and var.getNLocksUpType(SCIP_LOCKTYPE.CONFLICT) == n_locks_up_conflict + elif locktype == SCIP_LOCKTYPE.CONFLICT: + assert var.getNLocksDownType(SCIP_LOCKTYPE.MODEL) == n_locks_down_model and var.getNLocksUpType(SCIP_LOCKTYPE.MODEL) == n_locks_up_model + assert var.getNLocksDownType(SCIP_LOCKTYPE.CONFLICT) != n_locks_down_conflict or var.getNLocksUpType(SCIP_LOCKTYPE.CONFLICT) != n_locks_up_conflict + else: + raise ValueError("Unknown locktype") + + assert var.getNLocksDown() != n_locks_down or var.getNLocksUp() != n_locks_up + ## callbacks ## def consfree(self): calls.add("consfree") @@ -187,43 +211,46 @@ def consgetnvars(self, constraint): def test_conshdlr(): def create_model(): # create solver instance - s = Model() + model = Model() # add some variables - x = s.addVar("x", obj = -1.0, vtype = "I", lb=-10) - y = s.addVar("y", obj = 1.0, vtype = "I", lb=-1000) - z = s.addVar("z", obj = 1.0, vtype = "I", lb=-1000) + x = model.addVar("x", obj = -1.0, vtype = "I", lb=-10) + y = model.addVar("y", obj = 1.0, vtype = "I", lb=-1000) + z = model.addVar("z", obj = 1.0, vtype = "I", lb=-1000) + + model.data = {} + model.data["x"] = x # add some constraint - s.addCons(314*x + 867*y + 860*z == 363) - s.addCons(87*x + 875*y - 695*z == 423) + model.addCons(314*x + 867*y + 860*z == 363) + model.addCons(87*x + 875*y - 695*z == 423) # create conshdlr and include it to SCIP conshdlr = MyConshdlr(shouldtrans=True, shouldcopy=False) - s.includeConshdlr(conshdlr, "PyCons", "custom constraint handler implemented in python", + model.includeConshdlr(conshdlr, "PyCons", "custom constraint handler implemented in python", sepapriority = 1, enfopriority = 1, chckpriority = 1, sepafreq = 10, propfreq = 50, eagerfreq = 1, maxprerounds = -1, delaysepa = False, delayprop = False, needscons = True, presoltiming = SCIP_PRESOLTIMING.FAST, proptiming = SCIP_PROPTIMING.BEFORELP) - cons1 = s.createCons(conshdlr, "cons1name") + cons1 = model.createCons(conshdlr, "cons1name") ids.append(id(cons1)) - cons2 = s.createCons(conshdlr, "cons2name") + cons2 = model.createCons(conshdlr, "cons2name") ids.append(id(cons2)) conshdlr.createData(cons1, 10, "cons1_anothername") conshdlr.createData(cons2, 12, "cons2_anothername") # add these constraints - s.addPyCons(cons1) - s.addPyCons(cons2) - return s + model.addPyCons(cons1) + model.addPyCons(cons2) + return model - s = create_model() + model = create_model() # solve problem - s.optimize() + model.optimize() # so that consfree gets called - del s + del model # check callbacks got called assert "consenfolp" in calls @@ -249,4 +276,4 @@ def create_model(): assert "consdisable" in calls #assert "consdelvars" in calls #assert "consprint" in calls - assert "consgetnvars" in calls \ No newline at end of file + assert "consgetnvars" in calls diff --git a/tests/test_numerics.py b/tests/test_numerics.py new file mode 100644 index 000000000..964e6c216 --- /dev/null +++ b/tests/test_numerics.py @@ -0,0 +1,22 @@ +from pyscipopt import Model +import pytest + +def test_numerical_checks(): + m = Model() + + m.setParam("numerics/epsilon", 1e-10) + m.setParam("numerics/feastol", 1e-3) + + assert m.isFeasEQ(1, 1.00001) + assert not m.isEQ(1, 1.00001) + + assert m.isFeasLE(1, 0.99999) + assert not m.isLE(1, 0.99999) + + assert m.isFeasGE(1, 1.00001) + assert not m.isGE(1, 1.00001) + + assert not m.isFeasGT(1, 0.99999) + assert m.isGT(1, 0.99999) + +test_numerical_checks()