Repository: Qiskit/qiskit

Issue:
Initialize instruction does not preserve global phase
I create an `Initialize` instruction and pass it to the Aer statevector_simulator. But, the resulting amplitudes differ by a phase from the expected result. For example

EDIT (08APR2021): A closer to minimal example is given in the comment following this one.
EDIT (07APR2021): one line in this example has been edited to remove the dependence on aqua (which is deprecated)
```python
from qiskit import Aer
from qiskit.utils import QuantumInstance
from qiskit.extensions import Initialize
import numpy as np

state_array = np.array([1j/np.sqrt(2), 0, 1j/np.sqrt(2), 0])
init = Initialize(state_array)
init_circ = init.definition
#init_circ.data = init_circ.data[2:3]
qinstance = QuantumInstance(backend=Aer.get_backend("statevector_simulator"))
result = qinstance.execute(init_circ)
state_array_out = result.get_statevector()
```

`state_array_out` differs from `state_array` by a factor of `i`.  Uncommenting the line `init_circ.data = init_circ.data[2:3]` removes the qubit initializations, but does not change the result.

The docstring for `Initialize` is
```python

    """Complex amplitude initialization.

    Class that implements the (complex amplitude) initialization of some
    flexible collection of qubit registers (assuming the qubits are in the
    zero state).
    Note that Initialize is an Instruction and not a Gate since it contains a reset instruction,
    which is not unitary.
    """
```
This doesn't explicitly say that a global phase is respected. But, I suppose it should be. I also wonder why "assuming the qubits are in the zero state" is included since reset instructions are inserted. (EDIT: The last point is addressed in #5190)

### Information

- **Qiskit Terra version**: 348c75247






Discussion:
Here is an example that is closer to a Mnon-WE
```python
from qiskit.extensions import Initialize
import numpy as np
from qiskit.quantum_info import Operator
from qiskit import QuantumCircuit

state_array = 1j * np.array([1.0, 0])

# Create a circuit that does a reset and then prepares state_array,
# as an Initialize object
init = Initialize(state_array)

# Get the corresponding QuantumCircuit
init_circ = init.definition

# Make a copy of init_circ with the reset instruction removed
noinit_circ = init_circ.copy()
noinit_circ.data = noinit_circ.data[1:2]

# Get the matrix representation of the state preparation circuit
# We use the version without explicit reset, because reset is not
# unitary and not invertible.
noinit_matrix = Operator(noinit_circ).data

# Get the prepared state obtained from the matrix.
# noinit_matrix operating on |00> returns the first column
state_array_from_matrix = noinit_matrix[:,0]

# Output state differs from the intended state by a factor of sqrt(-1)
# This prints True
print(np.allclose(1j * state_array_from_matrix, state_array), ': Is 1j*array_out equal to requested array')
```
If, in the above example, we instead take
```python
state_array = 1j * np.array([0.0, 1])
```
then the output array ` state_array_from_matrix` *is* correct and *is* the same as the input array.

I opened this issue because it was brought to my attention, but I don't recall where.

The current behavior can be considered correct under some circumstances. If the register is the entire quantum system, then the global phase is irrelevant, so that introducing gates to correct the phase is wasteful. It seems that may be what is happening here. So a couple of questions are
* Are there cases in which it makes sense to retain the global phase? Maybe a case in which it is possible to use the Initializer on only part of a coherent quantum system?
* Should we have an option for the user to request that the global phase be retained? It seems that for the main use case, and certainly for real hardware, neglecting the phase is correct and should probably be the default.

If it is easy to fix the global phase (e.g. by just setting the `QuantumCircuit.global_phase` attribute) I think we should fix it, it might be confusing if the output of the initialize instructions doesn't match the input.

Resolving patch:
diff --git a/qiskit/extensions/quantum_initializer/initializer.py b/qiskit/extensions/quantum_initializer/initializer.py
--- a/qiskit/extensions/quantum_initializer/initializer.py
+++ b/qiskit/extensions/quantum_initializer/initializer.py
@@ -26,7 +26,7 @@
 from qiskit.circuit.library.standard_gates.h import HGate
 from qiskit.circuit.library.standard_gates.s import SGate, SdgGate
 from qiskit.circuit.library.standard_gates.ry import RYGate
-from qiskit.circuit.library.standard_gates.u1 import U1Gate
+from qiskit.circuit.library.standard_gates.rz import RZGate
 from qiskit.circuit.reset import Reset
 from qiskit.quantum_info import Statevector
 
@@ -198,13 +198,13 @@ def gates_to_uncompute(self):
                 add_last_cnot = False
 
             if np.linalg.norm(phis) != 0:
-                rz_mult = self._multiplex(U1Gate, phis, last_cnot=add_last_cnot)
+                rz_mult = self._multiplex(RZGate, phis, last_cnot=add_last_cnot)
                 circuit.append(rz_mult.to_instruction(), q[i:self.num_qubits])
 
             if np.linalg.norm(thetas) != 0:
                 ry_mult = self._multiplex(RYGate, thetas, last_cnot=add_last_cnot)
                 circuit.append(ry_mult.to_instruction().reverse_ops(), q[i:self.num_qubits])
-
+        circuit.global_phase -= np.angle(sum(remaining_param))
         return circuit
 
     @staticmethod


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 ClassicalRegister
 from qiskit import transpile
 from qiskit import execute, assemble, BasicAer
-from qiskit.quantum_info import state_fidelity, Statevector
+from qiskit.quantum_info import state_fidelity, Statevector, Operator
 from qiskit.exceptions import QiskitError
 from qiskit.test import QiskitTestCase
 
@@ -367,6 +367,43 @@ def test_from_int(self):
         actual_sv = Statevector.from_instruction(qc)
         self.assertTrue(desired_sv == actual_sv)
 
+    def _remove_resets(self, circ):
+        circ.data = [tup for tup in circ.data if tup[0].name != 'reset']
+
+    def test_global_phase_random(self):
+        """Test global phase preservation with random state vectors"""
+        from qiskit.quantum_info.random import random_statevector
+        repeats = 5
+        for n_qubits in [1, 2, 4]:
+            for irep in range(repeats):
+                with self.subTest(i=f'{n_qubits}_{irep}'):
+                    dim = 2**n_qubits
+                    qr = QuantumRegister(n_qubits)
+                    initializer = QuantumCircuit(qr)
+                    target = random_statevector(dim)
+                    initializer.initialize(target, qr)
+                    uninit = initializer.data[0][0].definition
+                    self._remove_resets(uninit)
+                    evolve = Statevector(uninit)
+                    self.assertEqual(target, evolve)
+
+    def test_global_phase_1q(self):
+        """Test global phase preservation with some simple 1q statevectors"""
+        target_list = [Statevector([1j, 0]), Statevector([0, 1j]),
+                       Statevector([1j/np.sqrt(2), 1j/np.sqrt(2)])]
+        n_qubits = 1
+        dim = 2**n_qubits
+        qr = QuantumRegister(n_qubits)
+        for target in target_list:
+            with self.subTest(i=target):
+                initializer = QuantumCircuit(qr)
+                initializer.initialize(target, qr)
+                # need to get rid of the resets in order to use the Operator class
+                disentangler = Operator(initializer.data[0][0].definition.data[1][0])
+                zero = Statevector.from_int(0, dim)
+                actual = zero @ disentangler
+                self.assertEqual(target, actual)
+
 
 class TestInstructionParam(QiskitTestCase):
     """Test conversion of numpy type parameters."""