From bcacc3710a9745a40fdb00a4c807ecac875ecdcf Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Mon, 10 Apr 2023 22:33:35 -0400 Subject: [PATCH 1/2] prevent crash on non-convex quadratic objective --- ilpy/impl/solvers/GurobiBackend.cpp | 14 ++++++++++++-- tests/test_solvers.py | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/ilpy/impl/solvers/GurobiBackend.cpp b/ilpy/impl/solvers/GurobiBackend.cpp index 9faf868..e8f63c8 100644 --- a/ilpy/impl/solvers/GurobiBackend.cpp +++ b/ilpy/impl/solvers/GurobiBackend.cpp @@ -218,21 +218,31 @@ GurobiBackend::solve(Solution& x, std::string& msg) { GRB_CHECK(GRBupdatemodel(_model)); + GRBenv* modelenv = GRBgetenv(_model); + if (_timeout > 0) { - GRBenv* modelenv = GRBgetenv(_model); GRB_CHECK(GRBsetdblparam(modelenv, GRB_DBL_PAR_TIMELIMIT, _timeout)); } if (_gap >= 0) { - GRBenv* modelenv = GRBgetenv(_model); if (_absoluteGap) GRB_CHECK(GRBsetdblparam(modelenv, GRB_DBL_PAR_MIPGAPABS, _gap)); else GRB_CHECK(GRBsetdblparam(modelenv, GRB_DBL_PAR_MIPGAP, _gap)); } + // Sets the strategy for handling non-convex quadratic objectives + // or non-convex quadratic constraints. + // 0 = an error is reported if the original user model contains non-convex + // quadratic constructs. + // 1 = an error is reported if non-convex quadratic constructs could not be + // discarded or linearized during presolve. + // 2 = non-convex quadratic problems are solved by means of translating them + // into bilinear form and applying spatial branching. + GRB_CHECK(GRBsetintparam(modelenv, GRB_INT_PAR_NONCONVEX, 2)); + GRB_CHECK(GRBoptimize(_model)); int status; diff --git a/tests/test_solvers.py b/tests/test_solvers.py index e635202..6cdf4cb 100644 --- a/tests/test_solvers.py +++ b/tests/test_solvers.py @@ -101,3 +101,24 @@ def test_quadratic_solver(preference: ilpy.Preference, as_expression: bool) -> N solution, _ = solver.solve() assert solution[5] == -2 # jan please check + + +@pytest.mark.parametrize( + "preference", + [ilpy.Preference.Scip, pytest.param(ilpy.Preference.Gurobi, marks=marks)], +) +def test_non_convex_quadratic(preference: ilpy.Preference) -> None: + # currently, just a smoke test to make sure we don't crash on solve. + obj = ilpy.Objective() + obj.set_quadratic_coefficient(0, 0, -1) # quadratic term (-x^2) + + solver = ilpy.Solver(1, ilpy.VariableType.Continuous, preference=preference) + solver.set_objective(obj) + + constraint = ilpy.Constraint() + constraint.set_coefficient(0, 1) + constraint.set_value(1) + solver.add_constraint(constraint) + + # Gurobi will give zeros and SCIP will give something like -9999999987 + assert solver.solve() is not None From e45473896b64cc415143739884fd305ef7b7d9d9 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 11 Apr 2023 09:44:59 -0400 Subject: [PATCH 2/2] fix test --- tests/test_solvers.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/test_solvers.py b/tests/test_solvers.py index 5b858f1..47cb8a4 100644 --- a/tests/test_solvers.py +++ b/tests/test_solvers.py @@ -13,11 +13,11 @@ HAVE_GUROBI = False +PREFS = [ilpy.Preference.Scip, pytest.param(ilpy.Preference.Gurobi, marks=gu_marks)] + + @pytest.mark.parametrize("as_expression", [True, False], ids=["as_expr", "as_constr"]) -@pytest.mark.parametrize( - "preference", - [ilpy.Preference.Scip, pytest.param(ilpy.Preference.Gurobi, marks=gu_marks)], -) +@pytest.mark.parametrize("preference", PREFS) def test_simple_solver(preference: ilpy.Preference, as_expression: bool) -> None: num_vars = 10 special_var = 5 @@ -62,10 +62,7 @@ def test_simple_solver(preference: ilpy.Preference, as_expression: bool) -> None @pytest.mark.parametrize("as_expression", [True, False], ids=["as_expr", "as_constr"]) -@pytest.mark.parametrize( - "preference", - [ilpy.Preference.Scip, pytest.param(ilpy.Preference.Gurobi, marks=gu_marks)], -) +@pytest.mark.parametrize("preference", PREFS) def test_quadratic_solver(preference: ilpy.Preference, as_expression: bool) -> None: num_vars = 10 special_var = 5 @@ -105,10 +102,7 @@ def test_quadratic_solver(preference: ilpy.Preference, as_expression: bool) -> N assert solution[5] == -2 # jan please check -@pytest.mark.parametrize( - "preference", - [ilpy.Preference.Scip, pytest.param(ilpy.Preference.Gurobi, marks=marks)], -) +@pytest.mark.parametrize("preference", PREFS) def test_non_convex_quadratic(preference: ilpy.Preference) -> None: # currently, just a smoke test to make sure we don't crash on solve. obj = ilpy.Objective()