-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Allow callables as optimizers in VQE and QAOA #7191
Conversation
Pull Request Test Coverage Report for Build 1986651072
💛 - Coveralls |
Marking this as |
I think |
Yep the documentation says you're right... How would the abstract variant look like? Otherwise we can maybe just add the additional requirement 😄 |
As long as you're happy having everything derive from class OptimizerHandle(abc.ABC):
@abc.abstractmethod
def __call__(self, ...) -> ...: ... and just continue to have the classes you want derive from it. |
The goal is to pass in functions from SciPy and user-defined ones, so without inheriting from an interface. The other solution, if we want to avoid |
I mean, you can technically fulfill the type hinting by just setting it to QubitSpecifier = Union[
Qubit,
QuantumRegister,
int,
slice,
Sequence[Union[Qubit, int]],
] and re-uses that in places. |
Hmm yeah but at least it'll make the code more readable and users should get from the docs what function they can pass in. Let's go with the long type hint then! |
I know all the code is in VQE but maybe adding a unit test to test_qaoa.py too ? Otherwise it looks good to me. |
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'd agree that you should probably duplicate your tests into QAOA as well, just to be sure.
OBJECTIVE = Callable[[np.ndarray], float] | ||
GRADIENT = Callable[[np.ndarray], np.ndarray] | ||
RESULT = Union[scipy.optimize.OptimizeResult, OptimizerResult] | ||
BOUNDS = List[Tuple[float, float]] | ||
|
||
MINIMIZER = Callable[ | ||
[ | ||
OBJECTIVE, # the objective function to minimize (the energy in the case of the VQE) | ||
np.ndarray, # the initial point for the optimization | ||
Optional[GRADIENT], # the gradient of the objective function | ||
Optional[BOUNDS], # parameters bounds for the optimization | ||
], | ||
RESULT, # a result object (either SciPy's or Qiskit's) | ||
] | ||
|
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.
Is this type hint actually correct for any SciPy minimiser? It seems to imply that the first four arguments are positional, but the first four positional arguments of their minimisers are (objective, x0, args, jac).
In an ideal world, I think we'd put this in __init__.py
, and write some documentation in the docstring about the types. It can have a Sphinx cross-ref (.. _algorithms_minimum_eigensolvers_minimizer:
, then you reference with :ref:
algorithms_minimum_eigensolvers_minimizer`), then the various class docstrings could all link to it. That said, I don't think you need to worry much about it right now.
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.
In fact the callable must have the named arguments fun, x0, jac, bounds
but I didn't quite know how to put that in a type hint using only what's available now 🤔 I updated the class docs to highlight this
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.
how about using Callback Protocol? PEP544
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.
We tried that but it's only supported from Python 3.8 onwards, see the discussion above: #7191 (comment)
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.
Protocol is back ported by typing-extensions. https://pypi.org/project/typing-extensions/ so you can use it.
(I'm sorry I overlooked...)
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.
Yeah but that would create an additional dependency to a new package, so we didn't add it (yet) 😄
result = OptimizerResult() | ||
result.x = # optimal parameters | ||
result.fun = # optimal function value |
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.
Kind of weird that you don't construct the whole class in one go at initialisation time, but I gave up that fight in Python long ago.
|
@Cryoris Where are we with this. I looked it up since I recalled this level of support but see its not there yet. In the external Slack applications channel someone was asking about passing other arguments into BOBYQA that internally on the skquant minimize is done via kwargs but that cannot be passed into the BOBYQA "wrapper" we have here. This would have allowed them to do it using the skquant minimize more directly. For ref the thread is here https://qiskit.slack.com/archives/CB6C24TPB/p1645196828099929 |
Yes @ikkoham, it's principally possible to go through the from qiskit.algorithms.optimizers import SciPyOptimizer
def my_optimizer(fun, x0, args, **kwargs):
return # some scipy.optimize.OptimizeResult()
optimizer = SciPyOptimizer(method=my_optimizer)
vqe = VQE(optimizer=optimizer) However with this PR we'd simplify this process by not having to go through this extra object. This PR would probably make using the from functools import partial
from scipy import minimize
vqe = VQE(optimizer=partial(minimize, method="L-BFGS-B or your method of choice")) This PR is part of the redesign accoring to the design doc we discussed a while back, you can check it here: #6381. If you any concerns with using callables directly I'm happy to discuss it! |
@Cryoris Thanks. I understand why you want to add this and I agree with you. This is useful and right direction. |
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.
OK. I can update Callback Protocol after merged.
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 resolved the merge conflict. Approve again.
* allow callables as optimizers in VQE * Missing quote * fix lint * don't use typing.Protocol * comments from review * add qaoa test * lint Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com> Co-authored-by: Ikko Hamamura <ikkoham@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* allow callables as optimizers in VQE * Missing quote * fix lint * don't use typing.Protocol * comments from review * add qaoa test * lint Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com> Co-authored-by: Ikko Hamamura <ikkoham@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Summary
Closes #6383.
Details and comments
Allow callables with the following signature as optimizers in the VQE and QAOA:
where the result can be either of
qiskit.algorithms.optimizers.OptimizerResult
orscipy.optimize.OptimizeResult
.This also allows to directly pass SciPy's optimizers into these algorithms, e.g. as