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

Refactor OSQP interface into a generic matrix solver #255

Merged
merged 10 commits into from
Sep 14, 2023

Conversation

cdiener
Copy link
Member

@cdiener cdiener commented Sep 1, 2023

  • description of feature/fix
  • tests added/passed
  • add an entry to the next release

This is a proposed refactor of the OSQP interface into a generic solver interface for backends that assume immutable problems in (sparse) standard form. This should make it much easier to port solvers to optlang and would for instance be useful to create compatibility with PULP or CVXPY or any other solver that is based on a matrix formulation of the problem. This is also supposed to set the stage for a future HIGHS/OSQP hybrid solver I would like to add.

The interface is still somehwat performant by creating a fast intermediate layer that can be translated into sparse matrices quickly.

@Midnighter
Copy link
Member

I'll try to go through this soon, but my upcoming week is super full. I would also love to get the CBC interface fixed. Having an open source MILP solver available will add a lot of value (to non-academics like myself).

@cdiener
Copy link
Member Author

cdiener commented Sep 2, 2023

Yeah sounds good. Feel free to checkout the linked repo with the hybrid solver then. This is a working LP/MIP/QP solver that works for large problems.

Copy link
Member

@Midnighter Midnighter left a comment

Choose a reason for hiding this comment

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

I did a high-level review. In general, this looks like a good idea to me. Some of the code here still uses syntax that was needed to support Python 2. That could be updated. I also left a few more specific suggestions.

@six.add_metaclass(inheritdocstring)
class Variable(interface.Variable):
def __init__(self, name, *args, **kwargs):
super(Variable, self).__init__(name, **kwargs)
Copy link
Member

Choose a reason for hiding this comment

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

Ideally use keyword args only

Suggested change
super(Variable, self).__init__(name, **kwargs)
super(Variable, self).__init__(name=name, **kwargs)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

_TYPES = ("continuous", "binary", "integer")


class MatrixProblem(object):
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to mark this as an abstract class?

Suggested change
class MatrixProblem(object):
class MatrixProblem(abc.ABC):

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

"""
raise NotImplementedError("This needs to be overwritten by the child class.")

def clean(self):
Copy link
Member

Choose a reason for hiding this comment

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

Not sure that I like the name clean. What about prune or reduce?

Copy link
Member Author

Choose a reason for hiding this comment

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

I like prune.

src/optlang/matrix_interface.py Show resolved Hide resolved
src/optlang/matrix_interface.py Show resolved Hide resolved
src/optlang/matrix_interface.py Show resolved Hide resolved
but can also be converted to a matrix formulation quickly.
"""

def __init__(self):
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def __init__(self):
def __init__(self, **kwargs):
super().__init__(**kwargs)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

src/optlang/matrix_interface.py Show resolved Hide resolved
@cdiener
Copy link
Member Author

cdiener commented Sep 11, 2023

Okay, should have addressed everything. I also removed all the six usage.

Copy link
Member

@Midnighter Midnighter left a comment

Choose a reason for hiding this comment

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

I like the way this is coded and I'm glad to be rid of the use of six. Most of my comments are suggestions only. In principle, it should be possible to upgrade all super calls to empty arguments, as we no longer support 2.7. It can sometimes be tricky with properties, so I'm not sure without trying. I do think it is safer to only use keyword arguments in inheritance.

I did not comment on all places where super is used. Please do a search on the code if you want to change this.

src/optlang/matrix_interface.py Outdated Show resolved Hide resolved
src/optlang/matrix_interface.py Outdated Show resolved Hide resolved
src/optlang/matrix_interface.py Show resolved Hide resolved
src/optlang/matrix_interface.py Show resolved Hide resolved
src/optlang/matrix_interface.py Outdated Show resolved Hide resolved
src/optlang/matrix_interface.py Outdated Show resolved Hide resolved
src/optlang/matrix_interface.py Outdated Show resolved Hide resolved
@cdiener
Copy link
Member Author

cdiener commented Sep 13, 2023

Okay should all be adressed now. Some of the super calls needed to stay as is because of the properties like you already suspected. I fixed all the others.

Copy link
Member

@Midnighter Midnighter left a comment

Choose a reason for hiding this comment

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

Fantastic 🚀

@Midnighter
Copy link
Member

Midnighter commented Sep 14, 2023

I just noticed that even though the classifiers list Python 3.7 as the minimum version, the actual check is done as:

python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*

Those should be consistent. I suggest going with python_requires = >=3.8.

I will then update the conda-forge feedstock accordingly.

@cdiener
Copy link
Member Author

cdiener commented Sep 14, 2023

Done, I also added Python 3.11 to the CI because that was missing as well.

@cdiener cdiener merged commit ea11218 into opencobra:master Sep 14, 2023
13 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