Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add check for solver installation when initializing solver class instances #377

Merged
merged 6 commits into from
Nov 15, 2024

Conversation

daniel-rdt
Copy link
Contributor

@daniel-rdt daniel-rdt commented Nov 14, 2024

This PR adds a check to the initialization of a solver instance to check whether the solver package is installed or not. An ImportError is raised if the necessary package is not installed.
fyi @FabianHofmann @lkstrp

Copy link
Member

@lkstrp lkstrp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not just use available_solvers instead of checking again?

linopy/linopy/solvers.py

Lines 50 to 115 in acac414

available_solvers = []
which = "where" if os.name == "nt" else "which"
# the first available solver will be the default solver
with contextlib.suppress(ModuleNotFoundError):
import gurobipy
available_solvers.append("gurobi")
with contextlib.suppress(ModuleNotFoundError):
_new_highspy_mps_layout = None
import highspy
available_solvers.append("highs")
from importlib.metadata import version
if version("highspy") < "1.7.1":
_new_highspy_mps_layout = False
else:
_new_highspy_mps_layout = True
if sub.run([which, "glpsol"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode == 0:
available_solvers.append("glpk")
if sub.run([which, "cbc"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode == 0:
available_solvers.append("cbc")
with contextlib.suppress(ModuleNotFoundError):
import pyscipopt as scip
available_solvers.append("scip")
with contextlib.suppress(ModuleNotFoundError):
import cplex
available_solvers.append("cplex")
with contextlib.suppress(ModuleNotFoundError):
import xpress
available_solvers.append("xpress")
with contextlib.suppress(ModuleNotFoundError):
import mosek
with contextlib.suppress(mosek.Error):
with mosek.Env() as m:
t = m.Task()
t.optimize()
m.checkinall()
available_solvers.append("mosek")
with contextlib.suppress(ModuleNotFoundError):
import mindoptpy
available_solvers.append("mindopt")
with contextlib.suppress(ModuleNotFoundError):
import coptpy
with contextlib.suppress(coptpy.CoptError):
coptpy.Envr()
available_solvers.append("copt")

@daniel-rdt
Copy link
Contributor Author

Can we not just use available_solvers instead of checking again?

Hm, good point. Then we could just define the function in the abstract class to check if solver_name is in available_solvers and raise the error if not?

@lkstrp
Copy link
Member

lkstrp commented Nov 15, 2024

Yes, we wouldn't even need a extra method, just checking

if self.solver_name.value not in available_solvers:
    raise ImportError('..')

in the abc init would be enough.

And for each solver we could use the created enum:

self.solver_name = SolverName.xx

@daniel-rdt
Copy link
Contributor Author

daniel-rdt commented Nov 15, 2024

We could even not specify the name but just one abstract function to get the name from the class __name__ via the SolverName enum:

def get_name_str(self):
    return SolverName[self.__class__.__name__].value

I made the changes

linopy/solvers.py Outdated Show resolved Hide resolved
linopy/solvers.py Outdated Show resolved Hide resolved
linopy/solvers.py Outdated Show resolved Hide resolved
@lkstrp lkstrp merged commit 0b2a208 into PyPSA:master Nov 15, 2024
17 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants