From 02d2dd25fe4cb6ab510783d7e30b7348bf3e2a8b Mon Sep 17 00:00:00 2001 From: Arnaud Baguet Date: Sat, 17 Aug 2024 22:50:23 -0400 Subject: [PATCH 1/5] remove deprecated addConstr call --- .../solvers/plugins/solvers/gurobi_direct.py | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/gurobi_direct.py b/pyomo/solvers/plugins/solvers/gurobi_direct.py index ed66a4e0e7b..4a2494daf2f 100644 --- a/pyomo/solvers/plugins/solvers/gurobi_direct.py +++ b/pyomo/solvers/plugins/solvers/gurobi_direct.py @@ -97,6 +97,20 @@ def _set_options(model_or_env, options): model_or_env.setParam(key, float(option)) +class GurobiModel(gurobipy.Model): + def __init__(self, *args, **kwds): + super().__init__(*args, **kwds) + + def addConstr(self, degree, lhs, sense=None, rhs=None, name=""): + if degree == 1: + con = self.addLConstr(lhs, sense, rhs, name) + elif degree == 2: + con = self.addQConstr(lhs, sense, rhs, name) + else: + raise DegreeError('GurobiModel.addConstr: Unsupported degree: %s' % degree) + return con + + @SolverFactory.register('gurobi_direct', doc='Direct python interface to Gurobi') class GurobiDirect(DirectSolver): """A direct interface to Gurobi using gurobipy. @@ -308,7 +322,7 @@ def _get_expr_from_pyomo_repn(self, repn, max_degree=2): new_expr += repn.constant - return new_expr, referenced_vars + return new_expr, referenced_vars, degree def _get_expr_from_pyomo_expr(self, expr, max_degree=2): if max_degree == 2: @@ -317,7 +331,7 @@ def _get_expr_from_pyomo_expr(self, expr, max_degree=2): repn = generate_standard_repn(expr, quadratic=False) try: - gurobi_expr, referenced_vars = self._get_expr_from_pyomo_repn( + gurobi_expr, referenced_vars, degree = self._get_expr_from_pyomo_repn( repn, max_degree ) except DegreeError as e: @@ -325,7 +339,7 @@ def _get_expr_from_pyomo_expr(self, expr, max_degree=2): msg += '\nexpr: {0}'.format(expr) raise DegreeError(msg) - return gurobi_expr, referenced_vars + return gurobi_expr, referenced_vars, degree def _gurobi_lb_ub_from_var(self, var): if var.is_fixed(): @@ -404,10 +418,12 @@ def _create_model(self, model): self._init_env() if self._solver_model is not None: self._solver_model.close() - if model.name is not None: - self._solver_model = gurobipy.Model(model.name, env=self._env) - else: - self._solver_model = gurobipy.Model(env=self._env) + + self._solver_model = ( + GurobiModel(model.name, env=self._env) + if model.name is not None + else GurobiModel(env=self._env) + ) def close(self): """Frees local Gurobi resources used by this solver instance. @@ -499,15 +515,11 @@ def _add_constraint(self, con): conname = self._symbol_map.getSymbol(con, self._labeler) if con._linear_canonical_form: - gurobi_expr, referenced_vars = self._get_expr_from_pyomo_repn( + gurobi_expr, referenced_vars, degree = self._get_expr_from_pyomo_repn( con.canonical_form(), self._max_constraint_degree ) - # elif isinstance(con, LinearCanonicalRepn): - # gurobi_expr, referenced_vars = self._get_expr_from_pyomo_repn( - # con, - # self._max_constraint_degree) else: - gurobi_expr, referenced_vars = self._get_expr_from_pyomo_expr( + gurobi_expr, referenced_vars, degree = self._get_expr_from_pyomo_expr( con.body, self._max_constraint_degree ) @@ -524,6 +536,7 @@ def _add_constraint(self, con): if con.equality: gurobipy_con = self._solver_model.addConstr( + degree=degree, lhs=gurobi_expr, sense=gurobipy.GRB.EQUAL, rhs=value(con.lower), @@ -536,6 +549,7 @@ def _add_constraint(self, con): self._range_constraints.add(con) elif con.has_lb(): gurobipy_con = self._solver_model.addConstr( + degree=degree, lhs=gurobi_expr, sense=gurobipy.GRB.GREATER_EQUAL, rhs=value(con.lower), @@ -543,6 +557,7 @@ def _add_constraint(self, con): ) elif con.has_ub(): gurobipy_con = self._solver_model.addConstr( + degree=degree, lhs=gurobi_expr, sense=gurobipy.GRB.LESS_EQUAL, rhs=value(con.upper), From b72310a8212458b9b205912921bf72374d5c714d Mon Sep 17 00:00:00 2001 From: Arnaud Baguet Date: Sun, 18 Aug 2024 05:40:19 -0400 Subject: [PATCH 2/5] remove unused import in gurobi_direct --- pyomo/solvers/plugins/solvers/gurobi_direct.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/gurobi_direct.py b/pyomo/solvers/plugins/solvers/gurobi_direct.py index 4a2494daf2f..91fb107e557 100644 --- a/pyomo/solvers/plugins/solvers/gurobi_direct.py +++ b/pyomo/solvers/plugins/solvers/gurobi_direct.py @@ -32,7 +32,6 @@ from pyomo.opt.results.solver import TerminationCondition, SolverStatus from pyomo.opt.base import SolverFactory from pyomo.core.base.suffix import Suffix -import pyomo.core.base.var logger = logging.getLogger('pyomo.solvers') @@ -410,7 +409,7 @@ def _init_env(self): else: # Ensure the (global) default env is started if not GurobiDirect._default_env_started: - m = gurobipy.Model() + m = GurobiModel() m.close() GurobiDirect._default_env_started = True From d1aa3c0d8fff7d5a016424ecf0e6f2b4a176939c Mon Sep 17 00:00:00 2001 From: Arnaud Baguet Date: Mon, 19 Aug 2024 21:31:02 -0400 Subject: [PATCH 3/5] implement jsiirola's suggestion --- .../solvers/plugins/solvers/gurobi_direct.py | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/gurobi_direct.py b/pyomo/solvers/plugins/solvers/gurobi_direct.py index 91fb107e557..1ed4c5e3505 100644 --- a/pyomo/solvers/plugins/solvers/gurobi_direct.py +++ b/pyomo/solvers/plugins/solvers/gurobi_direct.py @@ -96,20 +96,6 @@ def _set_options(model_or_env, options): model_or_env.setParam(key, float(option)) -class GurobiModel(gurobipy.Model): - def __init__(self, *args, **kwds): - super().__init__(*args, **kwds) - - def addConstr(self, degree, lhs, sense=None, rhs=None, name=""): - if degree == 1: - con = self.addLConstr(lhs, sense, rhs, name) - elif degree == 2: - con = self.addQConstr(lhs, sense, rhs, name) - else: - raise DegreeError('GurobiModel.addConstr: Unsupported degree: %s' % degree) - return con - - @SolverFactory.register('gurobi_direct', doc='Direct python interface to Gurobi') class GurobiDirect(DirectSolver): """A direct interface to Gurobi using gurobipy. @@ -409,7 +395,7 @@ def _init_env(self): else: # Ensure the (global) default env is started if not GurobiDirect._default_env_started: - m = GurobiModel() + m = gurobipy.Model() m.close() GurobiDirect._default_env_started = True @@ -419,9 +405,9 @@ def _create_model(self, model): self._solver_model.close() self._solver_model = ( - GurobiModel(model.name, env=self._env) + gurobipy.Model(model.name, env=self._env) if model.name is not None - else GurobiModel(env=self._env) + else gurobipy.Model(env=self._env) ) def close(self): @@ -504,6 +490,15 @@ def _set_instance(self, model, kwds={}): def _add_block(self, block): DirectOrPersistentSolver._add_block(self, block) + def _addConstr(self, degree, lhs, sense=None, rhs=None, name=""): + if degree == 1: + con = self._solver_model.addLConstr(lhs, sense, rhs, name) + elif degree == 2: + con = self._solver_model.addQConstr(lhs, sense, rhs, name) + else: + raise DegreeError('GurobiModel.addConstr: Unsupported degree: %s' % degree) + return con + def _add_constraint(self, con): if not con.active: return None @@ -534,7 +529,7 @@ def _add_constraint(self, con): ) if con.equality: - gurobipy_con = self._solver_model.addConstr( + gurobipy_con = self._addConstr( degree=degree, lhs=gurobi_expr, sense=gurobipy.GRB.EQUAL, @@ -547,7 +542,7 @@ def _add_constraint(self, con): ) self._range_constraints.add(con) elif con.has_lb(): - gurobipy_con = self._solver_model.addConstr( + gurobipy_con = self._addConstr( degree=degree, lhs=gurobi_expr, sense=gurobipy.GRB.GREATER_EQUAL, @@ -555,7 +550,7 @@ def _add_constraint(self, con): name=conname, ) elif con.has_ub(): - gurobipy_con = self._solver_model.addConstr( + gurobipy_con = self._addConstr( degree=degree, lhs=gurobi_expr, sense=gurobipy.GRB.LESS_EQUAL, @@ -650,7 +645,7 @@ def _set_objective(self, obj): else: raise ValueError('Objective sense is not recognized: {0}'.format(obj.sense)) - gurobi_expr, referenced_vars = self._get_expr_from_pyomo_expr( + gurobi_expr, referenced_vars, degree = self._get_expr_from_pyomo_expr( obj.expr, self._max_obj_degree ) From 5bfdcae1cd882e57721c2cfd90d21994551a355b Mon Sep 17 00:00:00 2001 From: Arnaud Baguet Date: Tue, 20 Aug 2024 06:44:08 -0400 Subject: [PATCH 4/5] fix unit tests after adding _addConstr --- pyomo/solvers/plugins/solvers/gurobi_direct.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/gurobi_direct.py b/pyomo/solvers/plugins/solvers/gurobi_direct.py index 1ed4c5e3505..9cd81ba8a55 100644 --- a/pyomo/solvers/plugins/solvers/gurobi_direct.py +++ b/pyomo/solvers/plugins/solvers/gurobi_direct.py @@ -491,12 +491,10 @@ def _add_block(self, block): DirectOrPersistentSolver._add_block(self, block) def _addConstr(self, degree, lhs, sense=None, rhs=None, name=""): - if degree == 1: - con = self._solver_model.addLConstr(lhs, sense, rhs, name) - elif degree == 2: + if degree == 2: con = self._solver_model.addQConstr(lhs, sense, rhs, name) else: - raise DegreeError('GurobiModel.addConstr: Unsupported degree: %s' % degree) + con = self._solver_model.addLConstr(lhs, sense, rhs, name) return con def _add_constraint(self, con): From 6dce762c86103aa868e50dd0b99ca3bcec370362 Mon Sep 17 00:00:00 2001 From: Arnaud Baguet Date: Tue, 20 Aug 2024 22:21:46 -0400 Subject: [PATCH 5/5] fix laxy constraint issue after changing _get_expr_from_pyomo_expr --- pyomo/solvers/plugins/solvers/gurobi_persistent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyomo/solvers/plugins/solvers/gurobi_persistent.py b/pyomo/solvers/plugins/solvers/gurobi_persistent.py index 94a2ac6b734..447d1de9b40 100644 --- a/pyomo/solvers/plugins/solvers/gurobi_persistent.py +++ b/pyomo/solvers/plugins/solvers/gurobi_persistent.py @@ -578,7 +578,7 @@ def cbCut(self, con): if is_fixed(con.body): raise ValueError('cbCut expected a non-trivial constraint') - gurobi_expr, referenced_vars = self._get_expr_from_pyomo_expr( + gurobi_expr, referenced_vars, degree = self._get_expr_from_pyomo_expr( con.body, self._max_constraint_degree ) @@ -656,7 +656,7 @@ def cbLazy(self, con): if is_fixed(con.body): raise ValueError('cbLazy expected a non-trivial constraint') - gurobi_expr, referenced_vars = self._get_expr_from_pyomo_expr( + gurobi_expr, referenced_vars, degree = self._get_expr_from_pyomo_expr( con.body, self._max_constraint_degree )