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

Fix bounds parsing in Scipy optimizers and warn when unsupported #155

Merged
merged 46 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
bc4c98c
Avoid multiply defined bounds options in optimizer
edoaltamura Feb 13, 2024
85e16b6
Update change date
edoaltamura Feb 13, 2024
6604837
Add warnings for parsing unsupported bounds
edoaltamura Feb 14, 2024
77abbcb
Add algorithms and optimizer specific warnings
edoaltamura Feb 14, 2024
0163c53
Fix missed import
edoaltamura Feb 14, 2024
8167209
Merge branch 'main' into main
edoaltamura Feb 14, 2024
343ae7c
Apply style patches
edoaltamura Feb 15, 2024
d1db2a3
Add unit tests and introduce _bounds attribute
edoaltamura Feb 19, 2024
83df2c1
Formatting and final patches to tests
edoaltamura Feb 19, 2024
f4159ad
Merge branch 'qiskit-community:main' into main
edoaltamura Feb 20, 2024
7215fcc
Merge branch 'main' into main
woodsp-ibm Feb 22, 2024
28c5f67
Bounds parsing forbidden in __init__ and allowed in minimize()
edoaltamura Feb 23, 2024
a217786
Merge remote-tracking branch 'origin/main'
edoaltamura Feb 23, 2024
6d057ec
Add bounds type hinting
edoaltamura Feb 24, 2024
cdfc487
Change copyright in tests
edoaltamura Feb 24, 2024
7c0bf6b
Remove scikit-quant dependency
edoaltamura Feb 24, 2024
a4f45ee
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Feb 24, 2024
18b0f77
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Feb 27, 2024
140fce6
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Feb 27, 2024
2fbd23a
Remove internal implementation checks in test_optimizers.py
edoaltamura Feb 27, 2024
d3eb8f2
Merge branch 'qiskit-community:main' into main
edoaltamura Feb 29, 2024
30c4b72
Avoid multiply defined bounds options in optimizer
edoaltamura Feb 13, 2024
06240b8
Update change date
edoaltamura Feb 13, 2024
be6dd75
Add warnings for parsing unsupported bounds
edoaltamura Feb 14, 2024
28d1493
Add algorithms and optimizer specific warnings
edoaltamura Feb 14, 2024
8446806
Fix missed import
edoaltamura Feb 14, 2024
f47d31a
Apply style patches
edoaltamura Feb 15, 2024
d7a0986
Add unit tests and introduce _bounds attribute
edoaltamura Feb 19, 2024
adfb264
Formatting and final patches to tests
edoaltamura Feb 19, 2024
cd7a34e
Bounds parsing forbidden in __init__ and allowed in minimize()
edoaltamura Feb 23, 2024
960cd7c
Add bounds type hinting
edoaltamura Feb 24, 2024
91ffeff
Change copyright in tests
edoaltamura Feb 24, 2024
ca0d277
Remove scikit-quant dependency
edoaltamura Feb 24, 2024
a7bbd21
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Feb 24, 2024
3611957
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Feb 27, 2024
08284c9
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Feb 27, 2024
b9a32dc
Remove internal implementation checks in test_optimizers.py
edoaltamura Feb 27, 2024
7a5fc0c
Remove loose incompatible-bounds logic
edoaltamura Feb 29, 2024
f20fe98
Merge remote-tracking branch 'origin/main'
edoaltamura Feb 29, 2024
a467036
Remove loose incompatible-bounds logic
edoaltamura Feb 29, 2024
a8d52e0
Update qiskit_algorithms/optimizers/scipy_optimizer.py
edoaltamura Mar 7, 2024
0f602e7
Remove redundant `_bounds` attributes
edoaltamura Mar 7, 2024
1472f4f
Add release note
edoaltamura Mar 7, 2024
f4d76fa
Remove _bounds attr from tests, add `list[tuple[None, None]]` as poss…
edoaltamura Mar 13, 2024
997f38b
Remove _bounds attr from tests
edoaltamura Mar 13, 2024
602ab8c
Merge branch 'main' into main
woodsp-ibm Apr 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions qiskit_algorithms/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2017, 2023.
# (C) Copyright IBM 2017, 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand All @@ -10,7 +10,7 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Exception for errors raised by Algorithms module."""
"""Exception and warnings for errors raised by Algorithms module."""

from qiskit.exceptions import QiskitError

Expand All @@ -19,3 +19,22 @@ class AlgorithmError(QiskitError):
"""For Algorithm specific errors."""

pass


class QiskitAlgorithmsWarning(UserWarning):
"""Base class for warnings raised by Qiskit Algorithms."""

def __init__(self, *message):
"""Set the error message."""
super().__init__(" ".join(message))
self.message = " ".join(message)

def __str__(self):
"""Return the message."""
return repr(self.message)


class QiskitAlgorithmsOptimizersWarning(QiskitAlgorithmsWarning):
"""For Algorithm specific warnings."""

pass
18 changes: 16 additions & 2 deletions qiskit_algorithms/optimizers/scipy_optimizer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2018, 2023.
# (C) Copyright IBM 2018, 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand Down Expand Up @@ -76,6 +76,17 @@ def __init__(
self._max_evals_grouped = max_evals_grouped
self._kwargs = kwargs

if "bounds" in self._kwargs:
raise RuntimeError(
"Optimizer bounds should be passed to SciPyOptimizer.minimize() and is not "
"supported in SciPyOptimizer constructor kwargs."
)
if "bounds" in self._options:
raise RuntimeError(
"Optimizer bounds should be passed to SciPyOptimizer.minimize() and not as "
"options."
)

def get_support_level(self):
"""Return support level dictionary"""
return {
Expand Down Expand Up @@ -116,9 +127,12 @@ def minimize(
jac: Callable[[POINT], POINT] | None = None,
bounds: list[tuple[float, float]] | None = None,
) -> OptimizerResult:
# Remove ignored parameters to suppress the warning of scipy.optimize.minimize

# Remove ignored bounds to suppress the warning of scipy.optimize.minimize
if self.is_bounds_ignored:
bounds = None

# Remove ignored gradient to suppress the warning of scipy.optimize.minimize
if self.is_gradient_ignored:
jac = None

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Resolved the issue with multiply-defined Scipy bounds in Optimizers. In line with Scipy, now only the ``minimize()``
method supports the ``bounds`` keyword. An error is raised when trying to pass ``bounds`` in the Optimizer constructor
via ``kwargs`` or ``options``.
37 changes: 35 additions & 2 deletions test/optimizers/test_optimizers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2018, 2023.
# (C) Copyright IBM 2018, 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand Down Expand Up @@ -149,7 +149,7 @@ def test_gsls(self):
max_eval=10000,
min_step_size=1.0e-12,
)
x_0 = [1.3, 0.7, 0.8, 1.9, 1.2]
x_0 = np.asarray([1.3, 0.7, 0.8, 1.9, 1.2])

algorithm_globals.random_seed = 1
res = optimizer.minimize(rosen, x_0)
Expand Down Expand Up @@ -183,6 +183,39 @@ def callback(x):
self.run_optimizer(optimizer, max_nfev=10000)
self.assertTrue(values) # Check the list is nonempty.

def test_scipy_optimizer_parse_bounds(self):
"""
Test the parsing of bounds in SciPyOptimizer.minimize method. Verifies that the bounds are
correctly parsed and set within the optimizer object.

Raises:
AssertionError: If any of the assertions fail.
AssertionError: If a TypeError is raised unexpectedly while parsing bounds.

"""
try:
# Initialize SciPyOptimizer instance with SLSQP method
optimizer = SciPyOptimizer("SLSQP")

# Call minimize method with a simple lambda function and bounds
optimizer.minimize(lambda x: -x, 1.0, bounds=[(0.0, 1.0)])

# Assert that "bounds" is not present in optimizer options and kwargs
self.assertFalse("bounds" in optimizer._options)
self.assertFalse("bounds" in optimizer._kwargs)

except TypeError:
# This would give: https://github.com/qiskit-community/qiskit-machine-learning/issues/570
self.fail(
"TypeError was raised unexpectedly when parsing bounds in SciPyOptimizer.minimize(...)."
)

# Finally, expect exceptions if bounds are parsed incorrectly, i.e. differently than as in Scipy
with self.assertRaises(RuntimeError):
_ = SciPyOptimizer("SLSQP", bounds=[(0.0, 1.0)])
with self.assertRaises(RuntimeError):
_ = SciPyOptimizer("SLSQP", options={"bounds": [(0.0, 1.0)]})

# ESCH and ISRES do not do well with rosen
@data(
(CRS, True),
Expand Down