Skip to content

Commit

Permalink
better catch
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Dec 19, 2024
1 parent a5f5737 commit 62a0fe8
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/ilpy/_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import TYPE_CHECKING, Any, Callable

from .expressions import Expression
from .solver_backends import Preference, SolverBackend, create_backend
from .solver_backends import Preference, SolverBackend, create_solver_backend

if TYPE_CHECKING:
from collections.abc import Iterator, Mapping, Sequence
Expand Down Expand Up @@ -50,7 +50,7 @@ def __init__(
preference: Preference = Preference.Any,
) -> None:
vtpes: dict[int, VariableType] = dict(variable_types) if variable_types else {}
self._backend: SolverBackend = create_backend(preference)
self._backend: SolverBackend = create_solver_backend(preference)
self._num_variables = num_variables
self._backend.initialize(num_variables, default_variable_type, vtpes)

Expand Down
30 changes: 20 additions & 10 deletions src/ilpy/solver_backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from ._base import SolverBackend

__all__ = ["Preference", "SolverBackend", "create_backend"]
__all__ = ["Preference", "SolverBackend", "create_solver_backend"]


class Preference(IntEnum):
Expand All @@ -15,20 +15,30 @@ class Preference(IntEnum):
Gurobi = auto()


def create_backend(preference: Preference) -> SolverBackend:
def create_solver_backend(preference: Preference | str) -> SolverBackend:
"""Create a solver backend based on the preference."""
if not isinstance(preference, Preference):
preference = Preference[str(preference).title()]

Check warning on line 21 in src/ilpy/solver_backends/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/ilpy/solver_backends/__init__.py#L21

Added line #L21 was not covered by tests

to_try = []
if preference in (Preference.Any, Preference.Gurobi):
to_try.append(("_gurobi", "GurobiSolver"))
elif preference in (Preference.Any, Preference.Scip):
if preference in (Preference.Any, Preference.Scip):
to_try.append(("_scip", "ScipSolver"))

errors: list[tuple[str, BaseException]] = []
for modname, clsname in to_try:
import_mod = f"ilpy.solver_backends.{modname}"
try:
mod = __import__(f"ilpy.solver_backends.{modname}", fromlist=[clsname])
except ImportError:
continue
else:
return getattr(mod, clsname)() # type: ignore [no-any-return]

raise ValueError(f"Unknown preference: {preference}") # pragma: no cover
mod = __import__(import_mod, fromlist=[clsname])
cls = getattr(mod, clsname)
backend = cls()
assert isinstance(backend, SolverBackend)
return backend
except Exception as e: # pragma: no cover
errors.append((f"{import_mod}::{clsname}", e))

raise RuntimeError( # pragma: no cover
"Failed to create a solver backend. Tried:\n\n"
+ "\n".join(f"- {name}:\n {e}" for name, e in errors)
)
11 changes: 9 additions & 2 deletions src/ilpy/solver_backends/_gurobi.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,23 @@


class GurobiSolver(SolverBackend):
def __init__(self):
# we put this in __init__ instead of initialize so that it will raise an
# exception inside of create_backend if the module is imported but the
# license is not available
self._model = gb.Model()

def initialize(
self,
num_variables: int,
default_variable_type: VariableType,
variable_types: Mapping[int, VariableType], # TODO
) -> None:
self._model = model = gb.Model()
# ilpy uses infinite bounds by default, but Gurobi uses 0 to infinity by default
vtype = VTYPE_MAP[default_variable_type]
self._vars = model.addVars(num_variables, lb=-gb.GRB.INFINITY, vtype=vtype)
self._vars = self._model.addVars(

Check warning on line 64 in src/ilpy/solver_backends/_gurobi.py

View check run for this annotation

Codecov / codecov/patch

src/ilpy/solver_backends/_gurobi.py#L63-L64

Added lines #L63 - L64 were not covered by tests
num_variables, lb=-gb.GRB.INFINITY, vtype=vtype
)
self._event_callback: Callable[[Mapping[str, float | str]], None] | None = None

Check warning on line 67 in src/ilpy/solver_backends/_gurobi.py

View check run for this annotation

Codecov / codecov/patch

src/ilpy/solver_backends/_gurobi.py#L67

Added line #L67 was not covered by tests

# 2 = non-convex quadratic problems are solved by means of translating them
Expand Down
4 changes: 3 additions & 1 deletion tests/test_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
# (this is the best way I could find to determine this so far)
gu_marks = []
try:
from ilpy.solver_backends import create_solver_backend

create_solver_backend(ilpy.Preference.Gurobi)
import gurobipy as gb

ilpy.Solver(0, ilpy.VariableType.Binary, None, ilpy.Preference.Gurobi)
HAVE_GUROBI = True
except Exception as e:
gu_marks.append(pytest.mark.xfail(reason=f"Gurobi error: {e}"))
Expand Down

0 comments on commit 62a0fe8

Please sign in to comment.