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

Refactoring of linopy solvers to object oriented architecture #349

Merged
merged 21 commits into from
Oct 18, 2024

Conversation

daniel-rdt
Copy link
Contributor

@daniel-rdt daniel-rdt commented Sep 20, 2024

In this PR the solvers.py file is refactored to an object-oriented architecture. For this, a Solver superclass is introduced, as well as subclasses for each of the implemented solvers. A given problem can now be solved from a problem file without a linopy model using a specified solver. To solve a problem, for each Solver subclass the method solve_problem_file() is implemented. The implementation is based on the following logic suggested by @FabianHofmann in #198 (comment):

class Solver:
    def __init__(self, **kwargs):
        ....

    def solve_problem(self):
        raise NotImplementedError

class SolverA(Solver):
    ....
    def solve_problem(self, problem_fn):
        # Implementation of the solve method for SolverA
        ...
        return Result(status, solution)

class SolverB(Solver):
    ....
    def solve_problem(self, problem_fn):
        # Implementation of the solve method for SolverB
        ...
        return Result(status, solution)
....

To solve a problem directly from a problem file, for example using linopy's Gurobi solver interface:

import linopy
from pathlib import Path

problem_file = Path("path/to/problem.lp")

gurobi = linopy.solvers.Gurobi()
gurobi.solve_problem(problem_fn=problem_file)

For direct execution using a linopy model, the method set_direct_model used that adds the model to the Solver instance:

....
solver = solver_class()
solver.set_direct_model(model=model)
result = solver.solve_problem()

Two unit tests (test_solver_classes_from_problem_file and test_solver_classes_direct) were also added to test the functionality of the solver classes from a problem file and directly from a model. @finozzifa, any feedback on this is welcome.

@FabianHofmann
Copy link
Collaborator

Great work @daniel-rdt and really efficient! I try to find time to review this asap. In case I am not able to @lkstrp has to jump in.

Perhaps you try solving the type and test coverage warnings. I have the feeling that sense and io_api should not be mandatory arguments for initialization of the solver. The sense is given in the lp and mps files. So the current implementation would lead to ambiguity. Could you look into this?

@daniel-rdt
Copy link
Contributor Author

daniel-rdt commented Sep 24, 2024

I've addressed the type check issues (except the type check for the pandas groupby which was addressed by PR #352).

I've also adjusted the architecture of the direct solving from a linopy model vs solving from a problem file. The solver instance is not initialized with io_api and sense anymore. Rather the information is extracted from either the model or from the lp or mps problem file. I updated the code examples at the top of the PR to explain how it works.

As far as code coverage is concerned, I have not yet been able to get around to tackling that with adjusted unit tests unfortunately. Apart from this, @lkstrp, I think it's ready for your review.

@lkstrp lkstrp merged commit 03f3cc7 into PyPSA:master Oct 18, 2024
18 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.

3 participants