Skip to content

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

Co-authored-by: Lukas Trippe <lkstrp@pm.me>
@lkstrp lkstrp merged commit 0b2a208 into PyPSA:master Nov 15, 2024
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