Repository: Qiskit/qiskit

Issue:
Statevector.from_instruction fails for custom controlled gates
<!-- ⚠️ 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**: latest
- **Python version**:
- **Operating system**:

### What is the current behavior?
```python
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector

## Create 7mod15 gate
N = 15
m = int(np.ceil(np.log2(N)))

U_qc = QuantumCircuit(m)
U_qc.x(range(m))
U_qc.swap(1, 2)
U_qc.swap(2, 3)
U_qc.swap(0, 3)

U = U_qc.to_gate()
U.name ='{}Mod{}'.format(7, N)
U_cntrl = U.control()

qc = QuantumCircuit(5)
qc.append(U_cntrl, range(5))

Statevector.from_instruction(qc)
```
gives


Traceback (most recent call last):
  File "<ipython-input-127-b464b6ab1295>", line 1, in <module>
    Statevector.from_instruction(qc)
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/qiskit/quantum_info/states/statevector.py", line 529, in from_instruction
    return Statevector._evolve_instruction(vec, instruction)
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/qiskit/quantum_info/states/statevector.py", line 690, in _evolve_instruction
    Statevector._evolve_instruction(statevec, instr, qargs=new_qargs)
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/qiskit/quantum_info/states/statevector.py", line 690, in _evolve_instruction
    Statevector._evolve_instruction(statevec, instr, qargs=new_qargs)
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/qiskit/quantum_info/states/statevector.py", line 661, in _evolve_instruction
    return Statevector._evolve_operator(statevec, Operator(mat), qargs=qargs)
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/qiskit/quantum_info/states/statevector.py", line 642, in _evolve_operator
    np.reshape(statevec.data, pre_tensor_shape), axes), contract_shape)
  File "<__array_function__ internals>", line 6, in transpose
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/numpy/core/fromnumeric.py", line 653, in transpose
    return _wrapfunc(a, 'transpose', axes)
  File "/opt/miniconda3/envs/qiskit/lib/python3.7/site-packages/numpy/core/fromnumeric.py", line 58, in _wrapfunc
    return bound(*args, **kwds)
ValueError: axes don't match array
### Steps to reproduce the problem



### What is the expected behavior?



### Suggested solutions





Discussion:

Resolving patch:
diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py
--- a/qiskit/quantum_info/states/statevector.py
+++ b/qiskit/quantum_info/states/statevector.py
@@ -677,6 +677,7 @@ def _evolve_instruction(statevec, obj, qargs=None):
                 obj.name, type(obj.definition)))
         if obj.definition.global_phase:
             statevec._data *= np.exp(1j * float(obj.definition.global_phase))
+        qubits = {qubit: i for i, qubit in enumerate(obj.definition.qubits)}
         for instr, qregs, cregs in obj.definition:
             if cregs:
                 raise QiskitError(
@@ -684,8 +685,8 @@ def _evolve_instruction(statevec, obj, qargs=None):
                         instr.name))
             # Get the integer position of the flat register
             if qargs is None:
-                new_qargs = [tup.index for tup in qregs]
+                new_qargs = [qubits[tup] for tup in qregs]
             else:
-                new_qargs = [qargs[tup.index] for tup in qregs]
+                new_qargs = [qargs[qubits[tup]] for tup in qregs]
             Statevector._evolve_instruction(statevec, instr, qargs=new_qargs)
         return statevec


Test patch:
diff --git a/test/python/quantum_info/states/test_statevector.py b/test/python/quantum_info/states/test_statevector.py
--- a/test/python/quantum_info/states/test_statevector.py
+++ b/test/python/quantum_info/states/test_statevector.py
@@ -129,6 +129,20 @@ def test_from_circuit(self):
         psi = Statevector.from_instruction(circuit)
         self.assertEqual(psi, target)
 
+        # Test custom controlled gate
+        qc = QuantumCircuit(2)
+        qc.x(0)
+        qc.h(1)
+        gate = qc.to_gate()
+        gate_ctrl = gate.control()
+
+        circuit = QuantumCircuit(3)
+        circuit.x(0)
+        circuit.append(gate_ctrl, range(3))
+        target = Statevector.from_label('000').evolve(Operator(circuit))
+        psi = Statevector.from_instruction(circuit)
+        self.assertEqual(psi, target)
+
         # Test initialize instruction
         target = Statevector([1, 0, 0, 1j]) / np.sqrt(2)
         circuit = QuantumCircuit(2)