Repository: Qiskit/qiskit

Issue:
Runtime error with complex numpy arrays and Aer simulators
<!-- ⚠️ 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**: 18.0
- **Python version**: 3.7.6
- **Operating system**: OSX Catalina

### What is the current behavior?
When executing a quantum circuit with an initialize gate, if the gate is given a complex numpy array, python crashes upon calling result().


### Steps to reproduce the problem

```
from qiskit import QuantumCircuit, Aer, execute
import numpy as np
qc = QuantumCircuit(1)
vec = np.array([0, 0+1j])
qc.initialize(vec, 0)
backend = Aer.get_backend('statevector_simulator')
job = execute(qc, backend)
result = job.result()
```
Outputs:

```
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-42-e6a6395b5aa4> in <module>
      6 backend = Aer.get_backend('statevector_simulator')
      7 job = execute(qc, backend)
----> 8 result = job.result()

/usr/local/anaconda3/lib/python3.7/site-packages/qiskit/providers/aer/aerjob.py in _wrapper(self, *args, **kwargs)
     39         if self._future is None:
     40             raise JobError("Job not submitted yet!. You have to .submit() first!")
---> 41         return func(self, *args, **kwargs)
     42     return _wrapper
     43 

/usr/local/anaconda3/lib/python3.7/site-packages/qiskit/providers/aer/aerjob.py in result(self, timeout)
     92             concurrent.futures.CancelledError: if job cancelled before completed.
     93         """
---> 94         return self._future.result(timeout=timeout)
     95 
     96     @requires_submit

/usr/local/anaconda3/lib/python3.7/concurrent/futures/_base.py in result(self, timeout)
    433                 raise CancelledError()
    434             elif self._state == FINISHED:
--> 435                 return self.__get_result()
    436             else:
    437                 raise TimeoutError()

/usr/local/anaconda3/lib/python3.7/concurrent/futures/_base.py in __get_result(self)
    382     def __get_result(self):
    383         if self._exception:
--> 384             raise self._exception
    385         else:
    386             return self._result

/usr/local/anaconda3/lib/python3.7/concurrent/futures/thread.py in run(self)
     55 
     56         try:
---> 57             result = self.fn(*self.args, **self.kwargs)
     58         except BaseException as exc:
     59             self.future.set_exception(exc)

/usr/local/anaconda3/lib/python3.7/site-packages/qiskit/providers/aer/backends/aerbackend.py in _run_job(self, job_id, qobj, backend_options, noise_model, validate)
    131             validate_qobj_against_schema(qobj)
    132             self._validate(qobj, backend_options, noise_model)
--> 133         output = self._controller(self._format_qobj(qobj, backend_options, noise_model))
    134         self._validate_controller_output(output)
    135         end = time.time()

RuntimeError: Unable to cast Python instance to C++ type (compile in debug mode for details)
```
Replacing Aer with BasicAer fixes this.

### What is the expected behavior?

Does not crash.



### Suggested solutions

I don't know if this is a problem with Terra or Aer. A workaround could be converting the numpy array to a normal list when creating the initialize gate.




Discussion:

Resolving patch:
diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py
--- a/qiskit/circuit/instruction.py
+++ b/qiskit/circuit/instruction.py
@@ -140,6 +140,8 @@ def params(self, parameters):
             # example: u2(pi/2, sin(pi/4))
             if isinstance(single_param, (ParameterExpression)):
                 self._params.append(single_param)
+            elif isinstance(single_param, numpy.number):
+                self._params.append(single_param.item())
             # example: u3(0.1, 0.2, 0.3)
             elif isinstance(single_param, (int, float)):
                 self._params.append(single_param)
@@ -155,8 +157,6 @@ def params(self, parameters):
             # example: numpy.array([[1, 0], [0, 1]])
             elif isinstance(single_param, numpy.ndarray):
                 self._params.append(single_param)
-            elif isinstance(single_param, numpy.number):
-                self._params.append(single_param.item())
             else:
                 raise CircuitError("invalid param type {0} in instruction "
                                    "{1}".format(type(single_param), self.name))


Test patch:
diff --git a/test/python/circuit/test_initializer.py b/test/python/circuit/test_initializer.py
--- a/test/python/circuit/test_initializer.py
+++ b/test/python/circuit/test_initializer.py
@@ -23,7 +23,7 @@
 from qiskit import QuantumCircuit
 from qiskit import QuantumRegister
 from qiskit import ClassicalRegister
-from qiskit import execute, BasicAer
+from qiskit import execute, assemble, BasicAer
 from qiskit.quantum_info import state_fidelity
 from qiskit.exceptions import QiskitError
 from qiskit.test import QiskitTestCase
@@ -315,5 +315,45 @@ def test_equivalence(self):
         self.assertEqual(qc1, qc2)
 
 
+class TestInstructionParam(QiskitTestCase):
+    """Test conversion of numpy type parameters."""
+
+    def test_daig_(self):
+        """Verify diagonal gate converts numpy.complex to complex."""
+        # ref: https://github.com/Qiskit/qiskit-aer/issues/696
+        diag = np.array([1+0j, 1+0j])
+        qc = QuantumCircuit(1)
+        qc.diagonal(list(diag), [0])
+
+        params = qc.data[0][0].params
+        self.assertTrue(
+            all(isinstance(p, complex) and not isinstance(p, np.number)
+                for p in params))
+
+        qobj = assemble(qc)
+        params = qobj.experiments[0].instructions[0].params
+        self.assertTrue(
+            all(isinstance(p, complex) and not isinstance(p, np.number)
+                for p in params))
+
+    def test_init(self):
+        """Verify initialize gate converts numpy.complex to complex."""
+        # ref: https://github.com/Qiskit/qiskit-terra/issues/4151
+        qc = QuantumCircuit(1)
+        vec = np.array([0, 0+1j])
+        qc.initialize(vec, 0)
+
+        params = qc.data[0][0].params
+        self.assertTrue(
+            all(isinstance(p, complex) and not isinstance(p, np.number)
+                for p in params))
+
+        qobj = assemble(qc)
+        params = qobj.experiments[0].instructions[0].params
+        self.assertTrue(
+            all(isinstance(p, complex) and not isinstance(p, np.number)
+                for p in params))
+
+
 if __name__ == '__main__':
     unittest.main()