Repository: Qiskit/qiskit

Issue:
NLocal raises UnboundLocalError if reps==0
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: 0.15.2
- **Python version**: 3.7.9
- **Operating system**: macOS 10.15.7

### What is the current behavior?

`NLocal` raises `UnboundLocalError` if `reps==0`.
The error message does not look comprehensive.


### Steps to reproduce the problem

```python
from qiskit.circuit.library import NLocal
print(NLocal(1, reps=0))
```

output
```python
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-7-664a076be942> in <module>
----> 1 print(NLocal(1, reps=0))

~/envs/qopt/lib/python3.7/site-packages/qiskit/circuit/library/n_local/n_local.py in __str__(self)
    920                        'cswap', 'ccx', 'cu1', 'cu3', 'u1', 'u2', 'u3']
    921         return transpile(self, basis_gates=basis_gates,
--> 922                          optimization_level=0).draw(output='text').single_string()
    923 
    924 

~/envs/qopt/lib/python3.7/site-packages/qiskit/compiler/transpile.py in transpile(circuits, backend, basis_gates, coupling_map, backend_properties, initial_layout, layout_method, routing_method, translation_method, seed_transpiler, optimization_level, pass_manager, callback, output_name)
    214 
    215     # Transpile circuits in parallel
--> 216     circuits = parallel_map(_transpile_circuit, list(zip(circuits, transpile_args)))
    217 
    218     if len(circuits) == 1:

~/envs/qopt/lib/python3.7/site-packages/qiskit/tools/parallel.py in parallel_map(task, values, task_args, task_kwargs, num_processes)
    106         return []
    107     if len(values) == 1:
--> 108         return [task(values[0], *task_args, **task_kwargs)]
    109 
    110     Publisher().publish("terra.parallel.start", len(values))

~/envs/qopt/lib/python3.7/site-packages/qiskit/compiler/transpile.py in _transpile_circuit(circuit_config_tuple)
    315 
    316     result = pass_manager.run(circuit, callback=transpile_config['callback'],
--> 317                               output_name=transpile_config['output_name'])
    318 
    319     if transpile_config['faulty_qubits_map']:

~/envs/qopt/lib/python3.7/site-packages/qiskit/transpiler/passmanager.py in run(self, circuits, output_name, callback)
    212         """
    213         if isinstance(circuits, QuantumCircuit):
--> 214             return self._run_single_circuit(circuits, output_name, callback)
    215         elif len(circuits) == 1:
    216             return self._run_single_circuit(circuits[0], output_name, callback)

~/envs/qopt/lib/python3.7/site-packages/qiskit/transpiler/passmanager.py in _run_single_circuit(self, circuit, output_name, callback)
    275         if callback is None and self.callback:  # TODO to remove with __init__(callback)
    276             callback = self.callback
--> 277         result = running_passmanager.run(circuit, output_name=output_name, callback=callback)
    278         self.property_set = running_passmanager.property_set
    279         return result

~/envs/qopt/lib/python3.7/site-packages/qiskit/transpiler/runningpassmanager.py in run(self, circuit, output_name, callback)
    105         """
    106         name = circuit.name
--> 107         dag = circuit_to_dag(circuit)
    108         del circuit
    109 

~/envs/qopt/lib/python3.7/site-packages/qiskit/converters/circuit_to_dag.py in circuit_to_dag(circuit)
     55         dagcircuit.add_creg(register)
     56 
---> 57     for instruction, qargs, cargs in circuit.data:
     58         dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs)
     59     return dagcircuit

~/envs/qopt/lib/python3.7/site-packages/qiskit/circuit/library/blueprintcircuit.py in data(self)
     90     def data(self):
     91         if self._data is None:
---> 92             self._build()
     93         return super().data
     94 

~/envs/qopt/lib/python3.7/site-packages/qiskit/circuit/library/n_local/n_local.py in _build(self)
    899             if self.insert_barriers:
    900                 self.barrier()
--> 901             self._build_rotation_layer(param_iter, i)
    902 
    903         # add the appended layers

UnboundLocalError: local variable 'i' referenced before assignment
```

### What is the expected behavior?

Display a comprehensive message to ask users to set `reps >= 1`.

### Suggested solutions

Check `reps >= 1` and if `reps <= 0` a message should be displayed such "reps should be larger or equal to 1`.




Discussion:
Hello, 
I am new to open source contribution and I think this should be a good first issue to work on.
If this is available please can I work on it ?
Thank You!
Feel free to work on it! This is a good first issue indeed.
I was thinking to check in the _init_ class constructor if reps<=0 I would raise a TypeError.
Something Like this on line 138 in n_local.py 
if reps <= 0:
     raise TypeError('reps should be larger than or equal to 1')

also, add the information of new raised error in comment line 116 in n_local.py

Please let me know if there are any simple alternative approaches that I might have missed?
> Feel free to work on it! This is a good first issue indeed.

Is the approach I mentioned earlier fine ?
Thank You!
It is! However I think raising a `ValueError` would be more appropriate. 
> It is! However I think raising a `ValueError` would be more appropriate. 

Okay will do the code and submit a pull request! 

Resolving patch:
diff --git a/qiskit/circuit/library/n_local/n_local.py b/qiskit/circuit/library/n_local/n_local.py
--- a/qiskit/circuit/library/n_local/n_local.py
+++ b/qiskit/circuit/library/n_local/n_local.py
@@ -113,7 +113,7 @@ def __init__(self,
             ImportError: If an ``initial_state`` is specified but Qiskit Aqua is not installed.
             TypeError: If an ``initial_state`` is specified but not of the correct type,
                 ``qiskit.aqua.components.initial_states.InitialState``.
-
+            ValueError: If reps parameter is less than or equal to 0.
         """
         super().__init__(name=name)
 
@@ -136,6 +136,9 @@ def __init__(self,
         self._data = None
         self._bounds = None
 
+        if reps <= 0:
+            raise ValueError('The value of reps should be larger than or equal to 1')
+
         if num_qubits is not None:
             self.num_qubits = num_qubits
 
@@ -479,7 +482,12 @@ def reps(self, repetitions: int) -> None:
 
         Args:
             repetitions: The new repetitions.
+
+        Raises:
+            ValueError: If reps setter has parameter repetitions <= 0.
         """
+        if repetitions <= 0:
+            raise ValueError('The repetitions should be larger than or equal to 1')
         if repetitions != self._reps:
             self._invalidate()
             self._reps = repetitions


Test patch:
diff --git a/test/python/circuit/library/test_nlocal.py b/test/python/circuit/library/test_nlocal.py
--- a/test/python/circuit/library/test_nlocal.py
+++ b/test/python/circuit/library/test_nlocal.py
@@ -33,6 +33,17 @@
 class TestNLocal(QiskitTestCase):
     """Test the n-local circuit class."""
 
+    def test_if_reps_is_zero(self):
+        """Test to check if error is raised for 0 or negative value of reps"""
+        with self.assertRaises(ValueError):
+            _ = NLocal(reps=-1)
+
+    def test_reps_setter_when_negative(self):
+        """Test to check if setter raises error for reps <=0"""
+        nlocal = NLocal(reps=1)
+        with self.assertRaises(ValueError):
+            nlocal.reps = -1
+
     def assertCircuitEqual(self, qc1, qc2, visual=False, transpiled=True):
         """An equality test specialized to circuits."""
         if transpiled: