Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redress global_phase in controlled UnitaryGate #4799

Merged
merged 9 commits into from
Aug 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions qiskit/extensions/unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
QiskitError: Invalid ctrl_state.
ExtensionError: Non-unitary controlled unitary.
"""
cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits, ctrl_state=ctrl_state)
cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits, ctrl_state=None)
iso = isometry.Isometry(cmat, 0, 0)
cunitary = ControlledGate('c-unitary', num_qubits=self.num_qubits+num_ctrl_qubits,
params=[cmat], label=label, num_ctrl_qubits=num_ctrl_qubits,
Expand All @@ -147,9 +147,8 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
raise ExtensionError('controlled unitary generation failed')
phase = numpy.angle(diag[0])
if phase:
qreg = cunitary.definition.qregs[0]
cunitary.definition.u3(numpy.pi, phase, phase - numpy.pi, qreg[0])
cunitary.definition.u3(numpy.pi, 0, numpy.pi, qreg[0])
# need to apply to _definition since open controls creates temporary definition
cunitary._definition.global_phase = phase
cunitary.base_gate = self.copy()
cunitary.base_gate.label = self.label
return cunitary
Expand Down
1 change: 0 additions & 1 deletion qiskit/transpiler/passes/synthesis/unitary_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
Returns:
Output dag with UnitaryGates synthesized to target basis.
"""

euler_basis = _choose_euler_basis(self._basis_gates)
kak_gate = _choose_kak_gate(self._basis_gates)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
issues:
- |
Previously, when creating decomposition of controlled unitary gate
using Isometry, global phase differences in the decomposition were
corrected by applying single qubit gates. This PR instead just
sets the global phase of the circuit definition to this phase
correction.
fixes:
- |
Fixes a bug where setting ctrl_state of a `UnitaryGate` would
apparently have no effect. In reality it was happening twice; once
in the creation of the matrix for the controlled unitary and again
when calling the `definition` method of the `ControlledGate`
class.
13 changes: 12 additions & 1 deletion test/python/circuit/test_controlled_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ def test_controlled_random_unitary(self, num_ctrl_qubits):
cop_mat = _compute_control_matrix(base_mat, num_ctrl_qubits)
self.assertTrue(matrix_equal(cop_mat, test_op.data, ignore_phase=True))

@combine(num_ctrl_qubits=[1, 2, 3], ctrl_state=[None])
@combine(num_ctrl_qubits=[1, 2, 3], ctrl_state=[0, None])
def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state):
"""Test that UnitaryGate with control returns params."""
umat = np.array([[1, 0], [0, -1]])
Expand All @@ -653,6 +653,17 @@ def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state):
ref_mat = _compute_control_matrix(umat, num_ctrl_qubits, ctrl_state=ctrl_state)
self.assertEqual(Operator(cugate), Operator(ref_mat))

def test_controlled_controlled_unitary(self):
"""Test that global phase in iso decomposition of unitary is handled."""
umat = np.array([[1, 0], [0, -1]])
ugate = UnitaryGate(umat)
cugate = ugate.control()
ccugate = cugate.control()
ccugate2 = ugate.control(2)
ref_mat = _compute_control_matrix(umat, 2)
self.assertTrue(Operator(ccugate2).equiv(Operator(ref_mat)))
self.assertTrue(Operator(ccugate).equiv(Operator(ccugate2)))

@data(1, 2, 3)
def test_open_controlled_unitary_matrix(self, num_ctrl_qubits):
"""test open controlled unitary matrix"""
Expand Down