-
Notifications
You must be signed in to change notification settings - Fork 1k
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
solve problem by multiple solvers #2450
base: master
Are you sure you want to change the base?
Conversation
cvxpy/problems/problem.py
Outdated
@@ -416,6 +416,50 @@ def compilation_time(self) -> float | None: | |||
""" | |||
return self._compilation_time | |||
|
|||
def solve_multiple_solvers(self, solvers:list[tuple[str, dict] | tuple[str] | str] = None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice functionality! I don't think we need to support an argument of None, since anyone calling this function should be giving some list of solvers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review!
I'll remove the support for None.
What about an empty list? Currently, the implementation uses the solve method without arguments in this case.
Do you think I should keep it like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say that an empty list should raise a ValueError.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Should the other errors related to input validation (such as inner input types) also raise ValueError
?
Currently, I've used ParameterError
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, these are all ValueError. Let me sync a bit with the other devs though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, please let me know if any further changes are needed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I'm positive on this but not a huge fan of the current public API. I left my suggestions. Aditionaly, I don't like solve_multiple_solvers
, could we call the method solve_via_chain
, solve_with_fallback
, try_solve
, or try_solve_till_success
? I think Stephen Boyd often uses the term solver chain for this feature; I can ask him next week.
Apply suggestions from code review Co-authored-by: Parth Nobel <parthnobel@berkeley.edu>
Co-authored-by: Parth Nobel <parthnobel@berkeley.edu>
@PTNobel thank you for all your suggestions!
That would be great, thanks! |
Stephen said we should call it a "solver path" in the documentation; he also suggested making it a keyword argument to |
I’m not sure about “path” as a keyword argument. I’d be in favor of
“solver_path” or “solver_priority” for keyword arguments to prob.solve.
…On Mon, Jun 3, 2024 at 7:20 PM Parth Nobel ***@***.***> wrote:
Stephen said we should call it a "solver path" in the documentation; he
also suggested making it a keyword argument to .solve instead of a new
public function (maybe .solve(path=[...]). I'm wondering if maybe we
could just specifialize on if the input is a string or a list to make .solve(solver=[cp.SCS,
cp.CLARABEL]) the API. Thoughts on that @SteveDiamond
<https://github.com/SteveDiamond> @phschiele
<https://github.com/phschiele> ?
—
Reply to this email directly, view it on GitHub
<#2450 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACRLIFCZAUD7QOITPGPDR7TZFT24BAVCNFSM6AAAAABH7TE5E2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNBWGI4DIMJZGQ>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Fair! I don't like solver_priority since we fallback to the other solvers instead of giving up, so I think |
What if both "solver" and "solver_path" are given? |
I think that should raise a runtime error. |
That should raise a ValueError
…On Wed, Jun 5, 2024 at 2:39 AM Parth Nobel ***@***.***> wrote:
I think that should raise a runtime error.
—
Reply to this email directly, view it on GitHub
<#2450 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACRLIFC22NDBTSI3NOFMKCDZF2XCHAVCNFSM6AAAAABH7TE5E2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNBYHE4TMNBUGU>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
How would this work when you have solver specific arguments to the solve method? |
Could be |
I've made some changes according to your suggestions. Does this meet your expectations? |
I like this PR with Oriya's changes. Since this is a change to the public API, let's get maintainer consensus on this proposal before writing the new docs and merging. |
""" | ||
|
||
if not solvers: | ||
raise ValueError("Solvers list must contain at least one solver.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError("Solvers list must contain at least one solver.") | |
raise ValueError("Solver path must contain at least one solver.") |
@@ -415,6 +415,58 @@ def compilation_time(self) -> float | None: | |||
last time it was compiled. | |||
""" | |||
return self._compilation_time | |||
|
|||
def _solve_solver_path(self, solve_func, solvers:list[tuple[str, dict] | tuple[str] | str], | |||
*args, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*args, **kwargs): | |
args, kwargs): |
if solver is not None: | ||
raise ValueError( | ||
"Cannot specify both 'solver' and 'solver_path'. Please choose one.") | ||
return self._solve_solver_path(solve_func,solver_path,*args,**kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return self._solve_solver_path(solve_func,solver_path,*args,**kwargs) | |
return self._solve_solver_path(solve_func,solver_path, args, kwargs) |
solution = solve_func( | ||
self, *args, solver=solver_name, **solver_kwargs, **kwargs) | ||
else: | ||
raise ValueError("Solver tuple input must be (str, dict) or (str)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError("Solver tuple input must be (str, dict) or (str)") | |
raise ValueError("Solver path entry must be str, tuple[str] or tuple[str, dict[str, Any]]") |
raise ValueError("Solver tuple input must be (str, dict) or (str)") | ||
else: | ||
raise ValueError("Solver input must be one of the following:\ | ||
(str, dict) tuple, (str) tuple, or str.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you define a constant string somewhere and use the same message on line 461 and 463?
cp.sum_squares(cp.matmul(A, cp.Variable(40)) - b))).solve( | ||
solver_path=solvers) | ||
|
||
## solver_path ans solver arguments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
## solver_path ans solver arguments | |
## Specify both solver_path and solver as arguments |
Description
As @erelsgl suggested in discussion #1522,
in some problems, some solvers may be better than others, but they might also fail with a SolverError.
Therefore, we've added a new method that allows sending a list of solvers rather than just one.
This function tries them in the order they are provided, and return the first solution for which no SolverError is raised.
Issue link: #1529
Type of change
Contribution checklist