From 7cc64e5625013b06bc8a4196c771e28395ca7a00 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 1 Nov 2023 16:51:21 +0100 Subject: [PATCH 01/54] Clean up test_customizedbenders --- tests/test_customizedbenders.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/test_customizedbenders.py b/tests/test_customizedbenders.py index d72c7942c..146d80279 100644 --- a/tests/test_customizedbenders.py +++ b/tests/test_customizedbenders.py @@ -188,7 +188,7 @@ def make_data(): return I,J,d,M,f,c -def test_flpbenders_defcuts(): +def flpbenders_defcuts_test(): ''' test the Benders' decomposition plugins with the facility location problem. ''' @@ -235,7 +235,7 @@ def test_flpbenders_defcuts(): return master.getObjVal() -def test_flpbenders_customcuts(): +def flpbenders_customcuts_test(): ''' test the Benders' decomposition plugins with the facility location problem. ''' @@ -285,7 +285,7 @@ def test_flpbenders_customcuts(): return master.getObjVal() -def test_flp(): +def flp_test(): ''' test the Benders' decomposition plugins with the facility location problem. ''' @@ -309,10 +309,11 @@ def test_flp(): return master.getObjVal() -if __name__ == "__main__": - defcutsobj = test_flpbenders_defcuts() - customcutsobj = test_flpbenders_customcuts() - monolithicobj = test_flp() + +def test_customized_benders(): + defcutsobj = flpbenders_defcuts_test() + customcutsobj = flpbenders_customcuts_test() + monolithicobj = flp_test() assert defcutsobj == customcutsobj assert defcutsobj == monolithicobj From fec98e32f776da1c1cf6ac9912448e2a485b7c0c Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 1 Nov 2023 17:00:11 +0100 Subject: [PATCH 02/54] Remove __name__ == "__main__" --- tests/test_alldiff.py | 5 +---- tests/test_benders.py | 6 +----- tests/test_branch_probing_lp.py | 5 +---- tests/test_conshdlr.py | 5 +---- tests/test_copy.py | 3 --- tests/test_cutsel.py | 4 ---- tests/test_event.py | 3 --- tests/test_gomory.py | 3 --- tests/test_heur.py | 3 --- tests/test_knapsack.py | 5 +---- tests/test_lp.py | 3 --- tests/test_memory.py | 6 +----- tests/test_model.py | 9 --------- tests/test_nlrow.py | 3 --- tests/test_nodesel.py | 6 +----- tests/test_nonlinear.py | 9 +-------- tests/test_pricer.py | 7 +------ tests/test_quadcons.py | 6 +----- tests/test_quickprod.py | 5 ----- tests/test_quicksum.py | 5 ----- tests/test_reader.py | 8 ++------ tests/test_relax.py | 6 +----- tests/test_solution.py | 5 ----- tests/test_tree.py | 5 +---- tests/test_tsp.py | 6 +----- tests/test_vars.py | 6 +----- 26 files changed, 16 insertions(+), 121 deletions(-) diff --git a/tests/test_alldiff.py b/tests/test_alldiff.py index efe9bec47..c14dd1bff 100644 --- a/tests/test_alldiff.py +++ b/tests/test_alldiff.py @@ -298,7 +298,4 @@ def test_main(): out = '' for col in range(9): out += str(round(scip.getVal(x[row,col]))) + ' ' - print(out) - -if __name__ == "__main__": - test_main() + print(out) \ No newline at end of file diff --git a/tests/test_benders.py b/tests/test_benders.py index c4a72df51..2273b5d48 100644 --- a/tests/test_benders.py +++ b/tests/test_benders.py @@ -106,8 +106,4 @@ def test_flpbenders(): # the solution will be lost master.freeBendersSubproblems() - assert master.getObjVal() == 5.61e+03 - - -if __name__ == "__main__": - test_flpbenders() + assert master.getObjVal() == 5.61e+03 \ No newline at end of file diff --git a/tests/test_branch_probing_lp.py b/tests/test_branch_probing_lp.py index 45fd8e724..b699ce9a1 100644 --- a/tests/test_branch_probing_lp.py +++ b/tests/test_branch_probing_lp.py @@ -92,7 +92,4 @@ def test_branching(): print("t", m.getVal(t)) assert my_branchrule.was_called_val - assert my_branchrule.was_called_int - -if __name__ == "__main__": - test_branching() + assert my_branchrule.was_called_int \ No newline at end of file diff --git a/tests/test_conshdlr.py b/tests/test_conshdlr.py index 45c42852f..9b27a8c2d 100644 --- a/tests/test_conshdlr.py +++ b/tests/test_conshdlr.py @@ -249,7 +249,4 @@ def create_model(): assert "consdisable" in calls #assert "consdelvars" in calls #assert "consprint" in calls - assert "consgetnvars" in calls - -if __name__ == "__main__": - test_conshdlr() + assert "consgetnvars" in calls \ No newline at end of file diff --git a/tests/test_copy.py b/tests/test_copy.py index b256452f2..b518d0a13 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -18,6 +18,3 @@ def test_copy(): s2.optimize() assert s.getObjVal() == s2.getObjVal() - -if __name__ == "__main__": - test_copy() diff --git a/tests/test_cutsel.py b/tests/test_cutsel.py index a0c193031..22d5ac45d 100644 --- a/tests/test_cutsel.py +++ b/tests/test_cutsel.py @@ -79,7 +79,3 @@ def test_cut_selector(): scip.setObjective(quicksum(c[i] * e[i] for i in range(len(A))), sense='minimize') scip.optimize() - - -if __name__ == "__main__": - test_cut_selector() diff --git a/tests/test_event.py b/tests/test_event.py index b595945b7..72c518073 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -48,6 +48,3 @@ def test_event(): assert 'eventexit' in calls assert 'eventexec' in calls assert len(calls) == 3 - -if __name__ == "__main__": - test_event() diff --git a/tests/test_gomory.py b/tests/test_gomory.py index b6f209b3c..b95537045 100644 --- a/tests/test_gomory.py +++ b/tests/test_gomory.py @@ -340,6 +340,3 @@ def test_CKS(): # solve problem s.optimize() s.printStatistics() - -if __name__ == "__main__": - test_CKS() diff --git a/tests/test_heur.py b/tests/test_heur.py index 1f1ade8fe..3ec3d62ba 100644 --- a/tests/test_heur.py +++ b/tests/test_heur.py @@ -64,6 +64,3 @@ def inner(): heur_prox.name assert is_memory_freed() - -if __name__ == "__main__": - test_heur() diff --git a/tests/test_knapsack.py b/tests/test_knapsack.py index 359f3256b..2634a4a24 100644 --- a/tests/test_knapsack.py +++ b/tests/test_knapsack.py @@ -45,7 +45,4 @@ def test_knapsack(): print ("\tIncluded Weight:", weights[i]*solValue, "\tItem Cost:", costs[i]*solValue) includedWeight = sum([weights[i]*varSolutions[i] for i in range(len(weights))]) - assert includedWeight > 0 and includedWeight <= knapsackSize - -if __name__ == "__main__": - test_knapsack() + assert includedWeight > 0 and includedWeight <= knapsackSize \ No newline at end of file diff --git a/tests/test_lp.py b/tests/test_lp.py index 98314e487..299ce122c 100644 --- a/tests/test_lp.py +++ b/tests/test_lp.py @@ -20,6 +20,3 @@ def test_lp(): solval = myLP.solve() assert round(5.0 == solval) - -if __name__ == "__main__": - test_lp() diff --git a/tests/test_memory.py b/tests/test_memory.py index 13735687d..173d109ab 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -13,8 +13,4 @@ def test_freed(): pytest.skip() m = Model() del m - assert is_memory_freed() - -if __name__ == "__main__": - test_not_freed() - test_freed() + assert is_memory_freed() \ No newline at end of file diff --git a/tests/test_model.py b/tests/test_model.py index f86fac33b..aa987a448 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -182,12 +182,3 @@ def test_model_ptr(): with pytest.raises(ValueError): Model.from_ptr("some gibberish", take_ownership=False) - - -if __name__ == "__main__": - test_model() - test_solve_concurrent() - test_multiple_cons_simple() - test_multiple_cons_names() - test_multiple_cons_params() - test_model_ptr() diff --git a/tests/test_nlrow.py b/tests/test_nlrow.py index 63e12d68e..94b876ca1 100644 --- a/tests/test_nlrow.py +++ b/tests/test_nlrow.py @@ -65,6 +65,3 @@ def test_nlrow(): linterms = nlrows[2].getLinearTerms() assert len(linterms) == 0 - -if __name__ == "__main__": - test_nlrow() diff --git a/tests/test_nodesel.py b/tests/test_nodesel.py index 665ac07ee..2fa4254e9 100644 --- a/tests/test_nodesel.py +++ b/tests/test_nodesel.py @@ -41,8 +41,4 @@ def test_nodesel(): m.addCons(x1 * x2 >= x0) m.setObjective(x1 + x0) - m.optimize() - - -if __name__ == "__main__": - test_nodesel() + m.optimize() \ No newline at end of file diff --git a/tests/test_nonlinear.py b/tests/test_nonlinear.py index 35df5a14f..528ed383c 100644 --- a/tests/test_nonlinear.py +++ b/tests/test_nonlinear.py @@ -284,11 +284,4 @@ def test_quad_coeffs(): assert quadterms[0][1] == 0.5 assert linterms[0][0].name == z.name - assert linterms[0][1] == 4 - -if __name__ == "__main__": - test_string_poly() - test_string() - test_circle() - test_gastrans() - test_quad_coeffs() + assert linterms[0][1] == 4 \ No newline at end of file diff --git a/tests/test_pricer.py b/tests/test_pricer.py index 111b0452e..7c7a83e2e 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -155,9 +155,4 @@ class IncompletePricer(Pricer): model.includePricer(pricer, "", "") with pytest.raises(Exception): - model.optimize() - - -if __name__ == '__main__': - test_cuttingstock() - test_incomplete_pricer() + model.optimize() \ No newline at end of file diff --git a/tests/test_quadcons.py b/tests/test_quadcons.py index 6170a7375..3c378c189 100644 --- a/tests/test_quadcons.py +++ b/tests/test_quadcons.py @@ -25,8 +25,4 @@ def test_niceqcqp(): s.optimize() assert round(s.getVal(x)) == 1.0 - assert round(s.getVal(y)) == 1.0 - -if __name__ == "__main__": - test_niceqp() - test_niceqcqp() + assert round(s.getVal(y)) == 1.0 \ No newline at end of file diff --git a/tests/test_quickprod.py b/tests/test_quickprod.py index 04b26e2c6..70e767047 100644 --- a/tests/test_quickprod.py +++ b/tests/test_quickprod.py @@ -35,8 +35,3 @@ def test_largequadratic(): assert cons.expr.degree() == 2*dim*dim m.addCons(cons) # TODO: what can we test beyond the lack of crashes? - -if __name__ == "__main__": - test_quickprod() - test_quickprod_model() - test_largequadratic() diff --git a/tests/test_quicksum.py b/tests/test_quicksum.py index 83c5de11a..3ac8f26ae 100644 --- a/tests/test_quicksum.py +++ b/tests/test_quicksum.py @@ -33,8 +33,3 @@ def test_largequadratic(): assert len(cons.expr.terms) == dim * (dim-1) / 2 + dim m.addCons(cons) # TODO: what can we test beyond the lack of crashes? - -if __name__ == "__main__": - test_quicksum() - test_quicksum_model() - test_largequadratic() diff --git a/tests/test_reader.py b/tests/test_reader.py index 6debe458e..b812560ff 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -59,7 +59,7 @@ def createFile(filename): def deleteFile(filename): os.remove(filename) -def test(): +def test_main(): createFile("tmp.sod") m = Model("soduko") @@ -78,8 +78,4 @@ def test(): input = f.readline() assert input == "soduko" - deleteFile("model.sod") - - -if __name__ == "__main__": - test() + deleteFile("model.sod") \ No newline at end of file diff --git a/tests/test_relax.py b/tests/test_relax.py index 480cd9040..5ecdfed23 100644 --- a/tests/test_relax.py +++ b/tests/test_relax.py @@ -29,8 +29,4 @@ def test_relax(): m.optimize() assert 'relaxexec' in calls - assert len(calls) >= 1 - - -if __name__ == "__main__": - test_relax() + assert len(calls) >= 1 \ No newline at end of file diff --git a/tests/test_solution.py b/tests/test_solution.py index 497c6d52c..e2927bfdb 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -61,8 +61,3 @@ def test_solution_evaluation(): assert sol[y] == m.getVal(y) assert sol[expr] == m.getVal(expr) assert sol[expr2] == m.getVal(expr2) - - -if __name__ == "__main__": - test_solution_getbest() - test_solution_create() diff --git a/tests/test_tree.py b/tests/test_tree.py index 74f0c7e69..58b121508 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -60,7 +60,4 @@ def test_tree(): del s - assert len(node_eventhdlr.calls) > 3 - -if __name__ == "__main__": - test_tree() + assert len(node_eventhdlr.calls) > 3 \ No newline at end of file diff --git a/tests/test_tsp.py b/tests/test_tsp.py index c6fb86dad..127fc267c 100644 --- a/tests/test_tsp.py +++ b/tests/test_tsp.py @@ -111,8 +111,4 @@ def test_main(): objective_value, edges = solve_tsp(vertices, distance) print("Optimal tour:", edges) - print("Optimal cost:", objective_value) - - -if __name__ == "__main__": - test_main() + print("Optimal cost:", objective_value) \ No newline at end of file diff --git a/tests/test_vars.py b/tests/test_vars.py index b55366a80..d8c92ff40 100644 --- a/tests/test_vars.py +++ b/tests/test_vars.py @@ -64,8 +64,4 @@ def test_vtype(): assert x.vtype() == "INTEGER" m.chgVarType(y, 'M') - assert y.vtype() == "IMPLINT" - -if __name__ == "__main__": - test_variablebounds() - test_vtype() + assert y.vtype() == "IMPLINT" \ No newline at end of file From ed54375aae1b1656840a0960041465fe144b1032 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 10:25:00 +0100 Subject: [PATCH 03/54] Add test_getSolTime --- tests/test_solution.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_solution.py b/tests/test_solution.py index e2927bfdb..8243542ab 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -1,4 +1,4 @@ -from pyscipopt import Model +from pyscipopt import Model, SCIP_PARAMSETTING, quicksum, quickprod def test_solution_getbest(): @@ -61,3 +61,20 @@ def test_solution_evaluation(): assert sol[y] == m.getVal(y) assert sol[expr] == m.getVal(expr) assert sol[expr2] == m.getVal(expr2) + +def test_getSolTime(): + m = Model() + m.setPresolve(SCIP_PARAMSETTING.OFF) + + x = {} + for i in range(20): + x[i] = m.addVar(ub=i) + + for i in range(1,6): + m.addCons(quicksum(x[j] for j in range(20) if j%i==0) >= i) + m.addCons(quickprod(x[j] for j in range(20) if j%i==0) <= i**3) + + m.setObjective(quicksum(x[i] for i in range(20))) + m.optimize() + for s in m.getSols(): + assert type(m.getSolTime(s)) == float From b8282bc4f0409a4b75ac474e1cf9b2ca13ae7a48 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 10:54:03 +0100 Subject: [PATCH 04/54] Add test for getVarRedcost --- tests/test_pricer.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_pricer.py b/tests/test_pricer.py index 7c7a83e2e..08a9c2ed3 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -10,6 +10,7 @@ def pricerredcost(self): dualSolutions = [] for i, c in enumerate(self.data['cons']): dualSolutions.append(self.model.getDualsolLinear(c)) + #assert self.model.getDualsolLinear(c) == self.model.getDualSolVal(c) # Building a MIP to solve the subproblem subMIP = Model("CuttingStock-Sub") @@ -38,6 +39,7 @@ def pricerredcost(self): objval = 1 + subMIP.getObjVal() + # Adding the column to the master problem if objval < -1e-08: currentNumVar = len(self.data['var']) @@ -53,6 +55,9 @@ def pricerredcost(self): newPattern.append(coeff) + # Testing getVarRedcost + assert round(self.model.getVarRedcost(newVar),6) == round(objval,6) + # Storing the new variable in the pricer data. self.data['patterns'].append(newPattern) self.data['var'].append(newVar) @@ -112,6 +117,7 @@ def test_cuttingstock(): pricer.data['demand'] = demand pricer.data['rollLength'] = rollLength pricer.data['patterns'] = patterns + pricer.data['redcosts'] = [] # solve problem s.optimize() @@ -142,7 +148,7 @@ def test_cuttingstock(): print(outline) print('\t\t\tTotal Output:\t', '\t'.join(str(e) for e in widthOutput)) - + assert s.getObjVal() == 452.25 def test_incomplete_pricer(): From cf69d027803e813ba3bda1c44d192b054acfda76 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 11:06:51 +0100 Subject: [PATCH 05/54] Add test for getConss, getNConss --- tests/test_model.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_model.py b/tests/test_model.py index aa987a448..1ca806564 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -141,6 +141,8 @@ def test_multiple_cons_names(): assert len(conss) == 5 assert all([c.name.startswith(name + "_") for c in conss]) + assert conss == m.getConss() + assert m.getNConss() == 5 def test_multiple_cons_params(): From 59980b740dfedb86ee7a2c6edd75588290f597d9 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 11:13:20 +0100 Subject: [PATCH 06/54] Add test for getNNlRows, printNlRow --- tests/test_nlrow.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_nlrow.py b/tests/test_nlrow.py index 94b876ca1..64bed80ce 100644 --- a/tests/test_nlrow.py +++ b/tests/test_nlrow.py @@ -35,6 +35,13 @@ def test_nlrow(): # collect nonlinear rows nlrows = m.getNlRows() + + # test getNNlRows + assert len(nlrows) == m.getNNlRows() + + # to test printing of NLRows + for row in nlrows: + m.printNlRow(row) # the nlrow that corresponds to the linear (third) constraint is added before the nonlinear rows, # because Initsol of the linear conshdlr gets called first From 7b5fab5f887de1afd3381f6245b7bee2eca9029d Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 11:33:47 +0100 Subject: [PATCH 07/54] Add test for add/del/chgCoefLinear --- tests/test_model.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/test_model.py b/tests/test_model.py index 1ca806564..0c2dabf63 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -172,6 +172,38 @@ def assert_conss_neq(a, b): assert_conss_neq(conss[0], conss[1]) +def test_addCoefLinear(): + m = Model() + x = m.addVar(obj=1) + y = m.addVar() + c = m.addCons(x >= 1) + + m.addCoefLinear(c, y, 1) + + m.optimize() + assert m.getVal(x) == 0 + +def test_delCoefLinear(): + m = Model() + x = m.addVar(obj=1) + y = m.addVar(obj=0) + c = m.addCons(x + y >= 1) + + m.delCoefLinear(c,y) + + m.optimize() + assert m.getVal(x) == 1 + +def test_chgCoefLinear(): + m = Model() + x = m.addVar(obj=10) + y = m.addVar(obj=1) + c = m.addCons(x + y >= 1) + + m.chgCoefLinear(c, y, 0.001) + + m.optimize() + assert m.getObjVal() == 10 def test_model_ptr(): model1 = Model() From 5930777bb425d4a5d52ad89d00130aabb38dab57 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 11:34:10 +0100 Subject: [PATCH 08/54] Add tests for setting cons options --- tests/test_cons.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/test_cons.py diff --git a/tests/test_cons.py b/tests/test_cons.py new file mode 100644 index 000000000..55f67f25b --- /dev/null +++ b/tests/test_cons.py @@ -0,0 +1,19 @@ +import pytest + +from pyscipopt import Model + +def test_constraint_option_setting(): + m = Model() + x = m.addVar() + c = m.addCons(x >= 3) + + for option in [True, False]: + m.setCheck(c, option) + m.setEnforced(c, option) + m.setRemovable(c, option) + m.setInitial(c, option) + + assert c.isChecked() == option + assert c.isEnforced() == option + assert c.isRemovable() == option + assert c.isInitial() == option From 61f1450ae31b47bc69b1b8edbdb91d46d1ed671f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 3 Nov 2023 10:47:20 +0000 Subject: [PATCH 09/54] Update test_solution.py --- tests/test_solution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_solution.py b/tests/test_solution.py index cb2c40796..a202c6dd1 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -77,7 +77,7 @@ def test_getSolTime(): m.setObjective(quicksum(x[i] for i in range(20))) m.optimize() for s in m.getSols(): - m.getSolTime(s)) + m.getSolTime(s) def test_create_solution(): with pytest.raises(ValueError): @@ -98,4 +98,4 @@ def test_getSols(): m.optimize() assert len(m.getSols()) >= 1 - assert any(sol[x] == 0.0 for sol in m.getSols()) \ No newline at end of file + assert any(sol[x] == 0.0 for sol in m.getSols()) From 7398a9324424e3847dea210c4523326606cc7e75 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 3 Nov 2023 12:39:53 +0100 Subject: [PATCH 10/54] Fix sudoku typo --- tests/test_reader.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_reader.py b/tests/test_reader.py index b812560ff..2f4712271 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -59,13 +59,13 @@ def createFile(filename): def deleteFile(filename): os.remove(filename) -def test_main(): +def test_sudoku_reader(): createFile("tmp.sod") - m = Model("soduko") + m = Model("sudoku") reader = SudokuReader() - m.includeReader(reader, "sodreader", "PyReader for soduko problem", "sod") + m.includeReader(reader, "sudreader", "PyReader for sudoku problem", "sod") m.readProblem("tmp.sod") @@ -76,6 +76,6 @@ def test_main(): m.writeProblem("model.sod") with open("model.sod", "r") as f: input = f.readline() - assert input == "soduko" + assert input == "sudoku" deleteFile("model.sod") \ No newline at end of file From f01ace05e3b076afef47817d613abf89fd87917c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:44:19 +0000 Subject: [PATCH 11/54] Update test_model.py --- tests/test_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_model.py b/tests/test_model.py index de764e1b6..991d95e1b 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -175,7 +175,7 @@ def assert_conss_neq(a, b): def test_addCoefLinear(): m = Model() x = m.addVar(obj=1) - y = m.addVar() + y = m.addVar(obj=0) c = m.addCons(x >= 1) m.addCoefLinear(c, y, 1) @@ -250,4 +250,4 @@ def test_getVarsDict(): var_dict = model.getVarDict() for v in x.values(): assert v.name in var_dict - assert model.getVal(v) == var_dict[v.name] \ No newline at end of file + assert model.getVal(v) == var_dict[v.name] From 20f75f1f3ec2c264a4ad734d0094972efaa09d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:47:59 +0000 Subject: [PATCH 12/54] Update test_solution.py --- tests/test_solution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_solution.py b/tests/test_solution.py index a202c6dd1..933dfa5de 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -77,7 +77,7 @@ def test_getSolTime(): m.setObjective(quicksum(x[i] for i in range(20))) m.optimize() for s in m.getSols(): - m.getSolTime(s) + assert m.getSolTime(s) >= 0 def test_create_solution(): with pytest.raises(ValueError): From a31ab0f166c867f936cedd9f16f3302566ed5c6e Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Mon, 6 Nov 2023 09:32:57 +0100 Subject: [PATCH 13/54] Remove comment --- tests/test_pricer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_pricer.py b/tests/test_pricer.py index 08a9c2ed3..ebae4eb46 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -10,7 +10,6 @@ def pricerredcost(self): dualSolutions = [] for i, c in enumerate(self.data['cons']): dualSolutions.append(self.model.getDualsolLinear(c)) - #assert self.model.getDualsolLinear(c) == self.model.getDualSolVal(c) # Building a MIP to solve the subproblem subMIP = Model("CuttingStock-Sub") From c57ad293d689b41cc98e5a3b1a00401ddfa5eea3 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 10 Nov 2023 16:00:16 +0100 Subject: [PATCH 14/54] Run full integration tests only on master --- .github/workflows/coverage.yml | 5 +++-- .github/workflows/integration-test.yml | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9692b312a..9d75d6dd3 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,12 +2,13 @@ name: Run tests with coverage env: version: 8.0.3 -# runs on branches and pull requests; doesn't run on tags. on: push: branches: - - '**' + - 'master' pull_request: + branches: + - 'master' jobs: diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index fc49d2fde..795e63d71 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -7,8 +7,7 @@ env: on: push: branches: - - '**' - pull_request: + - 'master' jobs: From 14c8486543971e2e732cabb32ae9286e31763e9c Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Mon, 13 Nov 2023 12:25:06 +0100 Subject: [PATCH 15/54] Make solution print test more reliable --- tests/test_solution.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_solution.py b/tests/test_solution.py index 33c654c39..8dcba59dc 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -1,3 +1,4 @@ +import re import pytest from pyscipopt import Model, scip, SCIP_PARAMSETTING, quicksum, quickprod @@ -124,13 +125,14 @@ def test_create_solution(): with pytest.raises(ValueError): scip.Solution() -def test_print_soltion(): +def test_print_solution(): m = Model() - m.addVar() + m.addVar(obj=1, name="x") m.optimize() - assert str(m.getBestSol()) == "{'x1': -0.0}" + solution_str = str(m.getBestSol()) + print(re.match(r"{'x': -?\d+\.?\d*}", solution_str) is not None) def test_getSols(): m = Model() From 2952567a05cc0a0caea81f29ac368d015183c9e5 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 15 Nov 2023 22:54:14 +0000 Subject: [PATCH 16/54] Add SOScons test --- tests/test_model.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/test_model.py b/tests/test_model.py index 991d95e1b..a667f3415 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -118,7 +118,6 @@ def assert_conss_eq(a, b): s.freeProb() m.freeProb() - def test_multiple_cons_names(): m = Model() x = m.addVar("x", vtype = 'C', obj = 1.0) @@ -251,3 +250,27 @@ def test_getVarsDict(): for v in x.values(): assert v.name in var_dict assert model.getVal(v) == var_dict[v.name] + +def test_SOScons(): + m = Model() + x = {} + for i in range(6): + x[i] = m.addVar(vtype="B", obj=-i) + + c1 = m.addConsSOS1([x[0]], [1]) + c2 = m.addConsSOS2([x[1]], [1]) + + m.addVarSOS1(c1, x[2], 1) + m.addVarSOS2(c2, x[3], 1) + + m.appendVarSOS1(c1, x[4]) + m.appendVarSOS2(c2, x[5]) + + m.optimize() + + assert m.getVal(x[0]) == 0 + assert m.getVal(x[1]) == 0 + assert m.getVal(x[2]) == 0 + assert m.getVal(x[3]) == 1 + assert m.getVal(x[4]) == 1 + assert m.getVal(x[5]) == 1 From 3aa3273026d2273017524bf07e7b1b2932062266 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 15 Nov 2023 22:55:26 +0000 Subject: [PATCH 17/54] Move test to test_cons --- tests/test_model.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/test_model.py b/tests/test_model.py index a667f3415..c2555eae9 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -250,27 +250,3 @@ def test_getVarsDict(): for v in x.values(): assert v.name in var_dict assert model.getVal(v) == var_dict[v.name] - -def test_SOScons(): - m = Model() - x = {} - for i in range(6): - x[i] = m.addVar(vtype="B", obj=-i) - - c1 = m.addConsSOS1([x[0]], [1]) - c2 = m.addConsSOS2([x[1]], [1]) - - m.addVarSOS1(c1, x[2], 1) - m.addVarSOS2(c2, x[3], 1) - - m.appendVarSOS1(c1, x[4]) - m.appendVarSOS2(c2, x[5]) - - m.optimize() - - assert m.getVal(x[0]) == 0 - assert m.getVal(x[1]) == 0 - assert m.getVal(x[2]) == 0 - assert m.getVal(x[3]) == 1 - assert m.getVal(x[4]) == 1 - assert m.getVal(x[5]) == 1 From d86b6ad1dfeec86610e525df5377811e133009fb Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 15 Nov 2023 23:15:32 +0000 Subject: [PATCH 18/54] Add test_cons_logical --- tests/test_cons.py | 53 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index 0192cec82..300cea4cc 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -39,4 +39,55 @@ def test_constraint_option_setting(): assert c.isChecked() == option assert c.isEnforced() == option assert c.isRemovable() == option - assert c.isInitial() == option \ No newline at end of file + assert c.isInitial() == option + +def test_cons_logical(): + m = Model() + x1 = m.addVar(vtype="B") + x2 = m.addVar(vtype="B") + x3 = m.addVar(vtype="B") + x4 = m.addVar(vtype="B") + result1 = m.addVar(vtype="B") + result2 = m.addVar(vtype="B") + + m.addCons(x3 == 1-x1) + m.addCons(x4 == 1-x2) + + # result1 true + m.addConsAnd([x1,x2], result1) + m.addConsOr([x1,x2], result1) + m.addConsXor([x1,x3], True) + + # result2 false + m.addConsOr([x3,x4], result2) + m.addConsAnd([x1,x3], result2) + m.addConsXor([x1,x2], False) + + m.optimize() + + assert m.getVal(result1) == 1 + assert m.getVal(result2) == 0 + +def test_SOScons(): + m = Model() + x = {} + for i in range(6): + x[i] = m.addVar(vtype="B", obj=-i) + + c1 = m.addConsSOS1([x[0]], [1]) + c2 = m.addConsSOS2([x[1]], [1]) + + m.addVarSOS1(c1, x[2], 1) + m.addVarSOS2(c2, x[3], 1) + + m.appendVarSOS1(c1, x[4]) + m.appendVarSOS2(c2, x[5]) + + m.optimize() + + assert m.getVal(x[0]) == 0 + assert m.getVal(x[1]) == 0 + assert m.getVal(x[2]) == 0 + assert m.getVal(x[3]) == 1 + assert m.getVal(x[4]) == 1 + assert m.getVal(x[5]) == 1 From 7870916597b01cec47531d2dcb408a32130f59af Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 15 Nov 2023 23:25:01 +0000 Subject: [PATCH 19/54] [WIP] Add test_cons_indicator --- tests/test_cons.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_cons.py b/tests/test_cons.py index 300cea4cc..66784ce8b 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -91,3 +91,23 @@ def test_SOScons(): assert m.getVal(x[3]) == 1 assert m.getVal(x[4]) == 1 assert m.getVal(x[5]) == 1 + + +# WIP. addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717. +def test_cons_indicator(): + + m = Model() + x = m.addVar(lb=0) + binvar = m.addVar(vtype="B",lb=1) + #binvar2 = m.addVar(vtype="B", ub=0) + + c = m.addConsIndicator(x >= 1, binvar) + #c = m.addConsIndicator(x <= 0, binvar2) + + slack = m.getSlackVarIndicator(c) + + m.optimize() + + assert m.getVal(slack) == 0 + assert m.getVal(binvar) == 1 + assert m.getVal(x) == 1 From 7e3e41c3dbc104c2d6ffa46c1a8540e3401fdc63 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 15 Nov 2023 23:33:40 +0000 Subject: [PATCH 20/54] Add test_printCons --- tests/test_cons.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_cons.py b/tests/test_cons.py index 66784ce8b..147f30430 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -111,3 +111,11 @@ def test_cons_indicator(): assert m.getVal(slack) == 0 assert m.getVal(binvar) == 1 assert m.getVal(x) == 1 + +def test_printCons(): + m = Model() + x = m.addVar() + y = m.addVar() + c = m.addCons(x*y <= 5) + + m.printCons(c) \ No newline at end of file From 24e45497fefee0eecc1ab09bd12218adf9898bc4 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 15 Nov 2023 23:58:55 +0000 Subject: [PATCH 21/54] Add test_addConsCardinality --- tests/test_cons.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_cons.py b/tests/test_cons.py index 147f30430..f34db56b9 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -112,6 +112,17 @@ def test_cons_indicator(): assert m.getVal(binvar) == 1 assert m.getVal(x) == 1 +def test_addConsCardinality(): + m = Model() + x = {} + for i in range(5): + x[i] = m.addVar(ub=1,obj=-1) + + m.addConsCardinality([x[i] for i in range(5)], 3) + m.optimize() + + assert m.getVal(quicksum(x[i] for i in range(5))) == 3 + def test_printCons(): m = Model() x = m.addVar() From ab1506a38181e354c259d3b149f65d36204a6ad0 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 16 Nov 2023 11:34:41 +0000 Subject: [PATCH 22/54] setSolVal and freeSol --- tests/test_solution.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_solution.py b/tests/test_solution.py index 33c654c39..c08ce29ba 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -34,6 +34,14 @@ def test_solution_create(): s[y] = 4.0 assert m.addSol(s, free=True) + s1 = m.createSol() + m.setSolVal(s1,x,1.0) + m.setSolVal(s1,y,2.0) + + m.optimize() + + assert m.getSolVal(s1,x+y) == 3 + m.freeSol(s1) def test_solution_evaluation(): m = Model() From 131013e3c8e025bf5cbe0da5a4a0073c04b39f4e Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 16 Nov 2023 11:45:24 +0000 Subject: [PATCH 23/54] getNSols, getNSolsFound, checkSol, presolve --- tests/test_model.py | 1 + tests/test_pricer.py | 6 ++++++ tests/test_solution.py | 9 +++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/test_model.py b/tests/test_model.py index c2555eae9..57e5493eb 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -40,6 +40,7 @@ def test_model(): assert s.getRhs(c) == 6.0 # solve problem + s.presolve() # to test presolve method s.optimize() solution = s.getBestSol() diff --git a/tests/test_pricer.py b/tests/test_pricer.py index ebae4eb46..52c3c6c11 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -38,6 +38,8 @@ def pricerredcost(self): objval = 1 + subMIP.getObjVal() + assert type(self.model.getNSolsFound()) == int + self.model.data["nSols"] = self.model.getNSolsFound() # Adding the column to the master problem if objval < -1e-08: @@ -74,6 +76,8 @@ def test_cuttingstock(): s = Model("CuttingStock") s.setPresolve(0) + s.data = {} + s.data["nSols"] = 0 # creating a pricer pricer = CutPricer() @@ -149,6 +153,8 @@ def test_cuttingstock(): print('\t\t\tTotal Output:\t', '\t'.join(str(e) for e in widthOutput)) assert s.getObjVal() == 452.25 + assert type(s.getNSols()) == int + assert s.getNSols() == s.data["nSols"] def test_incomplete_pricer(): class IncompletePricer(Pricer): diff --git a/tests/test_solution.py b/tests/test_solution.py index c08ce29ba..56d9158f3 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -31,16 +31,17 @@ def test_solution_create(): s = m.createSol() s[x] = 2.0 - s[y] = 4.0 + s[y] = 5.0 + assert not m.checkSol(s) assert m.addSol(s, free=True) s1 = m.createSol() m.setSolVal(s1,x,1.0) m.setSolVal(s1,y,2.0) + assert m.checkSol(s1) m.optimize() - assert m.getSolVal(s1,x+y) == 3 m.freeSol(s1) def test_solution_evaluation(): @@ -66,9 +67,13 @@ def test_solution_evaluation(): # Check consistency with Models's getVal method assert sol[x] == m.getVal(x) + assert m.getSolVal(sol,x) == m.getVal(x) assert sol[y] == m.getVal(y) + assert m.getSolVal(sol,y) == m.getVal(y) assert sol[expr] == m.getVal(expr) + assert m.getSolVal(sol,expr) == m.getVal(expr) assert sol[expr2] == m.getVal(expr2) + assert m.getSolVal(sol,expr2) == m.getVal(expr2) def test_getSolTime(): m = Model() From 2ac327b96e951bf64d291781e29c874a33e3c8a9 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 16 Nov 2023 11:59:07 +0000 Subject: [PATCH 24/54] setObjlimit, getNLimSolsFound, getSolObjVal, getNBestSolsFound --- src/pyscipopt/scip.pxi | 2 -- tests/test_model.py | 17 +++++++++++++++++ tests/test_pricer.py | 2 ++ tests/test_solution.py | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 302bc7261..707586581 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -2722,7 +2722,6 @@ cdef class Model: return pyCons - def addConsIndicator(self, cons, binvar=None, activeone=True, name="IndicatorCons", initial=True, separate=True, enforce=True, check=True, propagate=True, local=False, dynamic=False, @@ -3323,7 +3322,6 @@ cdef class Model: return _dualsol - def optimize(self): """Optimize the problem.""" PY_SCIP_CALL(SCIPsolve(self._scip)) diff --git a/tests/test_model.py b/tests/test_model.py index 57e5493eb..14424e108 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -251,3 +251,20 @@ def test_getVarsDict(): for v in x.values(): assert v.name in var_dict assert model.getVal(v) == var_dict[v.name] + +def test_objLim(): + m = Model() + + x = m.addVar(obj=1, lb=2) + m.setObjlimit(1) + + m.optimize() + assert m.getNLimSolsFound() == 0 + + m = Model() + x = m.addVar(obj=1, lb=2) + + m.setObjlimit(2) + m.optimize() + assert m.getNLimSolsFound() == 1 + \ No newline at end of file diff --git a/tests/test_pricer.py b/tests/test_pricer.py index 52c3c6c11..1b8fd1184 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -39,6 +39,8 @@ def pricerredcost(self): objval = 1 + subMIP.getObjVal() assert type(self.model.getNSolsFound()) == int + assert type(self.model.getNBestSolsFound()) == int + assert self.model.getNBestSolsFound() <= self.model.getNSolsFound() self.model.data["nSols"] = self.model.getNSolsFound() # Adding the column to the master problem diff --git a/tests/test_solution.py b/tests/test_solution.py index 56d9158f3..1f54d859b 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -42,6 +42,7 @@ def test_solution_create(): m.optimize() + assert m.getSolObjVal(s1) == -1 m.freeSol(s1) def test_solution_evaluation(): From 0919c2e49326c03f542f59b5e8fd40db9bbd14a0 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Thu, 16 Nov 2023 11:59:38 +0000 Subject: [PATCH 25/54] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b36a7bfa5..0a6677e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Add SCIP function SCIPgetSolTime and wrapper getSolTime - Add convenience methods relax and getVarDict - Add SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal +- Add multiple tests for constraints and for solutions ### Fixed - Fixed typo in documentation of chgRhs - Pricer plugin fundamental callbacks now raise an error if not implemented From c8219e833df42267fa6999b1fcc8893a73879027 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 17 Nov 2023 15:14:32 +0000 Subject: [PATCH 26/54] Add xfail. Code formatting. --- tests/test_cons.py | 107 ++++++++++++++++++++++++++--------------- tests/test_logical.py | 2 +- tests/test_solution.py | 65 ++++++++++++++----------- 3 files changed, 106 insertions(+), 68 deletions(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index f34db56b9..6aa5912d1 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -1,30 +1,33 @@ from pyscipopt import Model, quicksum import random +import pytest def test_getConsNVars(): - n_vars = random.randint(100,1000) + n_vars = random.randint(100, 1000) m = Model() x = {} for i in range(n_vars): - x[i] = m.addVar("%i"%i) - + x[i] = m.addVar("%i" % i) + c = m.addCons(quicksum(x[i] for i in x) <= 10) assert m.getConsNVars(c) == n_vars m.optimize() assert m.getConsNVars(c) == n_vars + def test_getConsVars(): - n_vars = random.randint(100,1000) + n_vars = random.randint(100, 1000) m = Model() x = {} for i in range(n_vars): - x[i] = m.addVar("%i"%i) - + x[i] = m.addVar("%i" % i) + c = m.addCons(quicksum(x[i] for i in x) <= 1) assert m.getConsVars(c) == [x[i] for i in x] - + + def test_constraint_option_setting(): m = Model() x = m.addVar() @@ -41,6 +44,7 @@ def test_constraint_option_setting(): assert c.isRemovable() == option assert c.isInitial() == option + def test_cons_logical(): m = Model() x1 = m.addVar(vtype="B") @@ -50,24 +54,25 @@ def test_cons_logical(): result1 = m.addVar(vtype="B") result2 = m.addVar(vtype="B") - m.addCons(x3 == 1-x1) - m.addCons(x4 == 1-x2) - + m.addCons(x3 == 1 - x1) + m.addCons(x4 == 1 - x2) + # result1 true - m.addConsAnd([x1,x2], result1) - m.addConsOr([x1,x2], result1) - m.addConsXor([x1,x3], True) + m.addConsAnd([x1, x2], result1) + m.addConsOr([x1, x2], result1) + m.addConsXor([x1, x3], True) # result2 false - m.addConsOr([x3,x4], result2) - m.addConsAnd([x1,x3], result2) - m.addConsXor([x1,x2], False) + m.addConsOr([x3, x4], result2) + m.addConsAnd([x1, x3], result2) + m.addConsXor([x1, x2], False) + + m.optimize() + + assert m.isEQ(m.getVal(result1), 1) + assert m.isEQ(m.getVal(result2), 0) - m.optimize() - assert m.getVal(result1) == 1 - assert m.getVal(result2) == 0 - def test_SOScons(): m = Model() x = {} @@ -85,48 +90,72 @@ def test_SOScons(): m.optimize() - assert m.getVal(x[0]) == 0 - assert m.getVal(x[1]) == 0 - assert m.getVal(x[2]) == 0 - assert m.getVal(x[3]) == 1 - assert m.getVal(x[4]) == 1 - assert m.getVal(x[5]) == 1 + assert m.isEQ(m.getVal(x[0]), 0) + assert m.isEQ(m.getVal(x[1]), 0) + assert m.isEQ(m.getVal(x[2]), 0) + assert m.isEQ(m.getVal(x[3]), 1) + assert m.isEQ(m.getVal(x[4]), 1) + assert m.isEQ(m.getVal(x[5]), 1) -# WIP. addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717. def test_cons_indicator(): - m = Model() x = m.addVar(lb=0) - binvar = m.addVar(vtype="B",lb=1) - #binvar2 = m.addVar(vtype="B", ub=0) + binvar = m.addVar(vtype="B", lb=1) c = m.addConsIndicator(x >= 1, binvar) - #c = m.addConsIndicator(x <= 0, binvar2) slack = m.getSlackVarIndicator(c) m.optimize() - assert m.getVal(slack) == 0 - assert m.getVal(binvar) == 1 - assert m.getVal(x) == 1 + assert m.isEQ(m.getVal(slack), 0) + assert m.isEQ(m.getVal(binvar), 1) + assert m.isEQ(m.getVal(x), 1) + + +# addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717. +@pytest.mark.xfail +def test_cons_indicator_fail(): + m = Model() + binvar = m.addVar(vtype="B") + x = m.addVar(vtype="C", lb=1, ub=3) + m.addConsIndicator(x <= 2, binvar) + + m.setObjective(x, "maximize") + + sol = m.createSol(None) + m.setSolVal(sol, x, 3) + m.setSolVal(sol, binvar, 0) + assert m.checkSol(sol) # solution should be feasible + def test_addConsCardinality(): m = Model() x = {} for i in range(5): - x[i] = m.addVar(ub=1,obj=-1) + x[i] = m.addVar(ub=1, obj=-1) m.addConsCardinality([x[i] for i in range(5)], 3) m.optimize() - assert m.getVal(quicksum(x[i] for i in range(5))) == 3 + assert m.isEQ(m.getVal(quicksum(x[i] for i in range(5))), 3) + def test_printCons(): m = Model() x = m.addVar() y = m.addVar() - c = m.addCons(x*y <= 5) - - m.printCons(c) \ No newline at end of file + c = m.addCons(x * y <= 5) + + m.printCons(c) + + +@pytest.mark.skip +def test_getValsLinear(): + assert True + + +@pytest.mark.skip +def test_getRowLinear(): + assert True diff --git a/tests/test_logical.py b/tests/test_logical.py index 8c46f87ef..dbf99d3a6 100644 --- a/tests/test_logical.py +++ b/tests/test_logical.py @@ -42,7 +42,7 @@ def getVarByName(m, name): return [v for v in m.getVars() if name == v.name][0] except IndexError: return None - + def getAllVarsByName(m, name): try: diff --git a/tests/test_solution.py b/tests/test_solution.py index 1f54d859b..362380eae 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -1,12 +1,13 @@ import pytest from pyscipopt import Model, scip, SCIP_PARAMSETTING, quicksum, quickprod + def test_solution_getbest(): m = Model() x = m.addVar("x", lb=0, ub=2, obj=-1) y = m.addVar("y", lb=0, ub=4, obj=0) - m.addCons(x*x <= y) + m.addCons(x * x <= y) m.optimize() @@ -27,7 +28,7 @@ def test_solution_create(): x = m.addVar("x", lb=0, ub=2, obj=-1) y = m.addVar("y", lb=0, ub=4, obj=0) - m.addCons(x*x <= y) + m.addCons(x * x <= y) s = m.createSol() s[x] = 2.0 @@ -36,8 +37,8 @@ def test_solution_create(): assert m.addSol(s, free=True) s1 = m.createSol() - m.setSolVal(s1,x,1.0) - m.setSolVal(s1,y,2.0) + m.setSolVal(s1, x, 1.0) + m.setSolVal(s1, y, 2.0) assert m.checkSol(s1) m.optimize() @@ -45,12 +46,13 @@ def test_solution_create(): assert m.getSolObjVal(s1) == -1 m.freeSol(s1) + def test_solution_evaluation(): m = Model() x = m.addVar("x", lb=0, ub=2, obj=-1) y = m.addVar("y", lb=0, ub=4, obj=0) - m.addCons(x*x <= y) + m.addCons(x * x <= y) m.optimize() @@ -61,20 +63,21 @@ def test_solution_evaluation(): assert round(sol[y]) == 4.0 # Expression evaluation - expr = x*x + 2*x*y + y*y + expr = x * x + 2 * x * y + y * y expr2 = x + 1 assert round(sol[expr]) == 36.0 assert round(sol[expr2]) == 3.0 # Check consistency with Models's getVal method - assert sol[x] == m.getVal(x) - assert m.getSolVal(sol,x) == m.getVal(x) - assert sol[y] == m.getVal(y) - assert m.getSolVal(sol,y) == m.getVal(y) - assert sol[expr] == m.getVal(expr) - assert m.getSolVal(sol,expr) == m.getVal(expr) - assert sol[expr2] == m.getVal(expr2) - assert m.getSolVal(sol,expr2) == m.getVal(expr2) + assert m.isEQ(sol[x], m.getVal(x)) + assert m.isEQ(m.getSolVal(sol, x), m.getVal(x)) + assert m.isEQ(sol[y], m.getVal(y)) + assert m.isEQ(m.getSolVal(sol, y), m.getVal(y)) + assert m.isEQ(sol[expr], m.getVal(expr)) + assert m.isEQ(m.getSolVal(sol, expr), m.getVal(expr)) + assert m.isEQ(sol[expr2], m.getVal(expr2)) + assert m.isEQ(m.getSolVal(sol, expr2), m.getVal(expr2)) + def test_getSolTime(): m = Model() @@ -84,60 +87,65 @@ def test_getSolTime(): for i in range(20): x[i] = m.addVar(ub=i) - for i in range(1,6): - m.addCons(quicksum(x[j] for j in range(20) if j%i==0) >= i) - m.addCons(quickprod(x[j] for j in range(20) if j%i==0) <= i**3) - + for i in range(1, 6): + m.addCons(quicksum(x[j] for j in range(20) if j % i == 0) >= i) + m.addCons(quickprod(x[j] for j in range(20) if j % i == 0) <= i**3) + m.setObjective(quicksum(x[i] for i in range(20))) m.optimize() for s in m.getSols(): assert m.getSolTime(s) >= 0 + def test_hasPrimalRay(): m = Model() x = m.addVar() m.setObjective(x, "maximize") m.setPresolve(SCIP_PARAMSETTING.OFF) - + m.optimize() - + assert m.hasPrimalRay() m = Model() - x = m.addVar(lb = 0) # for readability + x = m.addVar(lb=0) # for readability m.setPresolve(SCIP_PARAMSETTING.OFF) m.optimize() assert not m.hasPrimalRay() - + + def test_getPrimalRayVal(): m = Model() x = m.addVar() m.setObjective(x, "maximize") m.setPresolve(SCIP_PARAMSETTING.OFF) - + m.hideOutput() m.optimize() - + assert m.getPrimalRayVal(x) == 1 - + + def test_getPrimalRay(): m = Model() x = m.addVar() y = m.addVar() m.setObjective(x, "maximize") m.setPresolve(SCIP_PARAMSETTING.OFF) - + m.hideOutput() m.optimize() - assert m.getPrimalRay() == [1,0] + assert m.getPrimalRay() == [1, 0] + def test_create_solution(): with pytest.raises(ValueError): scip.Solution() + def test_print_soltion(): m = Model() @@ -146,6 +154,7 @@ def test_print_soltion(): assert str(m.getBestSol()) == "{'x1': -0.0}" + def test_getSols(): m = Model() @@ -153,4 +162,4 @@ def test_getSols(): m.optimize() assert len(m.getSols()) >= 1 - assert any(sol[x] == 0.0 for sol in m.getSols()) \ No newline at end of file + assert any(m.isEQ(sol[x], 0.0) for sol in m.getSols()) From 665b47744983cf3cb6480421ab7c0ed678bf0e33 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Fri, 17 Nov 2023 15:28:38 +0000 Subject: [PATCH 27/54] Fix print solution --- tests/test_solution.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_solution.py b/tests/test_solution.py index 06342603f..d1b7c9d33 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -150,13 +150,11 @@ def test_create_solution(): def test_print_solution(): m = Model() - m.addVar() m.addVar(obj=1, name="x") m.optimize() - assert str(m.getBestSol()) == "{'x1': -0.0}" solution_str = str(m.getBestSol()) - print(re.match(r"{'x': -?\d+\.?\d*}", solution_str) is not None) + assert re.match(r"{'x': -?\d+\.?\d*}", solution_str) is not None def test_getSols(): From 22341f06f724f5dc07503dabcce566a1b5facd4b Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 17 Nov 2023 16:34:37 +0100 Subject: [PATCH 28/54] Update tests/test_cons.py --- tests/test_cons.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index 6aa5912d1..30c24afbf 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -114,7 +114,6 @@ def test_cons_indicator(): assert m.isEQ(m.getVal(x), 1) -# addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717. @pytest.mark.xfail def test_cons_indicator_fail(): m = Model() From df6f035ff06fc11a64c04faf3e5512bb6646a098 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 17 Nov 2023 16:34:44 +0100 Subject: [PATCH 29/54] Update tests/test_cons.py --- tests/test_cons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index 30c24afbf..4182c4b81 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -114,7 +114,7 @@ def test_cons_indicator(): assert m.isEQ(m.getVal(x), 1) -@pytest.mark.xfail +@pytest.mark.xfail(reason="addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717." def test_cons_indicator_fail(): m = Model() binvar = m.addVar(vtype="B") From 7e35dec2278eba79c331418827dfd461ded13412 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 17 Nov 2023 16:36:51 +0100 Subject: [PATCH 30/54] Apply suggestions from code review --- tests/test_cons.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index 4182c4b81..2161be45a 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -114,7 +114,7 @@ def test_cons_indicator(): assert m.isEQ(m.getVal(x), 1) -@pytest.mark.xfail(reason="addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717." +@pytest.mark.xfail(reason="addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717.") def test_cons_indicator_fail(): m = Model() binvar = m.addVar(vtype="B") @@ -150,11 +150,11 @@ def test_printCons(): m.printCons(c) -@pytest.mark.skip +@pytest.mark.skip(reason="TODO: test getValsLinear()") def test_getValsLinear(): assert True -@pytest.mark.skip +@pytest.mark.skip(reaons="TODO: test getRowLinear()") def test_getRowLinear(): assert True From d71dd2eebe2eedde72a4e06a76b41e29ecaa30f7 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 17 Nov 2023 16:43:32 +0100 Subject: [PATCH 31/54] Fix typo --- tests/test_cons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index 2161be45a..19c0551d1 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -155,6 +155,6 @@ def test_getValsLinear(): assert True -@pytest.mark.skip(reaons="TODO: test getRowLinear()") +@pytest.mark.skip(reason="TODO: test getRowLinear()") def test_getRowLinear(): assert True From 03d5ab96fcb4411226a0d5eab30b1b98a14719d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:58:39 +0000 Subject: [PATCH 32/54] Add lowerbound, result to PyRelaxExec (#749) * Set lowerbound and result in relax * Set result, lowerbound in PyRelaxExec * Fix test_relax * Set lowerbound in test_relax * Assert that relaxator returned a dict * Add period --------- Co-authored-by: Mohammed Ghannam --- CHANGELOG.md | 1 + src/pyscipopt/relax.pxi | 10 ++++--- tests/test_relax.py | 58 ++++++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a6677e2b..ca1ff959a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Add SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal - Add multiple tests for constraints and for solutions ### Fixed +- Correctly set result, lowerbound in PyRelaxExec - Fixed typo in documentation of chgRhs - Pricer plugin fundamental callbacks now raise an error if not implemented - Brachrule plugin fundamental callbacks now raise an error if not implemented diff --git a/src/pyscipopt/relax.pxi b/src/pyscipopt/relax.pxi index e73244a82..2b52c2643 100644 --- a/src/pyscipopt/relax.pxi +++ b/src/pyscipopt/relax.pxi @@ -28,7 +28,7 @@ cdef class Relax: '''callls execution method of relaxation handler''' print("python error in relaxexec: this method needs to be implemented") return{} - + cdef SCIP_RETCODE PyRelaxCopy (SCIP* scip, SCIP_RELAX* relax) with gil: return SCIP_OKAY @@ -73,6 +73,8 @@ cdef SCIP_RETCODE PyRelaxExec (SCIP* scip, SCIP_RELAX* relax, SCIP_Real* lowerbo cdef SCIP_RELAXDATA* relaxdata relaxdata = SCIPrelaxGetData(relax) PyRelax = relaxdata - PyRelax.relaxexec() - return SCIP_OKAY - + result_dict = PyRelax.relaxexec() + assert isinstance(result_dict, dict), "relaxexec() must return a dictionary." + lowerbound[0] = result_dict.get("lowerbound", lowerbound[0]) + result[0] = result_dict.get("result", result[0]) + return SCIP_OKAY \ No newline at end of file diff --git a/tests/test_relax.py b/tests/test_relax.py index 5ecdfed23..f797ae548 100644 --- a/tests/test_relax.py +++ b/tests/test_relax.py @@ -1,32 +1,64 @@ -from pyscipopt import Model +from pyscipopt import Model, SCIP_RESULT from pyscipopt.scip import Relax +import pytest calls = [] + class SoncRelax(Relax): def relaxexec(self): calls.append('relaxexec') - + return { + 'result': SCIP_RESULT.SUCCESS, + 'lowerbound': 10e4 + } + def test_relax(): m = Model() m.hideOutput() - #include relaxator - m.includeRelax(SoncRelax(),'testrelaxator','Test that relaxator gets included') - - #add Variables - x0 = m.addVar(vtype = "C", name = "x0") - x1 = m.addVar(vtype = "C", name = "x1") - x2 = m.addVar(vtype = "C", name = "x2") - - #addCons + # include relaxator + m.includeRelax(SoncRelax(), 'testrelaxator', + 'Test that relaxator gets included') + + # add Variables + x0 = m.addVar(vtype="I", name="x0") + x1 = m.addVar(vtype="I", name="x1") + x2 = m.addVar(vtype="I", name="x2") + + # addCons m.addCons(x0 >= 2) m.addCons(x0**2 <= x1) m.addCons(x1 * x2 >= x0) - + m.setObjective(x1 + x0) m.optimize() assert 'relaxexec' in calls - assert len(calls) >= 1 \ No newline at end of file + assert len(calls) >= 1 + assert m.getObjVal() > 10e4 + +class EmptyRelaxator(Relax): + def relaxexec(self): + pass + # doesn't return anything + +def test_empty_relaxator(): + m = Model() + m.hideOutput() + + m.includeRelax(EmptyRelaxator(), "", "") + + x0 = m.addVar(vtype="I", name="x0") + x1 = m.addVar(vtype="I", name="x1") + x2 = m.addVar(vtype="I", name="x2") + + m.addCons(x0 >= 2) + m.addCons(x0**2 <= x1) + m.addCons(x1 * x2 >= x0) + + m.setObjective(x1 + x0) + + with pytest.raises(Exception): + m.optimize() From 4f3ba8d3a56f8d15823b400f639d72953710b612 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 17 Nov 2023 17:40:05 +0100 Subject: [PATCH 33/54] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 29 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..6bd7fc5c3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**System** + - OS: [e.g. iOS] + - Version [e.g. 22] + - SCIP version + - How did you install `pyscipopt`? + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..bbcbbe7d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 386036bd003d6a6401b7800b6a81e38e23d591d3 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Fri, 17 Nov 2023 18:25:25 +0100 Subject: [PATCH 34/54] Simplify --- .github/ISSUE_TEMPLATE/feature_request.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d6..df81be2be 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -13,8 +13,5 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate **Describe the solution you'd like** A clear and concise description of what you want to happen. -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - **Additional context** Add any other context or screenshots about the feature request here. From c243218b120fb9b6ac5444ba4bc26b14c7280eee Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 21 Nov 2023 14:16:56 +0000 Subject: [PATCH 35/54] Fix pointer --- src/pyscipopt/scip.pxi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 302bc7261..c2fde60b0 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -2169,7 +2169,7 @@ cdef class Model: SCIPgetConsNVars(self._scip, constraint.scip_cons, &_nvars, &success) cdef SCIP_VAR** _vars = malloc(_nvars * sizeof(SCIP_VAR*)) - SCIPgetConsVars(self._scip, constraint.scip_cons, _vars, _nvars*sizeof(SCIP_VAR), &success) + SCIPgetConsVars(self._scip, constraint.scip_cons, _vars, _nvars*sizeof(SCIP_VAR*), &success) vars = [] for i in range(_nvars): @@ -4459,6 +4459,8 @@ cdef class Model: """ cdef SCIP_SOL* _sol _sol = solution.sol + + assert _sol != NULL, "Cannot set value to a freed solution." PY_SCIP_CALL(SCIPsetSolVal(self._scip, _sol, var.scip_var, val)) def trySol(self, Solution solution, printreason=True, completely=False, checkbounds=True, checkintegrality=True, checklprows=True, free=True): From 358a0b94c3242614b8ba25e286d9307384e7ae08 Mon Sep 17 00:00:00 2001 From: Igor Banfi Date: Fri, 24 Nov 2023 15:51:23 +0100 Subject: [PATCH 36/54] freeTransform recreates _modelvars --- src/pyscipopt/scip.pxi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 874b2c9e3..8b6fc259f 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1072,6 +1072,8 @@ cdef class Model: def freeTransform(self): """Frees all solution process data including presolving and transformed problem, only original problem is kept""" PY_SCIP_CALL(SCIPfreeTransform(self._scip)) + self._modelvars = {} + self.getVars() def version(self): """Retrieve SCIP version""" From 54a72c700026a70817101a1e460545146deb0d6d Mon Sep 17 00:00:00 2001 From: Igor Banfi Date: Mon, 27 Nov 2023 08:51:15 +0100 Subject: [PATCH 37/54] Removing non-original variables from _modelvars before freeTransform --- src/pyscipopt/scip.pxi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 8b6fc259f..b28f498bd 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -1071,9 +1071,12 @@ cdef class Model: def freeTransform(self): """Frees all solution process data including presolving and transformed problem, only original problem is kept""" + self._modelvars = { + var: value + for var, value in self._modelvars.items() + if value.isOriginal() + } PY_SCIP_CALL(SCIPfreeTransform(self._scip)) - self._modelvars = {} - self.getVars() def version(self): """Retrieve SCIP version""" From c9c780c92c6f4d12caef1c77b77eafe9778c9dd9 Mon Sep 17 00:00:00 2001 From: Igor Banfi Date: Mon, 27 Nov 2023 16:14:51 +0100 Subject: [PATCH 38/54] Added freeTransform check into test_cuttingstock --- tests/test_pricer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_pricer.py b/tests/test_pricer.py index 1b8fd1184..abc5599a2 100644 --- a/tests/test_pricer.py +++ b/tests/test_pricer.py @@ -158,6 +158,11 @@ def test_cuttingstock(): assert type(s.getNSols()) == int assert s.getNSols() == s.data["nSols"] + # Testing freeTransform + s.freeTransform() + for i in range(10): + s.addVar() + def test_incomplete_pricer(): class IncompletePricer(Pricer): pass From 3aac80a13b9e420ddf93ebef5bd6b8a02064bae3 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 28 Nov 2023 16:40:21 +0000 Subject: [PATCH 39/54] EVENTTYPE Overhaul --- src/pyscipopt/scip.pxd | 90 +++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index bbf12f566..44478f965 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -197,43 +197,45 @@ cdef extern from "scip/scip.h": SCIP_BASESTAT_ZERO = 3 - ctypedef enum SCIP_EVENTTYPE: - SCIP_EVENTTYPE_DISABLED = 0x00000000u - SCIP_EVENTTYPE_VARADDED = 0x00000001u - SCIP_EVENTTYPE_VARDELETED = 0x00000002u - SCIP_EVENTTYPE_VARFIXED = 0x00000004u - SCIP_EVENTTYPE_VARUNLOCKED = 0x00000008u - SCIP_EVENTTYPE_OBJCHANGED = 0x00000010u - SCIP_EVENTTYPE_GLBCHANGED = 0x00000020u - SCIP_EVENTTYPE_GUBCHANGED = 0x00000040u - SCIP_EVENTTYPE_LBTIGHTENED = 0x00000080u - SCIP_EVENTTYPE_LBRELAXED = 0x00000100u - SCIP_EVENTTYPE_UBTIGHTENED = 0x00000200u - SCIP_EVENTTYPE_UBRELAXED = 0x00000400u - SCIP_EVENTTYPE_GHOLEADDED = 0x00000800u - SCIP_EVENTTYPE_GHOLEREMOVED = 0x00001000u - SCIP_EVENTTYPE_LHOLEADDED = 0x00002000u - SCIP_EVENTTYPE_LHOLEREMOVED = 0x00004000u - SCIP_EVENTTYPE_IMPLADDED = 0x00008000u - SCIP_EVENTTYPE_PRESOLVEROUND = 0x00010000u - SCIP_EVENTTYPE_NODEFOCUSED = 0x00020000u - SCIP_EVENTTYPE_NODEFEASIBLE = 0x00040000u - SCIP_EVENTTYPE_NODEINFEASIBLE = 0x00080000u - SCIP_EVENTTYPE_NODEBRANCHED = 0x00100000u - SCIP_EVENTTYPE_FIRSTLPSOLVED = 0x00200000u - SCIP_EVENTTYPE_LPSOLVED = 0x00400000u - SCIP_EVENTTYPE_POORSOLFOUND = 0x00800000u - SCIP_EVENTTYPE_BESTSOLFOUND = 0x01000000u - SCIP_EVENTTYPE_ROWADDEDSEPA = 0x02000000u - SCIP_EVENTTYPE_ROWDELETEDSEPA = 0x04000000u - SCIP_EVENTTYPE_ROWADDEDLP = 0x08000000u - SCIP_EVENTTYPE_ROWDELETEDLP = 0x10000000u - SCIP_EVENTTYPE_ROWCOEFCHANGED = 0x20000000u - SCIP_EVENTTYPE_ROWCONSTCHANGED = 0x40000000u - SCIP_EVENTTYPE_ROWSIDECHANGED = 0x80000000u - SCIP_EVENTTYPE_SYNC = 0x100000000u - - SCIP_EVENTTYPE_LPEVENT = SCIP_EVENTTYPE_FIRSTLPSOLVED | SCIP_EVENTTYPE_LPSOLVED + cdef extern from "scip/type_event.h": + unsigned long SCIP_EVENTTYPE_DISABLED + unsigned long SCIP_EVENTTYPE_VARADDED + unsigned long SCIP_EVENTTYPE_VARDELETED + unsigned long SCIP_EVENTTYPE_VARFIXED + unsigned long SCIP_EVENTTYPE_VARUNLOCKED + unsigned long SCIP_EVENTTYPE_OBJCHANGED + unsigned long SCIP_EVENTTYPE_GLBCHANGED + unsigned long SCIP_EVENTTYPE_GUBCHANGED + unsigned long SCIP_EVENTTYPE_LBTIGHTENED + unsigned long SCIP_EVENTTYPE_LBRELAXED + unsigned long SCIP_EVENTTYPE_UBTIGHTENED + unsigned long SCIP_EVENTTYPE_UBRELAXED + unsigned long SCIP_EVENTTYPE_GHOLEADDED + unsigned long SCIP_EVENTTYPE_GHOLEREMOVED + unsigned long SCIP_EVENTTYPE_LHOLEADDED + unsigned long SCIP_EVENTTYPE_LHOLEREMOVED + unsigned long SCIP_EVENTTYPE_IMPLADDED + unsigned long SCIP_EVENTTYPE_PRESOLVEROUND + unsigned long SCIP_EVENTTYPE_NODEFOCUSED + unsigned long SCIP_EVENTTYPE_NODEFEASIBLE + unsigned long SCIP_EVENTTYPE_NODEINFEASIBLE + unsigned long SCIP_EVENTTYPE_NODEBRANCHED + unsigned long SCIP_EVENTTYPE_NODEDELETE + unsigned long SCIP_EVENTTYPE_FIRSTLPSOLVED + unsigned long SCIP_EVENTTYPE_LPSOLVED + unsigned long SCIP_EVENTTYPE_POORSOLFOUND + unsigned long SCIP_EVENTTYPE_BESTSOLFOUND + unsigned long SCIP_EVENTTYPE_ROWADDEDSEPA + unsigned long SCIP_EVENTTYPE_ROWDELETEDSEPA + unsigned long SCIP_EVENTTYPE_ROWADDEDLP + unsigned long SCIP_EVENTTYPE_ROWDELETEDLP + unsigned long SCIP_EVENTTYPE_ROWCOEFCHANGED + unsigned long SCIP_EVENTTYPE_ROWCONSTCHANGED + unsigned long SCIP_EVENTTYPE_ROWSIDECHANGED + unsigned long SCIP_EVENTTYPE_SYNC + + unsigned long SCIP_EVENTTYPE_LPEVENT + ctypedef enum SCIP_LPSOLQUALITY: SCIP_LPSOLQUALITY_ESTIMCONDITION = 0 @@ -544,41 +546,41 @@ cdef extern from "scip/scip.h": # Event Methods SCIP_RETCODE SCIPcatchEvent(SCIP* scip, - SCIP_EVENTTYPE eventtype, + unsigned long eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int* filterpos) SCIP_RETCODE SCIPdropEvent(SCIP* scip, - SCIP_EVENTTYPE eventtype, + unsigned long eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int filterpos) SCIP_RETCODE SCIPcatchVarEvent(SCIP* scip, SCIP_VAR* var, - SCIP_EVENTTYPE eventtype, + unsigned long eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int* filterpos) SCIP_RETCODE SCIPdropVarEvent(SCIP* scip, SCIP_VAR* var, - SCIP_EVENTTYPE eventtype, + unsigned long eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int filterpos) SCIP_RETCODE SCIPcatchRowEvent(SCIP* scip, SCIP_ROW* row, - SCIP_EVENTTYPE eventtype, + unsigned long eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int* filterpos) SCIP_RETCODE SCIPdropRowEvent(SCIP* scip, SCIP_ROW* row, - SCIP_EVENTTYPE eventtype, + unsigned long eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int filterpos) SCIP_EVENTHDLR* SCIPfindEventhdlr(SCIP* scip, const char* name) - SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT* event) + unsigned long SCIPeventGetType(SCIP_EVENT* event) SCIP_Real SCIPeventGetNewbound(SCIP_EVENT* event) SCIP_Real SCIPeventGetOldbound(SCIP_EVENT* event) SCIP_VAR* SCIPeventGetVar(SCIP_EVENT* event) From da69c342af54b30384a877beb5cea077eb072a38 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 28 Nov 2023 23:29:32 +0000 Subject: [PATCH 40/54] Directly use SCIP macros instead of their value --- src/pyscipopt/scip.pxd | 584 +++++++++++++++++++++-------------------- 1 file changed, 303 insertions(+), 281 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 44478f965..36a0b2668 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -2,281 +2,303 @@ #@brief holding prototype of the SCIP public functions to use them in PySCIPOpt cdef extern from "scip/scip.h": # SCIP internal types - ctypedef enum SCIP_RETCODE: - SCIP_OKAY = 1 - SCIP_ERROR = 0 - SCIP_NOMEMORY = -1 - SCIP_READERROR = -2 - SCIP_WRITEERROR = -3 - SCIP_NOFILE = -4 - SCIP_FILECREATEERROR = -5 - SCIP_LPERROR = -6 - SCIP_NOPROBLEM = -7 - SCIP_INVALIDCALL = -8 - SCIP_INVALIDDATA = -9 - SCIP_INVALIDRESULT = -10 - SCIP_PLUGINNOTFOUND = -11 - SCIP_PARAMETERUNKNOWN = -12 - SCIP_PARAMETERWRONGTYPE = -13 - SCIP_PARAMETERWRONGVAL = -14 - SCIP_KEYALREADYEXISTING = -15 - SCIP_MAXDEPTHLEVEL = -16 - - ctypedef enum SCIP_VARTYPE: - SCIP_VARTYPE_BINARY = 0 - SCIP_VARTYPE_INTEGER = 1 - SCIP_VARTYPE_IMPLINT = 2 - SCIP_VARTYPE_CONTINUOUS = 3 - - ctypedef enum SCIP_OBJSENSE: - SCIP_OBJSENSE_MAXIMIZE = -1 - SCIP_OBJSENSE_MINIMIZE = 1 + ctypedef int SCIP_RETCODE + cdef extern from "scip/type_retcode.h": + SCIP_RETCODE SCIP_OKAY + SCIP_RETCODE SCIP_ERROR + SCIP_RETCODE SCIP_NOMEMORY + SCIP_RETCODE SCIP_READERROR + SCIP_RETCODE SCIP_WRITEERROR + SCIP_RETCODE SCIP_NOFILE + SCIP_RETCODE SCIP_FILECREATEERROR + SCIP_RETCODE SCIP_LPERROR + SCIP_RETCODE SCIP_NOPROBLEM + SCIP_RETCODE SCIP_INVALIDCALL + SCIP_RETCODE SCIP_INVALIDDATA + SCIP_RETCODE SCIP_INVALIDRESULT + SCIP_RETCODE SCIP_PLUGINNOTFOUND + SCIP_RETCODE SCIP_PARAMETERUNKNOWN + SCIP_RETCODE SCIP_PARAMETERWRONGTYPE + SCIP_RETCODE SCIP_PARAMETERWRONGVAL + SCIP_RETCODE SCIP_KEYALREADYEXISTING + SCIP_RETCODE SCIP_MAXDEPTHLEVEL + + ctypedef int SCIP_VARTYPE + cdef extern from "scip/type_var.h": + SCIP_VARTYPE SCIP_VARTYPE_BINARY + SCIP_VARTYPE SCIP_VARTYPE_INTEGER + SCIP_VARTYPE SCIP_VARTYPE_IMPLINT + SCIP_VARTYPE SCIP_VARTYPE_CONTINUOUS + + ctypedef int SCIP_OBJSENSE + cdef extern from "scip/type_prob.h": + SCIP_OBJSENSE SCIP_OBJSENSE_MAXIMIZE + SCIP_OBJSENSE SCIP_OBJSENSE_MINIMIZE # This version is used in LPI. - ctypedef enum SCIP_OBJSEN: - SCIP_OBJSEN_MAXIMIZE = -1 - SCIP_OBJSEN_MINIMIZE = 1 - - ctypedef enum SCIP_BOUNDTYPE: - SCIP_BOUNDTYPE_LOWER = 0 - SCIP_BOUNDTYPE_UPPER = 1 - - ctypedef enum SCIP_RESULT: - SCIP_DIDNOTRUN = 1 - SCIP_DELAYED = 2 - SCIP_DIDNOTFIND = 3 - SCIP_FEASIBLE = 4 - SCIP_INFEASIBLE = 5 - SCIP_UNBOUNDED = 6 - SCIP_CUTOFF = 7 - SCIP_SEPARATED = 8 - SCIP_NEWROUND = 9 - SCIP_REDUCEDDOM = 10 - SCIP_CONSADDED = 11 - SCIP_CONSCHANGED = 12 - SCIP_BRANCHED = 13 - SCIP_SOLVELP = 14 - SCIP_FOUNDSOL = 15 - SCIP_SUSPENDED = 16 - SCIP_SUCCESS = 17 - - ctypedef enum SCIP_STATUS: - SCIP_STATUS_UNKNOWN = 0 - SCIP_STATUS_USERINTERRUPT = 1 - SCIP_STATUS_NODELIMIT = 2 - SCIP_STATUS_TOTALNODELIMIT = 3 - SCIP_STATUS_STALLNODELIMIT = 4 - SCIP_STATUS_TIMELIMIT = 5 - SCIP_STATUS_MEMLIMIT = 6 - SCIP_STATUS_GAPLIMIT = 7 - SCIP_STATUS_SOLLIMIT = 8 - SCIP_STATUS_BESTSOLLIMIT = 9 - SCIP_STATUS_RESTARTLIMIT = 10 - SCIP_STATUS_OPTIMAL = 11 - SCIP_STATUS_INFEASIBLE = 12 - SCIP_STATUS_UNBOUNDED = 13 - SCIP_STATUS_INFORUNBD = 14 - - ctypedef enum SCIP_STAGE: - SCIP_STAGE_INIT = 0 - SCIP_STAGE_PROBLEM = 1 - SCIP_STAGE_TRANSFORMING = 2 - SCIP_STAGE_TRANSFORMED = 3 - SCIP_STAGE_INITPRESOLVE = 4 - SCIP_STAGE_PRESOLVING = 5 - SCIP_STAGE_EXITPRESOLVE = 6 - SCIP_STAGE_PRESOLVED = 7 - SCIP_STAGE_INITSOLVE = 8 - SCIP_STAGE_SOLVING = 9 - SCIP_STAGE_SOLVED = 10 - SCIP_STAGE_EXITSOLVE = 11 - SCIP_STAGE_FREETRANS = 12 - SCIP_STAGE_FREE = 13 - - ctypedef enum SCIP_NODETYPE: - SCIP_NODETYPE_FOCUSNODE = 0 - SCIP_NODETYPE_PROBINGNODE = 1 - SCIP_NODETYPE_SIBLING = 2 - SCIP_NODETYPE_CHILD = 3 - SCIP_NODETYPE_LEAF = 4 - SCIP_NODETYPE_DEADEND = 5 - SCIP_NODETYPE_JUNCTION = 6 - SCIP_NODETYPE_PSEUDOFORK = 7 - SCIP_NODETYPE_FORK = 8 - SCIP_NODETYPE_SUBROOT = 9 - SCIP_NODETYPE_REFOCUSNODE = 10 - - ctypedef enum SCIP_PARAMSETTING: - SCIP_PARAMSETTING_DEFAULT = 0 - SCIP_PARAMSETTING_AGGRESSIVE = 1 - SCIP_PARAMSETTING_FAST = 2 - SCIP_PARAMSETTING_OFF = 3 - - ctypedef enum SCIP_PARAMTYPE: - SCIP_PARAMTYPE_BOOL = 0 - SCIP_PARAMTYPE_INT = 1 - SCIP_PARAMTYPE_LONGINT = 2 - SCIP_PARAMTYPE_REAL = 3 - SCIP_PARAMTYPE_CHAR = 4 - SCIP_PARAMTYPE_STRING = 5 - - ctypedef enum SCIP_PARAMEMPHASIS: - SCIP_PARAMEMPHASIS_DEFAULT = 0 - SCIP_PARAMEMPHASIS_CPSOLVER = 1 - SCIP_PARAMEMPHASIS_EASYCIP = 2 - SCIP_PARAMEMPHASIS_FEASIBILITY = 3 - SCIP_PARAMEMPHASIS_HARDLP = 4 - SCIP_PARAMEMPHASIS_OPTIMALITY = 5 - SCIP_PARAMEMPHASIS_COUNTER = 6 - SCIP_PARAMEMPHASIS_PHASEFEAS = 7 - SCIP_PARAMEMPHASIS_PHASEIMPROVE = 8 - SCIP_PARAMEMPHASIS_PHASEPROOF = 9 - SCIP_PARAMEMPHASIS_NUMERICS = 10 - SCIP_PARAMEMPHASIS_BENCHMARK = 11 - - ctypedef enum SCIP_PROPTIMING: - SCIP_PROPTIMING_BEFORELP = 0x001u - SCIP_PROPTIMING_DURINGLPLOOP = 0x002u - SCIP_PROPTIMING_AFTERLPLOOP = 0x004u - SCIP_PROPTIMING_AFTERLPNODE = 0x008u - - ctypedef enum SCIP_PRESOLTIMING: - SCIP_PRESOLTIMING_NONE = 0x002u - SCIP_PRESOLTIMING_FAST = 0x004u - SCIP_PRESOLTIMING_MEDIUM = 0x008u - SCIP_PRESOLTIMING_EXHAUSTIVE = 0x010u - - ctypedef enum SCIP_HEURTIMING: - SCIP_HEURTIMING_BEFORENODE = 0x001u - SCIP_HEURTIMING_DURINGLPLOOP = 0x002u - SCIP_HEURTIMING_AFTERLPLOOP = 0x004u - SCIP_HEURTIMING_AFTERLPNODE = 0x008u - SCIP_HEURTIMING_AFTERPSEUDONODE = 0x010u - SCIP_HEURTIMING_AFTERLPPLUNGE = 0x020u - SCIP_HEURTIMING_AFTERPSEUDOPLUNGE = 0x040u - SCIP_HEURTIMING_DURINGPRICINGLOOP = 0x080u - SCIP_HEURTIMING_BEFOREPRESOL = 0x100u - SCIP_HEURTIMING_DURINGPRESOLLOOP = 0x200u - SCIP_HEURTIMING_AFTERPROPLOOP = 0x400u - - ctypedef enum SCIP_EXPROP: - SCIP_EXPR_VARIDX = 1 - SCIP_EXPR_CONST = 2 - SCIP_EXPR_PARAM = 3 - SCIP_EXPR_PLUS = 8 - SCIP_EXPR_MINUS = 9 - SCIP_EXPR_MUL = 10 - SCIP_EXPR_DIV = 11 - SCIP_EXPR_SQUARE = 12 - SCIP_EXPR_SQRT = 13 - SCIP_EXPR_REALPOWER = 14 - SCIP_EXPR_INTPOWER = 15 - SCIP_EXPR_SIGNPOWER = 16 - SCIP_EXPR_EXP = 17 - SCIP_EXPR_LOG = 18 - SCIP_EXPR_SIN = 19 - SCIP_EXPR_COS = 20 - SCIP_EXPR_TAN = 21 - SCIP_EXPR_MIN = 24 - SCIP_EXPR_MAX = 25 - SCIP_EXPR_ABS = 26 - SCIP_EXPR_SIGN = 27 - SCIP_EXPR_SUM = 64 - SCIP_EXPR_PRODUCT = 65 - SCIP_EXPR_LINEAR = 66 - SCIP_EXPR_QUADRATIC = 67 - SCIP_EXPR_POLYNOMIAL= 68 - SCIP_EXPR_USER = 69 - SCIP_EXPR_LAST = 70 - - - ctypedef enum SCIP_BASESTAT: - SCIP_BASESTAT_LOWER = 0 - SCIP_BASESTAT_BASIC = 1 - SCIP_BASESTAT_UPPER = 2 - SCIP_BASESTAT_ZERO = 3 - - + ctypedef int SCIP_OBJSEN + cdef extern from "lpi/type_lpi.h": + SCIP_OBJSEN SCIP_OBJSEN_MAXIMIZE + SCIP_OBJSEN SCIP_OBJSEN_MINIMIZE + + ctypedef int SCIP_BOUNDTYPE + cdef extern from "scip/type_lp.h": + SCIP_BOUNDTYPE SCIP_BOUNDTYPE_LOWER + SCIP_BOUNDTYPE SCIP_BOUNDTYPE_UPPER + + ctypedef int SCIP_RESULT + cdef extern from "scip/type_result.h": + SCIP_RESULT SCIP_DIDNOTRUN + SCIP_RESULT SCIP_DELAYED + SCIP_RESULT SCIP_DIDNOTFIND + SCIP_RESULT SCIP_FEASIBLE + SCIP_RESULT SCIP_INFEASIBLE + SCIP_RESULT SCIP_UNBOUNDED + SCIP_RESULT SCIP_CUTOFF + SCIP_RESULT SCIP_SEPARATED + SCIP_RESULT SCIP_NEWROUND + SCIP_RESULT SCIP_REDUCEDDOM + SCIP_RESULT SCIP_CONSADDED + SCIP_RESULT SCIP_CONSCHANGED + SCIP_RESULT SCIP_BRANCHED + SCIP_RESULT SCIP_SOLVELP + SCIP_RESULT SCIP_FOUNDSOL + SCIP_RESULT SCIP_SUSPENDED + SCIP_RESULT SCIP_SUCCESS + + ctypedef int SCIP_STATUS + cdef extern from "scip/type_stat.h": + SCIP_STATUS SCIP_STATUS_UNKNOWN + SCIP_STATUS SCIP_STATUS_USERINTERRUPT + SCIP_STATUS SCIP_STATUS_NODELIMIT + SCIP_STATUS SCIP_STATUS_TOTALNODELIMIT + SCIP_STATUS SCIP_STATUS_STALLNODELIMIT + SCIP_STATUS SCIP_STATUS_TIMELIMIT + SCIP_STATUS SCIP_STATUS_MEMLIMIT + SCIP_STATUS SCIP_STATUS_GAPLIMIT + SCIP_STATUS SCIP_STATUS_SOLLIMIT + SCIP_STATUS SCIP_STATUS_BESTSOLLIMIT + SCIP_STATUS SCIP_STATUS_RESTARTLIMIT + SCIP_STATUS SCIP_STATUS_OPTIMAL + SCIP_STATUS SCIP_STATUS_INFEASIBLE + SCIP_STATUS SCIP_STATUS_UNBOUNDED + SCIP_STATUS SCIP_STATUS_INFORUNBD + + ctypedef int SCIP_STAGE + cdef extern from "scip/type_set.h": + SCIP_STAGE SCIP_STAGE_INIT + SCIP_STAGE SCIP_STAGE_PROBLEM + SCIP_STAGE SCIP_STAGE_TRANSFORMING + SCIP_STAGE SCIP_STAGE_TRANSFORMED + SCIP_STAGE SCIP_STAGE_INITPRESOLVE + SCIP_STAGE SCIP_STAGE_PRESOLVING + SCIP_STAGE SCIP_STAGE_EXITPRESOLVE + SCIP_STAGE SCIP_STAGE_PRESOLVED + SCIP_STAGE SCIP_STAGE_INITSOLVE + SCIP_STAGE SCIP_STAGE_SOLVING + SCIP_STAGE SCIP_STAGE_SOLVED + SCIP_STAGE SCIP_STAGE_EXITSOLVE + SCIP_STAGE SCIP_STAGE_FREETRANS + SCIP_STAGE SCIP_STAGE_FREE + + ctypedef int SCIP_NODETYPE + cdef extern from "scip/type_tree.h": + SCIP_NODETYPE SCIP_NODETYPE_FOCUSNODE + SCIP_NODETYPE SCIP_NODETYPE_PROBINGNODE + SCIP_NODETYPE SCIP_NODETYPE_SIBLING + SCIP_NODETYPE SCIP_NODETYPE_CHILD + SCIP_NODETYPE SCIP_NODETYPE_LEAF + SCIP_NODETYPE SCIP_NODETYPE_DEADEND + SCIP_NODETYPE SCIP_NODETYPE_JUNCTION + SCIP_NODETYPE SCIP_NODETYPE_PSEUDOFORK + SCIP_NODETYPE SCIP_NODETYPE_FORK + SCIP_NODETYPE SCIP_NODETYPE_SUBROOT + SCIP_NODETYPE SCIP_NODETYPE_REFOCUSNODE + + ctypedef int SCIP_PARAMSETTING + cdef extern from "scip/type_paramset.h": + SCIP_PARAMSETTING SCIP_PARAMSETTING_DEFAULT + SCIP_PARAMSETTING SCIP_PARAMSETTING_AGGRESSIVE + SCIP_PARAMSETTING SCIP_PARAMSETTING_FAST + SCIP_PARAMSETTING SCIP_PARAMSETTING_OFF + + ctypedef int SCIP_PARAMTYPE + cdef extern from "scip/type_paramset.h": + SCIP_PARAMTYPE SCIP_PARAMTYPE_BOOL + SCIP_PARAMTYPE SCIP_PARAMTYPE_INT + SCIP_PARAMTYPE SCIP_PARAMTYPE_LONGINT + SCIP_PARAMTYPE SCIP_PARAMTYPE_REAL + SCIP_PARAMTYPE SCIP_PARAMTYPE_CHAR + SCIP_PARAMTYPE SCIP_PARAMTYPE_STRING + + ctypedef int SCIP_PARAMEMPHASIS + cdef extern from "scip/type_paramset.h": + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_DEFAULT + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_CPSOLVER + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_EASYCIP + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_FEASIBILITY + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_HARDLP + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_OPTIMALITY + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_COUNTER + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_PHASEFEAS + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_PHASEIMPROVE + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_PHASEPROOF + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_NUMERICS + SCIP_PARAMEMPHASIS SCIP_PARAMEMPHASIS_BENCHMARK + + ctypedef unsigned long SCIP_PROPTIMING + cdef extern from "scip/type_timing.h": + SCIP_PROPTIMING SCIP_PROPTIMING_BEFORELP + SCIP_PROPTIMING SCIP_PROPTIMING_DURINGLPLOOP + SCIP_PROPTIMING SCIP_PROPTIMING_AFTERLPLOOP + SCIP_PROPTIMING SCIP_PROPTIMING_AFTERLPNODE + + ctypedef unsigned long SCIP_PRESOLTIMING + cdef extern from "scip/type_timing.h": + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_NONE + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_FAST + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM + SCIP_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE + + ctypedef unsigned long SCIP_HEURTIMING + cdef extern from "scip/type_timing.h": + SCIP_HEURTIMING SCIP_HEURTIMING_BEFORENODE + SCIP_HEURTIMING SCIP_HEURTIMING_DURINGLPLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPNODE + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPSEUDONODE + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERLPPLUNGE + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPSEUDOPLUNGE + SCIP_HEURTIMING SCIP_HEURTIMING_DURINGPRICINGLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_BEFOREPRESOL + SCIP_HEURTIMING SCIP_HEURTIMING_DURINGPRESOLLOOP + SCIP_HEURTIMING SCIP_HEURTIMING_AFTERPROPLOOP + + ctypedef int SCIP_EXPR + cdef extern from "scip/type_expr.h": + SCIP_EXPR SCIP_EXPR_VARIDX + SCIP_EXPR SCIP_EXPR_CONST + SCIP_EXPR SCIP_EXPR_PARAM + SCIP_EXPR SCIP_EXPR_PLUS + SCIP_EXPR SCIP_EXPR_MINUS + SCIP_EXPR SCIP_EXPR_MUL + SCIP_EXPR SCIP_EXPR_DIV + SCIP_EXPR SCIP_EXPR_SQUARE + SCIP_EXPR SCIP_EXPR_SQRT + SCIP_EXPR SCIP_EXPR_REALPOWER + SCIP_EXPR SCIP_EXPR_INTPOWER + SCIP_EXPR SCIP_EXPR_SIGNPOWER + SCIP_EXPR SCIP_EXPR_EXP + SCIP_EXPR SCIP_EXPR_LOG + SCIP_EXPR SCIP_EXPR_SIN + SCIP_EXPR SCIP_EXPR_COS + SCIP_EXPR SCIP_EXPR_TAN + SCIP_EXPR SCIP_EXPR_MIN + SCIP_EXPR SCIP_EXPR_MAX + SCIP_EXPR SCIP_EXPR_ABS + SCIP_EXPR SCIP_EXPR_SIGN + SCIP_EXPR SCIP_EXPR_SUM + SCIP_EXPR SCIP_EXPR_PRODUCT + SCIP_EXPR SCIP_EXPR_LINEAR + SCIP_EXPR SCIP_EXPR_QUADRATIC + SCIP_EXPR SCIP_EXPR_POLYNOMIAL + SCIP_EXPR SCIP_EXPR_USER + SCIP_EXPR SCIP_EXPR_LAST + + ctypedef int SCIP_BASESTAT + cdef extern from "lpi/type_lpi.h": + SCIP_BASESTAT SCIP_BASESTAT_LOWER + SCIP_BASESTAT SCIP_BASESTAT_BASIC + SCIP_BASESTAT SCIP_BASESTAT_UPPER + SCIP_BASESTAT SCIP_BASESTAT_ZERO + + ctypedef unsigned long SCIP_EVENTTYPE cdef extern from "scip/type_event.h": - unsigned long SCIP_EVENTTYPE_DISABLED - unsigned long SCIP_EVENTTYPE_VARADDED - unsigned long SCIP_EVENTTYPE_VARDELETED - unsigned long SCIP_EVENTTYPE_VARFIXED - unsigned long SCIP_EVENTTYPE_VARUNLOCKED - unsigned long SCIP_EVENTTYPE_OBJCHANGED - unsigned long SCIP_EVENTTYPE_GLBCHANGED - unsigned long SCIP_EVENTTYPE_GUBCHANGED - unsigned long SCIP_EVENTTYPE_LBTIGHTENED - unsigned long SCIP_EVENTTYPE_LBRELAXED - unsigned long SCIP_EVENTTYPE_UBTIGHTENED - unsigned long SCIP_EVENTTYPE_UBRELAXED - unsigned long SCIP_EVENTTYPE_GHOLEADDED - unsigned long SCIP_EVENTTYPE_GHOLEREMOVED - unsigned long SCIP_EVENTTYPE_LHOLEADDED - unsigned long SCIP_EVENTTYPE_LHOLEREMOVED - unsigned long SCIP_EVENTTYPE_IMPLADDED - unsigned long SCIP_EVENTTYPE_PRESOLVEROUND - unsigned long SCIP_EVENTTYPE_NODEFOCUSED - unsigned long SCIP_EVENTTYPE_NODEFEASIBLE - unsigned long SCIP_EVENTTYPE_NODEINFEASIBLE - unsigned long SCIP_EVENTTYPE_NODEBRANCHED - unsigned long SCIP_EVENTTYPE_NODEDELETE - unsigned long SCIP_EVENTTYPE_FIRSTLPSOLVED - unsigned long SCIP_EVENTTYPE_LPSOLVED - unsigned long SCIP_EVENTTYPE_POORSOLFOUND - unsigned long SCIP_EVENTTYPE_BESTSOLFOUND - unsigned long SCIP_EVENTTYPE_ROWADDEDSEPA - unsigned long SCIP_EVENTTYPE_ROWDELETEDSEPA - unsigned long SCIP_EVENTTYPE_ROWADDEDLP - unsigned long SCIP_EVENTTYPE_ROWDELETEDLP - unsigned long SCIP_EVENTTYPE_ROWCOEFCHANGED - unsigned long SCIP_EVENTTYPE_ROWCONSTCHANGED - unsigned long SCIP_EVENTTYPE_ROWSIDECHANGED - unsigned long SCIP_EVENTTYPE_SYNC - - unsigned long SCIP_EVENTTYPE_LPEVENT - - - ctypedef enum SCIP_LPSOLQUALITY: - SCIP_LPSOLQUALITY_ESTIMCONDITION = 0 - SCIP_LPSOLQUALITY_EXACTCONDITION = 1 - - ctypedef enum SCIP_LOCKTYPE: - SCIP_LOCKTYPE_MODEL = 0 - SCIP_LOCKTYPE_CONFLICT = 1 - - ctypedef enum SCIP_BENDERSENFOTYPE: - SCIP_BENDERSENFOTYPE_LP = 1 - SCIP_BENDERSENFOTYPE_RELAX = 2 - SCIP_BENDERSENFOTYPE_PSEUDO = 3 - SCIP_BENDERSENFOTYPE_CHECK = 4 - - ctypedef enum SCIP_LPSOLSTAT: - SCIP_LPSOLSTAT_NOTSOLVED = 0 - SCIP_LPSOLSTAT_OPTIMAL = 1 - SCIP_LPSOLSTAT_INFEASIBLE = 2 - SCIP_LPSOLSTAT_UNBOUNDEDRAY = 3 - SCIP_LPSOLSTAT_OBJLIMIT = 4 - SCIP_LPSOLSTAT_ITERLIMIT = 5 - SCIP_LPSOLSTAT_TIMELIMIT = 6 - SCIP_LPSOLSTAT_ERROR = 7 - - ctypedef enum SCIP_BRANCHDIR: - SCIP_BRANCHDIR_DOWNWARDS = 0 - SCIP_BRANCHDIR_UPWARDS = 1 - SCIP_BRANCHDIR_FIXED = 2 - SCIP_BRANCHDIR_AUTO = 3 - - ctypedef enum SCIP_BOUNDCHGTYPE: - SCIP_BOUNDCHGTYPE_BRANCHING = 0 - SCIP_BOUNDCHGTYPE_CONSINFER = 1 - SCIP_BOUNDCHGTYPE_PROPINFER = 2 - - ctypedef enum SCIP_ROWORIGINTYPE: - SCIP_ROWORIGINTYPE_UNSPEC = 0 - SCIP_ROWORIGINTYPE_CONS = 1 - SCIP_ROWORIGINTYPE_SEPA = 2 - SCIP_ROWORIGINTYPE_REOPT = 3 + SCIP_EVENTTYPE SCIP_EVENTTYPE_DISABLED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARDELETED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARFIXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARUNLOCKED + SCIP_EVENTTYPE SCIP_EVENTTYPE_OBJCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GLBCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GUBCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LBTIGHTENED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LBRELAXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_UBTIGHTENED + SCIP_EVENTTYPE SCIP_EVENTTYPE_UBRELAXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLEADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLEREMOVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLEREMOVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_IMPLADDED + SCIP_EVENTTYPE SCIP_EVENTTYPE_PRESOLVEROUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEFOCUSED + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEFEASIBLE + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEINFEASIBLE + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEBRANCHED + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEDELETE + SCIP_EVENTTYPE SCIP_EVENTTYPE_FIRSTLPSOLVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LPSOLVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_POORSOLFOUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_BESTSOLFOUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWADDEDSEPA + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWDELETEDSEPA + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWADDEDLP + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWDELETEDLP + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCOEFCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCONSTCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWSIDECHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_SYNC + SCIP_EVENTTYPE SCIP_EVENTTYPE_LPEVENT + + + ctypedef int SCIP_LPSOLQUALITY + cdef extern from "lpi/type_lpi.h": + SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_ESTIMCONDITION + SCIP_LPSOLQUALITY SCIP_LPSOLQUALITY_EXACTCONDITION + + ctypedef int SCIP_LOCKTYPE + cdef extern from "scip/type_var.h": + SCIP_LOCKTYPE SCIP_LOCKTYPE_MODEL + SCIP_LOCKTYPE SCIP_LOCKTYPE_CONFLICT + + ctypedef int SCIP_BENDERSENFOTYPE + cdef extern from "scip/type_benders.h": + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_LP + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_RELAX + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_PSEUDO + SCIP_BENDERSENFOTYPE SCIP_BENDERSENFOTYPE_CHECK + + ctypedef int SCIP_LPSOLSTAT + cdef extern from "scip/type_lp.h": + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_NOTSOLVED + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_OPTIMAL + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_INFEASIBLE + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_UNBOUNDEDRAY + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_OBJLIMIT + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_ITERLIMIT + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_TIMELIMIT + SCIP_LPSOLSTAT SCIP_LPSOLSTAT_ERROR + + ctypedef int SCIP_BRANCHDIR + cdef extern from "scip/type_history.h": + SCIP_BRANCHDIR SCIP_BRANCHDIR_DOWNWARDS + SCIP_BRANCHDIR SCIP_BRANCHDIR_UPWARDS + SCIP_BRANCHDIR SCIP_BRANCHDIR_FIXED + SCIP_BRANCHDIR SCIP_BRANCHDIR_AUTO + + ctypedef int SCIP_BOUNDCHGTYPE + cdef extern from "scip/type_var.h": + SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_BRANCHING + SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_CONSINFER + SCIP_BOUNDCHGTYPE SCIP_BOUNDCHGTYPE_PROPINFER + + ctypedef int SCIP_ROWORIGINTYPE + cdef extern from "scip/type_lp.h": + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_UNSPEC + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_CONS + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_SEPA + SCIP_ROWORIGINTYPE SCIP_ROWORIGINTYPE_REOPT ctypedef bint SCIP_Bool @@ -416,8 +438,8 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_HASHMAP: pass - ctypedef struct SCIP_BOUNDTYPE: - pass + #ctypedef struct SCIP_BOUNDTYPE: + # pass ctypedef struct SCIP_BDCHGIDX: pass @@ -546,41 +568,41 @@ cdef extern from "scip/scip.h": # Event Methods SCIP_RETCODE SCIPcatchEvent(SCIP* scip, - unsigned long eventtype, + SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int* filterpos) SCIP_RETCODE SCIPdropEvent(SCIP* scip, - unsigned long eventtype, + SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int filterpos) SCIP_RETCODE SCIPcatchVarEvent(SCIP* scip, SCIP_VAR* var, - unsigned long eventtype, + SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int* filterpos) SCIP_RETCODE SCIPdropVarEvent(SCIP* scip, SCIP_VAR* var, - unsigned long eventtype, + SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int filterpos) SCIP_RETCODE SCIPcatchRowEvent(SCIP* scip, SCIP_ROW* row, - unsigned long eventtype, + SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int* filterpos) SCIP_RETCODE SCIPdropRowEvent(SCIP* scip, SCIP_ROW* row, - unsigned long eventtype, + SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR* eventhdlr, SCIP_EVENTDATA* eventdata, int filterpos) SCIP_EVENTHDLR* SCIPfindEventhdlr(SCIP* scip, const char* name) - unsigned long SCIPeventGetType(SCIP_EVENT* event) + SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT* event) SCIP_Real SCIPeventGetNewbound(SCIP_EVENT* event) SCIP_Real SCIPeventGetOldbound(SCIP_EVENT* event) SCIP_VAR* SCIPeventGetVar(SCIP_EVENT* event) From ce54e5db00b135680bc2f2e1e51bb2a61279084e Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 28 Nov 2023 23:31:51 +0000 Subject: [PATCH 41/54] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b36a7bfa5..51399024e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Add convenience methods relax and getVarDict - Add SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal ### Fixed +- - Fixed typo in documentation of chgRhs - Pricer plugin fundamental callbacks now raise an error if not implemented - Brachrule plugin fundamental callbacks now raise an error if not implemented From 8e7a4b98540cdb2f01d1b85887a0faddd622cc74 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Tue, 28 Nov 2023 23:32:03 +0000 Subject: [PATCH 42/54] Update CHANGELOG --- CHANGELOG.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51399024e..26c1846e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,13 @@ ## Unreleased ### Added -- Add SCIP functions SCIPconsGetNVars, SCIPconsGetVars -- Add SCIP functions SCIPchgCoefLinear, SCIPaddCoefLinear and SCIPdelCoefLinear -- Add SCIP function SCIPgetSolTime and wrapper getSolTime -- Add convenience methods relax and getVarDict -- Add SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal +- Added SCIP functions SCIPconsGetNVars, SCIPconsGetVars +- Added SCIP functions SCIPchgCoefLinear, SCIPaddCoefLinear and SCIPdelCoefLinear +- Added SCIP function SCIPgetSolTime and wrapper getSolTime +- Added convenience methods relax and getVarDict +- Added SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal ### Fixed -- +- Fixed mistake with outdated values for several enums - Fixed typo in documentation of chgRhs - Pricer plugin fundamental callbacks now raise an error if not implemented - Brachrule plugin fundamental callbacks now raise an error if not implemented @@ -16,6 +16,7 @@ - Changed getSols so that it prints solutions in terms of the original variables - Fixed error message in _checkStage ### Changed +- Made it so SCIP macros are used directly, instead of being manually inputted. - Improved error message when using < or > instead of <= or >= ### Removed - Removed double declaration of SCIPfindEventhdlr From 6d836e6628b616b33d349d917e294a859fab8216 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Wed, 29 Nov 2023 23:31:02 +0000 Subject: [PATCH 43/54] Add NODEDELETE to scip.pxi --- src/pyscipopt/scip.pxi | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 302bc7261..c0e1247f4 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -188,6 +188,7 @@ cdef class PY_SCIP_EVENTTYPE: NODEFEASIBLE = SCIP_EVENTTYPE_NODEFEASIBLE NODEINFEASIBLE = SCIP_EVENTTYPE_NODEINFEASIBLE NODEBRANCHED = SCIP_EVENTTYPE_NODEBRANCHED + NODEDELETE = SCIP_EVENTTYPE_NODEDELETE FIRSTLPSOLVED = SCIP_EVENTTYPE_FIRSTLPSOLVED LPSOLVED = SCIP_EVENTTYPE_LPSOLVED LPEVENT = SCIP_EVENTTYPE_LPEVENT From ec96c7ac832d8e31315ebdf0ae71226c21b08fbc Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sun, 3 Dec 2023 20:12:57 +0000 Subject: [PATCH 44/54] Add test prototype for events --- tests/test_event.py | 68 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/tests/test_event.py b/tests/test_event.py index 72c518073..733d7aa3a 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -1,6 +1,6 @@ -import pytest +import pytest, random -from pyscipopt import Model, Eventhdlr, SCIP_RESULT, SCIP_EVENTTYPE, SCIP_PARAMSETTING +from pyscipopt import Model, Eventhdlr, SCIP_RESULT, SCIP_EVENTTYPE, SCIP_PARAMSETTING, quicksum calls = [] @@ -8,43 +8,49 @@ class MyEvent(Eventhdlr): def eventinit(self): calls.append('eventinit') - self.model.catchEvent(SCIP_EVENTTYPE.FIRSTLPSOLVED, self) + #self.model.catchEvent(SCIP_EVENTTYPE.FIRSTLPSOLVED, self) + self.model.catchEvent(self.event_type, self) def eventexit(self): - calls.append('eventexit') - self.model.dropEvent(SCIP_EVENTTYPE.FIRSTLPSOLVED, self) + self.model.dropEvent(self.event_type, self) def eventexec(self, event): calls.append('eventexec') - assert event.getType() == SCIP_EVENTTYPE.FIRSTLPSOLVED - assert event.getNode().getNumber() == 1 - assert event.getNode().getParent() is None + print(event.getType(),self.event_type) + if self.event_type == SCIP_EVENTTYPE.LPEVENT: + assert event.getType() in [SCIP_EVENTTYPE.FIRSTLPSOLVED, SCIP_EVENTTYPE.LPSOLVED] + else: + assert event.getType() == self.event_type + #assert event.getNode().getNumber() == 1 + #assert event.getNode().getParent() is None def test_event(): - # create solver instance - s = Model() - s.hideOutput() - s.setPresolve(SCIP_PARAMSETTING.OFF) - eventhdlr = MyEvent() - s.includeEventhdlr(eventhdlr, "TestFirstLPevent", "python event handler to catch FIRSTLPEVENT") - - # add some variables - x = s.addVar("x", obj=1.0) - y = s.addVar("y", obj=2.0) - - # add some constraint - s.addCons(x + 2*y >= 5) - # solve problem - s.optimize() - - # print solution - assert round(s.getVal(x)) == 5.0 - assert round(s.getVal(y)) == 0.0 + + all_events = [SCIP_EVENTTYPE.DISABLED,SCIP_EVENTTYPE.VARADDED,SCIP_EVENTTYPE.VARDELETED,SCIP_EVENTTYPE.VARFIXED,SCIP_EVENTTYPE.VARUNLOCKED,SCIP_EVENTTYPE.OBJCHANGED,SCIP_EVENTTYPE.GLBCHANGED,SCIP_EVENTTYPE.GUBCHANGED,SCIP_EVENTTYPE.LBTIGHTENED,SCIP_EVENTTYPE.LBRELAXED,SCIP_EVENTTYPE.UBTIGHTENED,SCIP_EVENTTYPE.UBRELAXED,SCIP_EVENTTYPE.GHOLEADDED,SCIP_EVENTTYPE.GHOLEREMOVED,SCIP_EVENTTYPE.LHOLEADDED,SCIP_EVENTTYPE.LHOLEREMOVED,SCIP_EVENTTYPE.IMPLADDED,SCIP_EVENTTYPE.PRESOLVEROUND,SCIP_EVENTTYPE.NODEFOCUSED,SCIP_EVENTTYPE.NODEFEASIBLE,SCIP_EVENTTYPE.NODEINFEASIBLE,SCIP_EVENTTYPE.NODEBRANCHED,SCIP_EVENTTYPE.FIRSTLPSOLVED,SCIP_EVENTTYPE.LPSOLVED,SCIP_EVENTTYPE.POORSOLFOUND,SCIP_EVENTTYPE.BESTSOLFOUND,SCIP_EVENTTYPE.ROWADDEDSEPA,SCIP_EVENTTYPE.ROWDELETEDSEPA,SCIP_EVENTTYPE.ROWADDEDLP,SCIP_EVENTTYPE.ROWDELETEDLP,SCIP_EVENTTYPE.ROWCOEFCHANGED,SCIP_EVENTTYPE.ROWCONSTCHANGED,SCIP_EVENTTYPE.ROWSIDECHANGED,SCIP_EVENTTYPE.SYNC,SCIP_EVENTTYPE.LPEVENT] + + all_event_hdlrs = [] + for event in all_events: + # create solver instance + s = Model() + s.hideOutput() + s.setPresolve(SCIP_PARAMSETTING.OFF) + all_event_hdlrs.append(MyEvent()) + all_event_hdlrs[-1].event_type = event + s.includeEventhdlr(all_event_hdlrs[-1], str(event), "python event handler to catch %s" % str(event)) + + x = {} + # add some variables + for i in range(100): + x[i] = s.addVar("x", obj=random.random(), vtype="I") + + # add some constraints + for j in range(1,20): + s.addCons(quicksum(x[i] for i in range(100) if i%j==0) >= random.randint(10,100)) + + # solve problem + s.optimize() del s - assert 'eventinit' in calls - assert 'eventexit' in calls - assert 'eventexec' in calls - assert len(calls) == 3 +test_event() \ No newline at end of file From e919e2910c680bc153b4cfbc3d207b5ce036b9cf Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sun, 3 Dec 2023 20:28:02 +0000 Subject: [PATCH 45/54] Add more SCIP events --- src/pyscipopt/scip.pxd | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 36a0b2668..0f08d26c8 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -249,7 +249,24 @@ cdef extern from "scip/scip.h": SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCONSTCHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWSIDECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_SYNC - SCIP_EVENTTYPE SCIP_EVENTTYPE_LPEVENT + SCIP_EVENTTYPE SCIP_EVENTTYPE_GBDCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LBCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_UBCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDTIGHTENED + SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDRELAXED + SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLECHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_HOLECHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_DOMCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VARCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_VAREVENT + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODESOLVED + SCIP_EVENTTYPE SCIP_EVENTTYPE_NODEEVENT + SCIP_EVENTTYPE SCIP_EVENTTYPE_LPEVENT + SCIP_EVENTTYPE SCIP_EVENTTYPE_SOLFOUND + SCIP_EVENTTYPE SCIP_EVENTTYPE_SOLEVENT + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_ROWEVENT ctypedef int SCIP_LPSOLQUALITY From 763041f2a068a4d69598242787105839a62c3f5e Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sun, 3 Dec 2023 22:17:15 +0000 Subject: [PATCH 46/54] Add all event types as of SCIP 8 --- src/pyscipopt/scip.pxi | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 64ed81cf0..ba2496361 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -202,7 +202,24 @@ cdef class PY_SCIP_EVENTTYPE: ROWCONSTCHANGED = SCIP_EVENTTYPE_ROWCONSTCHANGED ROWSIDECHANGED = SCIP_EVENTTYPE_ROWSIDECHANGED SYNC = SCIP_EVENTTYPE_SYNC - NODESOLVED = SCIP_EVENTTYPE_NODEFEASIBLE | SCIP_EVENTTYPE_NODEINFEASIBLE | SCIP_EVENTTYPE_NODEBRANCHED + GBDCHANGED = SCIP_EVENTTYPE_GBDCHANGED + LBCHANGED = SCIP_EVENTTYPE_LBCHANGED + UBCHANGED = SCIP_EVENTTYPE_UBCHANGED + BOUNDTIGHTENED = SCIP_EVENTTYPE_BOUNDTIGHTENED + BOUNDRELAXED = SCIP_EVENTTYPE_BOUNDRELAXED + BOUNDCHANGED = SCIP_EVENTTYPE_BOUNDCHANGED + GHOLECHANGED = SCIP_EVENTTYPE_GHOLECHANGED + LHOLECHANGED = SCIP_EVENTTYPE_LHOLECHANGED + HOLECHANGED = SCIP_EVENTTYPE_HOLECHANGED + DOMCHANGED = SCIP_EVENTTYPE_DOMCHANGED + VARCHANGED = SCIP_EVENTTYPE_VARCHANGED + VAREVENT = SCIP_EVENTTYPE_VAREVENT + NODESOLVED = SCIP_EVENTTYPE_NODESOLVED + NODEEVENT = SCIP_EVENTTYPE_NODEEVENT + SOLFOUND = SCIP_EVENTTYPE_SOLFOUND + SOLEVENT = SCIP_EVENTTYPE_SOLEVENT + ROWCHANGED = SCIP_EVENTTYPE_ROWCHANGED + ROWEVENT = SCIP_EVENTTYPE_ROWEVENT cdef class PY_SCIP_LPSOLSTAT: NOTSOLVED = SCIP_LPSOLSTAT_NOTSOLVED From 08372e9366744e5e93f92ea4e5a917ddaf67a820 Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sun, 3 Dec 2023 22:18:35 +0000 Subject: [PATCH 47/54] Add test for event identification --- src/pyscipopt/scip.pxd | 1 + tests/test_event.py | 62 ++++++++++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index 0f08d26c8..c5826b4ad 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -255,6 +255,7 @@ cdef extern from "scip/scip.h": SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDTIGHTENED SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDRELAXED SCIP_EVENTTYPE SCIP_EVENTTYPE_BOUNDCHANGED + SCIP_EVENTTYPE SCIP_EVENTTYPE_GHOLECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_LHOLECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_HOLECHANGED SCIP_EVENTTYPE SCIP_EVENTTYPE_DOMCHANGED diff --git a/tests/test_event.py b/tests/test_event.py index 733d7aa3a..92653eab4 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -8,30 +8,65 @@ class MyEvent(Eventhdlr): def eventinit(self): calls.append('eventinit') - #self.model.catchEvent(SCIP_EVENTTYPE.FIRSTLPSOLVED, self) self.model.catchEvent(self.event_type, self) - def eventexit(self): - self.model.dropEvent(self.event_type, self) + #def eventexit(self): + # self.model.dropEvent(self.event_type, self) def eventexec(self, event): calls.append('eventexec') - print(event.getType(),self.event_type) if self.event_type == SCIP_EVENTTYPE.LPEVENT: assert event.getType() in [SCIP_EVENTTYPE.FIRSTLPSOLVED, SCIP_EVENTTYPE.LPSOLVED] + elif self.event_type == SCIP_EVENTTYPE.GBDCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.GLBCHANGED, SCIP_EVENTTYPE.GUBCHANGED] + elif self.event_type == SCIP_EVENTTYPE.LBCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.LBTIGHTENED, SCIP_EVENTTYPE.LBRELAXED] + elif self.event_type == SCIP_EVENTTYPE.UBCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.UBTIGHTENED, SCIP_EVENTTYPE.UBRELAXED] + elif self.event_type == SCIP_EVENTTYPE.BOUNDTIGHTENED: + assert event.getType() in [SCIP_EVENTTYPE.LBTIGHTENED, SCIP_EVENTTYPE.UBTIGHTENED] + elif self.event_type == SCIP_EVENTTYPE.BOUNDRELAXED: + assert event.getType() in [SCIP_EVENTTYPE.LBRELAXED, SCIP_EVENTTYPE.UBRELAXED] + elif self.event_type == SCIP_EVENTTYPE.BOUNDCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.LBCHANGED, SCIP_EVENTTYPE.UBCHANGED] + elif self.event_type == SCIP_EVENTTYPE.GHOLECHANGED: + assert event.getType() in [SCIP_EVENTTYPE.GHOLEADDED, SCIP_EVENTTYPE.GHOLEREMOVED] + elif self.event_type == SCIP_EVENTTYPE.LHOLECHANGED: + assert event.getType() in [SCIP_EVENTTYPE.LHOLEADDED, SCIP_EVENTTYPE.LHOLEREMOVED] + elif self.event_type == SCIP_EVENTTYPE.HOLECHANGED: + assert event.getType() in [SCIP_EVENTTYPE.GHOLECHANGED, SCIP_EVENTTYPE.LHOLECHANGED] + elif self.event_type == SCIP_EVENTTYPE.DOMCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.BOUNDCHANGED, SCIP_EVENTTYPE.HOLECHANGED] + elif self.event_type == SCIP_EVENTTYPE.VARCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.VARFIXED, SCIP_EVENTTYPE.VARUNLOCKED, SCIP_EVENTTYPE.OBJCHANGED, SCIP_EVENTTYPE.GBDCHANGED, SCIP_EVENTTYPE.DOMCHANGED, SCIP_EVENTTYPE.IMPLADDED, SCIP_EVENTTYPE.VARDELETED, SCIP_EVENTTYPE.TYPECHANGED] + elif self.event_type == SCIP_EVENTTYPE.VAREVENT: + assert event.getType() in [SCIP_EVENTTYPE.VARADDED, SCIP_EVENTTYPE.VARCHANGED, SCIP_EVENTTYPE.TYPECHANGED] + elif self.event_type == SCIP_EVENTTYPE.NODESOLVED: + assert event.getType() in [SCIP_EVENTTYPE.NODEFEASIBLE, SCIP_EVENTTYPE.NODEINFEASIBLE, SCIP_EVENTTYPE.NODEBRANCHED] + elif self.event_type == SCIP_EVENTTYPE.NODEEVENT: + assert event.getType() in [SCIP_EVENTTYPE.NODEFOCUSED, SCIP_EVENTTYPE.NODEFEASIBLE, SCIP_EVENTTYPE.NODEINFEASIBLE, SCIP_EVENTTYPE.NODEBRANCHED] + elif self.event_type == SCIP_EVENTTYPE.LPEVENT: + assert event.getType() in [SCIP_EVENTTYPE.FIRSTLPSOLVED, SCIP_EVENTTYPE.LPSOLVED] + elif self.event_type == SCIP_EVENTTYPE.SOLFOUND: + assert event.getType() in [SCIP_EVENTTYPE.POORSOLFOUND, SCIP_EVENTTYPE.BESTSOLFOUND] + elif self.event_type == SCIP_EVENTTYPE.ROWCHANGED: + assert event.getType() in [SCIP_EVENTTYPE.ROWCOEFCHANGED, SCIP_EVENTTYPE.ROWCONSTCHANGED, SCIP_EVENTTYPE.ROWSIDECHANGED] + elif self.event_type == SCIP_EVENTTYPE.ROWEVENT: + assert event.getType() in [SCIP_EVENTTYPE.ROWADDEDSEPA, SCIP_EVENTTYPE.ROWDELETEDSEPA, SCIP_EVENTTYPE.ROWADDEDLP, SCIP_EVENTTYPE.ROWDELETEDLP, SCIP_EVENTTYPE.ROWCHANGED] else: assert event.getType() == self.event_type - #assert event.getNode().getNumber() == 1 - #assert event.getNode().getParent() is None def test_event(): - all_events = [SCIP_EVENTTYPE.DISABLED,SCIP_EVENTTYPE.VARADDED,SCIP_EVENTTYPE.VARDELETED,SCIP_EVENTTYPE.VARFIXED,SCIP_EVENTTYPE.VARUNLOCKED,SCIP_EVENTTYPE.OBJCHANGED,SCIP_EVENTTYPE.GLBCHANGED,SCIP_EVENTTYPE.GUBCHANGED,SCIP_EVENTTYPE.LBTIGHTENED,SCIP_EVENTTYPE.LBRELAXED,SCIP_EVENTTYPE.UBTIGHTENED,SCIP_EVENTTYPE.UBRELAXED,SCIP_EVENTTYPE.GHOLEADDED,SCIP_EVENTTYPE.GHOLEREMOVED,SCIP_EVENTTYPE.LHOLEADDED,SCIP_EVENTTYPE.LHOLEREMOVED,SCIP_EVENTTYPE.IMPLADDED,SCIP_EVENTTYPE.PRESOLVEROUND,SCIP_EVENTTYPE.NODEFOCUSED,SCIP_EVENTTYPE.NODEFEASIBLE,SCIP_EVENTTYPE.NODEINFEASIBLE,SCIP_EVENTTYPE.NODEBRANCHED,SCIP_EVENTTYPE.FIRSTLPSOLVED,SCIP_EVENTTYPE.LPSOLVED,SCIP_EVENTTYPE.POORSOLFOUND,SCIP_EVENTTYPE.BESTSOLFOUND,SCIP_EVENTTYPE.ROWADDEDSEPA,SCIP_EVENTTYPE.ROWDELETEDSEPA,SCIP_EVENTTYPE.ROWADDEDLP,SCIP_EVENTTYPE.ROWDELETEDLP,SCIP_EVENTTYPE.ROWCOEFCHANGED,SCIP_EVENTTYPE.ROWCONSTCHANGED,SCIP_EVENTTYPE.ROWSIDECHANGED,SCIP_EVENTTYPE.SYNC,SCIP_EVENTTYPE.LPEVENT] - + all_events = [SCIP_EVENTTYPE.DISABLED,SCIP_EVENTTYPE.VARADDED,SCIP_EVENTTYPE.VARDELETED,SCIP_EVENTTYPE.VARFIXED,SCIP_EVENTTYPE.VARUNLOCKED,SCIP_EVENTTYPE.OBJCHANGED,SCIP_EVENTTYPE.GLBCHANGED,SCIP_EVENTTYPE.GUBCHANGED,SCIP_EVENTTYPE.LBTIGHTENED,SCIP_EVENTTYPE.LBRELAXED,SCIP_EVENTTYPE.UBTIGHTENED,SCIP_EVENTTYPE.UBRELAXED,SCIP_EVENTTYPE.GHOLEADDED,SCIP_EVENTTYPE.GHOLEREMOVED,SCIP_EVENTTYPE.LHOLEADDED,SCIP_EVENTTYPE.LHOLEREMOVED,SCIP_EVENTTYPE.IMPLADDED,SCIP_EVENTTYPE.PRESOLVEROUND,SCIP_EVENTTYPE.NODEFOCUSED,SCIP_EVENTTYPE.NODEFEASIBLE,SCIP_EVENTTYPE.NODEINFEASIBLE,SCIP_EVENTTYPE.NODEBRANCHED,SCIP_EVENTTYPE.NODEDELETE,SCIP_EVENTTYPE.FIRSTLPSOLVED,SCIP_EVENTTYPE.LPSOLVED,SCIP_EVENTTYPE.POORSOLFOUND,SCIP_EVENTTYPE.BESTSOLFOUND,SCIP_EVENTTYPE.ROWADDEDSEPA,SCIP_EVENTTYPE.ROWDELETEDSEPA,SCIP_EVENTTYPE.ROWADDEDLP,SCIP_EVENTTYPE.ROWDELETEDLP,SCIP_EVENTTYPE.ROWCOEFCHANGED,SCIP_EVENTTYPE.ROWCONSTCHANGED,SCIP_EVENTTYPE.ROWSIDECHANGED,SCIP_EVENTTYPE.SYNC,SCIP_EVENTTYPE.GBDCHANGED,SCIP_EVENTTYPE.LBCHANGED,SCIP_EVENTTYPE.UBCHANGED,SCIP_EVENTTYPE.BOUNDTIGHTENED,SCIP_EVENTTYPE.BOUNDRELAXED,SCIP_EVENTTYPE.BOUNDCHANGED,SCIP_EVENTTYPE.LHOLECHANGED,SCIP_EVENTTYPE.HOLECHANGED,SCIP_EVENTTYPE.DOMCHANGED,SCIP_EVENTTYPE.VARCHANGED,SCIP_EVENTTYPE.VAREVENT,SCIP_EVENTTYPE.NODESOLVED,SCIP_EVENTTYPE.NODEEVENT,SCIP_EVENTTYPE.LPEVENT,SCIP_EVENTTYPE.SOLFOUND,SCIP_EVENTTYPE.SOLEVENT,SCIP_EVENTTYPE.ROWCHANGED,SCIP_EVENTTYPE.ROWEVENT] + + + for i in [20]: + print(SCIP_EVENTTYPE.NODEINFEASIBLE) + all_event_hdlrs = [] for event in all_events: - # create solver instance s = Model() s.hideOutput() s.setPresolve(SCIP_PARAMSETTING.OFF) @@ -40,17 +75,10 @@ def test_event(): s.includeEventhdlr(all_event_hdlrs[-1], str(event), "python event handler to catch %s" % str(event)) x = {} - # add some variables for i in range(100): x[i] = s.addVar("x", obj=random.random(), vtype="I") - # add some constraints for j in range(1,20): s.addCons(quicksum(x[i] for i in range(100) if i%j==0) >= random.randint(10,100)) - # solve problem - s.optimize() - - del s - -test_event() \ No newline at end of file + s.optimize() \ No newline at end of file From 8bb4f83c54726f0e37e353d979ba5689f8f1637b Mon Sep 17 00:00:00 2001 From: Joao-Dionisio Date: Sun, 3 Dec 2023 22:19:46 +0000 Subject: [PATCH 48/54] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f4410e9e..845c21d61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased ### Added +- Added all event types and tests for checking them - Added SCIP functions SCIPconsGetNVars, SCIPconsGetVars - Added SCIP functions SCIPchgCoefLinear, SCIPaddCoefLinear and SCIPdelCoefLinear - Added SCIP function SCIPgetSolTime and wrapper getSolTime From c0ec88d0eeef7771c7be39276ee438c2df0d1ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dion=C3=ADsio?= <57299939+Joao-Dionisio@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:49:00 +0000 Subject: [PATCH 49/54] Remove commented code --- src/pyscipopt/scip.pxd | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pyscipopt/scip.pxd b/src/pyscipopt/scip.pxd index c5826b4ad..12815dbc4 100644 --- a/src/pyscipopt/scip.pxd +++ b/src/pyscipopt/scip.pxd @@ -456,9 +456,6 @@ cdef extern from "scip/scip.h": ctypedef struct SCIP_HASHMAP: pass - #ctypedef struct SCIP_BOUNDTYPE: - # pass - ctypedef struct SCIP_BDCHGIDX: pass From 269a482aadf2a9937b76e2b50be0a15ed6eb2054 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Mon, 4 Dec 2023 17:02:51 +0100 Subject: [PATCH 50/54] Update version --- CHANGELOG.md | 8 +++++++- src/pyscipopt/__init__.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 845c21d61..4bc6e0d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # CHANGELOG -## Unreleased +## Untracked +### Added +### Fixed +### Changed +### Removed + +## 4.4.0 - 2023-12-04 ### Added - Added all event types and tests for checking them - Added SCIP functions SCIPconsGetNVars, SCIPconsGetVars diff --git a/src/pyscipopt/__init__.py b/src/pyscipopt/__init__.py index e3e760dc7..8221fb130 100644 --- a/src/pyscipopt/__init__.py +++ b/src/pyscipopt/__init__.py @@ -1,4 +1,4 @@ -__version__ = '4.3.0' +__version__ = '4.4.0' # required for Python 3.8 on Windows import os From 077e32e5ebd4d18e3219038858d194a04e8cbc6c Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Mon, 4 Dec 2023 17:05:39 +0100 Subject: [PATCH 51/54] Rename --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc6e0d22..5453b1faa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## Untracked +## Unreleased ### Added ### Fixed ### Changed From 2d8815b06a1b7ff9d035e875188365aed524103e Mon Sep 17 00:00:00 2001 From: Mark Turner Date: Thu, 7 Dec 2023 13:47:09 +0100 Subject: [PATCH 52/54] Add function getconshdlrname --- CHANGELOG.md | 1 + src/pyscipopt/scip.pxi | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca1ff959a..5293f6a4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Add convenience methods relax and getVarDict - Add SCIP functions hasPrimalRay, getPrimalRay, getPrimalRayVal - Add multiple tests for constraints and for solutions +- Add getConshdlrName to class Constraint ### Fixed - Correctly set result, lowerbound in PyRelaxExec - Fixed typo in documentation of chgRhs diff --git a/src/pyscipopt/scip.pxi b/src/pyscipopt/scip.pxi index 707586581..9a6d6d052 100644 --- a/src/pyscipopt/scip.pxi +++ b/src/pyscipopt/scip.pxi @@ -923,6 +923,11 @@ cdef class Constraint: constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(self.scip_cons))).decode('UTF-8') return constype == 'nonlinear' + def getConshdlrName(self): + """Return the constraint handler's name""" + constype = bytes(SCIPconshdlrGetName(SCIPconsGetHdlr(self.scip_cons))).decode('UTF-8') + return constype + def __hash__(self): return hash(self.scip_cons) @@ -5117,4 +5122,4 @@ def is_memory_freed(): return BMSgetMemoryUsed() == 0 def print_memory_in_use(): - BMScheckEmptyMemory() \ No newline at end of file + BMScheckEmptyMemory() From 3cfe3661a365a5c5633e25b282cea1ad73808ee5 Mon Sep 17 00:00:00 2001 From: Mark Turner Date: Fri, 8 Dec 2023 14:24:54 +0100 Subject: [PATCH 53/54] Add check to test_cons --- tests/test_cons.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_cons.py b/tests/test_cons.py index 19c0551d1..74cb57472 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -96,6 +96,8 @@ def test_SOScons(): assert m.isEQ(m.getVal(x[3]), 1) assert m.isEQ(m.getVal(x[4]), 1) assert m.isEQ(m.getVal(x[5]), 1) + assert c1.getConshdlrName() == "SOS1" + assert c2.getConshdlrName() == "SOS1" def test_cons_indicator(): @@ -112,6 +114,7 @@ def test_cons_indicator(): assert m.isEQ(m.getVal(slack), 0) assert m.isEQ(m.getVal(binvar), 1) assert m.isEQ(m.getVal(x), 1) + assert c.getConshdlrName() == "indicator" @pytest.mark.xfail(reason="addConsIndicator doesn't behave as expected when binary variable is False. See Issue #717.") From 95d52450645a7e2915974693c7daa52a91ecfc4d Mon Sep 17 00:00:00 2001 From: Mark Turner Date: Fri, 8 Dec 2023 14:33:11 +0100 Subject: [PATCH 54/54] Change assert to SOS2 --- tests/test_cons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cons.py b/tests/test_cons.py index 74cb57472..c3f1f1978 100644 --- a/tests/test_cons.py +++ b/tests/test_cons.py @@ -97,7 +97,7 @@ def test_SOScons(): assert m.isEQ(m.getVal(x[4]), 1) assert m.isEQ(m.getVal(x[5]), 1) assert c1.getConshdlrName() == "SOS1" - assert c2.getConshdlrName() == "SOS1" + assert c2.getConshdlrName() == "SOS2" def test_cons_indicator():