Repository: Qiskit/qiskit-terra (python)

Issue:
Bug using SNOBFIT in combination with UCCSD (VQE) / misleading function signature of optimizer SNOBFIT
When running a VQE algorithm with ansatz UCCSD the following error message shows up:
```
[...]
 File "C:\Users\poc\Anaconda3\envs\qiskit\lib\site-packages\qiskit_nature\algorithms\pes_samplers\bopes_sampler.py", line 175, in sample
    self._raw_results = self._run_points(points)
  File "C:\Users\poc\Anaconda3\envs\qiskit\lib\site-packages\qiskit_nature\algorithms\pes_samplers\bopes_sampler.py", line 201, in _run_points
    raw_result = self._run_single_point(point)  # dict of results
  File "C:\Users\poc\Anaconda3\envs\qiskit\lib\site-packages\qiskit_nature\algorithms\pes_samplers\bopes_sampler.py", line 259, in _run_single_point
    result = self._state_solver.solve(self._problem, aux_ops_current_step)
  File "C:\Users\poc\Anaconda3\envs\qiskit\lib\site-packages\qiskit_nature\algorithms\ground_state_solvers\ground_state_eigensolver.py", line 91, in solve
    raw_mes_result = self._solver.compute_minimum_eigenvalue(main_operator, aux_ops)  # type: ignore
  File "C:\Users\poc\Anaconda3\envs\qiskit\lib\site-packages\qiskit\algorithms\minimum_eigen_solvers\vqe.py", line 530, in compute_minimum_eigenvalue
    opt_result = self.optimizer.minimize(
  File "C:\Users\poc\Anaconda3\envs\qiskit\lib\site-packages\qiskit\algorithms\optimizers\snobfit.py", line 96, in minimize
    if abs(theta) > bounds[idx][0]:
TypeError: '>' not supported between instances of 'float' and 'NoneType'
```

In case of ansatz `EfficientSU2` the code runs fine, only with `UCCSD` I get the error.

I tracked down the error to be caused by missing parameter bounds. The function [signature](https://github.com/Qiskit/qiskit-terra/blob/cbb64ed266b55525738de20a4e43419d5fef6e32/qiskit/algorithms/optimizers/snobfit.py#L82) of the optimizer's `minimize` function (``) suggests that `None` is a valid value. But the code never handles None-type input (neither `None` nor the nested list/tuple with `None` values).

So, I propose one of the following changes:
- Change the signature of the `minimize` method (still not easy to read for a user)
- Catch the `None`s in the input bounds and add a more verbose error message that optimizer SNOBFIT requires parameter bounds
- Artificially add bounds for the optimizer. Basically the parameter can only be varied from 0 to 2pi so one could catch the `None` input and change it to these bounds. Though I'm not aware of the side effects this approach might have... Here it might be useful to ask also someone from qiskit nature whether it could be resolved within the UCCSD ansatz (though it would not solve the initial problem with the misleading signature/missing error message).

Any fixes (or suggestions therefore) are highly appreciated.


Pull request description:
Raise error for missing bounds in optimizer SNOBFIT
<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [ ] I have added the tests to cover my changes.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the CONTRIBUTING document.
-->

### Summary

Raise error for invalid `None`s in bounds (i.e. missing bounds) of optimizer SNOBFIT.
Closes #8580 

### Details and comments

Function signature is misleading, allowing None for bounds. The resulting error is non-intuitive. So, this PR adds raising a more concise error message. This includes also `None` values within the bounds list (can happen e.g. with ansatz UCCSD).

Patch:
diff --git a/qiskit/algorithms/optimizers/snobfit.py b/qiskit/algorithms/optimizers/snobfit.py
index f1bd12faf..f74d8ca85 100644
--- a/qiskit/algorithms/optimizers/snobfit.py
+++ b/qiskit/algorithms/optimizers/snobfit.py
@@ -84,6 +84,9 @@ class SNOBFIT(Optimizer):
         import skquant.opt as skq
         from SQSnobFit import optset
 
+        if bounds is None or any(None in bound_tuple for bound_tuple in bounds):
+            raise ValueError("Optimizer SNOBFIT requires bounds for all parameters.")
+
         snobfit_settings = {
             "maxmp": self._maxmp,
             "maxfail": self._maxfail,
diff --git a/releasenotes/notes/improve-error-message-snobfit-missing-bounds-748943a87e682d82.yaml b/releasenotes/notes/improve-error-message-snobfit-missing-bounds-748943a87e682d82.yaml
new file mode 100644
index 000000000..da40ee94a
--- /dev/null
+++ b/releasenotes/notes/improve-error-message-snobfit-missing-bounds-748943a87e682d82.yaml
@@ -0,0 +1,4 @@
+---
+fixes:
+  - |
+    Catch error of missing bounds for SNOBFIT optimizer (raising error with clear error message). Arises e.g. when ansatz `UCC` is used in combination with SNOBFIT. Refer to `#8580 <https://github.com/Qiskit/qiskit-terra/issues/8580>` for more details.


Test patch:
diff --git a/test/python/algorithms/optimizers/test_optimizers_scikitquant.py b/test/python/algorithms/optimizers/test_optimizers_scikitquant.py
index b355232ba..63dd95c44 100644
--- a/test/python/algorithms/optimizers/test_optimizers_scikitquant.py
+++ b/test/python/algorithms/optimizers/test_optimizers_scikitquant.py
@@ -13,8 +13,10 @@
 """ Test of scikit-quant optimizers. """
 
 import unittest
-
 from test.python.algorithms import QiskitAlgorithmsTestCase
+
+from ddt import ddt, data, unpack
+
 from qiskit import BasicAer
 from qiskit.circuit.library import RealAmplitudes
 from qiskit.utils import QuantumInstance, algorithm_globals
@@ -24,6 +26,7 @@ from qiskit.algorithms import VQE
 from qiskit.algorithms.optimizers import BOBYQA, SNOBFIT, IMFIL
 
 
+@ddt
 class TestOptimizers(QiskitAlgorithmsTestCase):
     """Test scikit-quant optimizers."""
 
@@ -68,6 +71,21 @@ class TestOptimizers(QiskitAlgorithmsTestCase):
         except MissingOptionalLibraryError as ex:
             self.skipTest(str(ex))
 
+    @data((None,), ([(-1, 1), (None, None)],))
+    @unpack
+    def test_snobfit_missing_bounds(self, bounds):
+        """SNOBFIT optimizer test with missing bounds."""
+        try:
+            optimizer = SNOBFIT()
+            with self.assertRaises(ValueError):
+                optimizer.minimize(
+                    fun=lambda _: 1,  # using dummy function (never called)
+                    x0=[0.1, 0.1],  # dummy initial point
+                    bounds=bounds,
+                )
+        except MissingOptionalLibraryError as ex:
+            self.skipTest(str(ex))
+
     def test_imfil(self):
         """IMFIL test."""
         try: