-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Fix wrong relative phase of MCRZ #9836
Changes from 41 commits
9f49257
2c81328
a8fbb81
5151a42
0aec4ec
b01a093
e39e09d
d632819
32acacc
3c8bdc4
3a92dc9
155a982
ed6953b
100a690
7d3ea14
7c75611
c1ceaf6
39d35b4
c00d17a
0a6148d
f4042c1
b999c20
0c3eeed
6bdb533
9b02451
2568a39
15034fd
fe874ef
b762b39
d75b9c9
d584340
1fe9ce5
de3d840
e39de45
4e4f14d
ac25805
ab9920f
b94e936
17ce419
fab1c80
3aedea6
fd14c87
856cd15
7a9df50
9269ecf
fb180f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -148,6 +148,7 @@ def control( | |
q_target[bit_indices[qargs[0]]], | ||
use_basis_gates=True, | ||
) | ||
continue | ||
elif gate.name == "p": | ||
from qiskit.circuit.library import MCPhaseGate | ||
|
||
|
@@ -184,23 +185,17 @@ def control( | |
use_basis_gates=True, | ||
) | ||
elif theta == 0 and phi == 0: | ||
controlled_circ.mcrz( | ||
lamb, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True | ||
) | ||
controlled_circ.mcp(lamb, q_control, q_target[bit_indices[qargs[0]]]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this output still the same as before, without the explicit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It still has no auxiliary qubits, however the basis_gates are different. This is an internal change and probably doesn't need to be reported in the release notes. |
||
else: | ||
controlled_circ.mcrz( | ||
lamb, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True | ||
) | ||
controlled_circ.mcp(lamb, q_control, q_target[bit_indices[qargs[0]]]) | ||
controlled_circ.mcry( | ||
theta, | ||
q_control, | ||
q_target[bit_indices[qargs[0]]], | ||
q_ancillae, | ||
use_basis_gates=True, | ||
) | ||
controlled_circ.mcrz( | ||
phi, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True | ||
) | ||
controlled_circ.mcp(phi, q_control, q_target[bit_indices[qargs[0]]]) | ||
elif gate.name == "z": | ||
controlled_circ.h(q_target[bit_indices[qargs[0]]]) | ||
controlled_circ.mcx(q_control, q_target[bit_indices[qargs[0]]], q_ancillae) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,28 +84,28 @@ def _apply_mcu_graycode(circuit, theta, phi, lam, ctls, tgt, use_basis_gates): | |
|
||
|
||
def mcsu2_real_diagonal( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it would be better to mark this function as private as it is a utility and not API documented. If we want to expose it, it might be worth to turn it into it's own class in a follow-up PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept it public, but we can easily make its private and delete the release note of #9688. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better if it's private, this way we can still move it e.g. to the synthesis module later, or turn it into a class without having to deprecate it. Since the release is imminent, I'll open a short separate PR for that 🙂 |
||
circuit, | ||
circuit: QuantumCircuit, | ||
unitary: np.ndarray, | ||
controls: Union[QuantumRegister, List[Qubit]], | ||
target: Union[Qubit, int], | ||
ctrl_state: str = None, | ||
ctrl_state: Optional[str] = None, | ||
): | ||
""" | ||
Apply multi-controlled SU(2) gate with a real main diagonal or secondary diagonal. | ||
https://arxiv.org/abs/2302.06377 | ||
|
||
Args: | ||
circuit (QuantumCircuit): The QuantumCircuit object to apply the diagonal operator on. | ||
unitary (ndarray): SU(2) unitary matrix with one real diagonal | ||
controls (QuantumRegister or list(Qubit)): The list of control qubits | ||
target (Qubit or int): The target qubit | ||
ctrl_state (str): control state of the operator SU(2) operator | ||
circuit: The QuantumCircuit object to apply the diagonal operator on. | ||
unitary: SU(2) unitary matrix with one real diagonal | ||
controls: The list of control qubits | ||
target: The target qubit | ||
ctrl_state: control state of the operator SU(2) operator | ||
|
||
Raises: | ||
QiskitError: parameter errors | ||
""" | ||
# pylint: disable=cyclic-import | ||
from qiskit.circuit.library import MCXVChain | ||
from .x import MCXVChain | ||
from qiskit.extensions import UnitaryGate | ||
from qiskit.quantum_info.operators.predicates import is_unitary_matrix | ||
|
||
|
@@ -130,13 +130,17 @@ def mcsu2_real_diagonal( | |
x = -unitary[0, 1].real | ||
z = unitary[1, 1] - unitary[0, 1].imag * 1.0j | ||
|
||
alpha_r = np.sqrt((np.sqrt((z.real + 1.0) / 2.0) + 1.0) / 2.0) | ||
alpha_i = z.imag / (2.0 * np.sqrt((z.real + 1.0) * (np.sqrt((z.real + 1.0) / 2.0) + 1.0))) | ||
alpha = alpha_r + 1.0j * alpha_i | ||
beta = x / (2.0 * np.sqrt((z.real + 1.0) * (np.sqrt((z.real + 1.0) / 2.0) + 1.0))) | ||
if np.isclose(z, -1): | ||
s_op = [[1.0, 0.0], [0.0, 1.0j]] | ||
else: | ||
alpha_r = np.sqrt((np.sqrt((z.real + 1.0) / 2.0) + 1.0) / 2.0) | ||
alpha_i = z.imag / (2.0 * np.sqrt((z.real + 1.0) * (np.sqrt((z.real + 1.0) / 2.0) + 1.0))) | ||
alpha = alpha_r + 1.0j * alpha_i | ||
beta = x / (2.0 * np.sqrt((z.real + 1.0) * (np.sqrt((z.real + 1.0) / 2.0) + 1.0))) | ||
|
||
# S gate definition | ||
s_op = np.array([[alpha, -np.conj(beta)], [beta, np.conj(alpha)]]) | ||
|
||
# S gate definition | ||
s_op = np.array([[alpha, -np.conj(beta)], [beta, np.conj(alpha)]]) | ||
s_gate = UnitaryGate(s_op) | ||
|
||
num_ctrl = len(controls) | ||
|
@@ -327,6 +331,8 @@ def mcrz( | |
Raises: | ||
QiskitError: parameter errors | ||
""" | ||
from .rz import CRZGate, RZGate | ||
|
||
control_qubits = self.qbit_argument_conversion(q_controls) | ||
target_qubit = self.qbit_argument_conversion(q_target) | ||
if len(target_qubit) != 1: | ||
|
@@ -336,13 +342,16 @@ def mcrz( | |
self._check_dups(all_qubits) | ||
|
||
n_c = len(control_qubits) | ||
if n_c == 1: # cu | ||
_apply_cu(self, 0, 0, lam, control_qubits[0], target_qubit, use_basis_gates=use_basis_gates) | ||
if n_c == 1: | ||
self.append(CRZGate(lam), control_qubits + [target_qubit]) | ||
else: | ||
lam_step = lam * (1 / (2 ** (n_c - 1))) | ||
_apply_mcu_graycode( | ||
self, 0, 0, lam_step, control_qubits, target_qubit, use_basis_gates=use_basis_gates | ||
) | ||
mcsu2_real_diagonal(self, RZGate(lam).to_matrix(), control_qubits, target_qubit) | ||
|
||
if use_basis_gates: | ||
# pylint: disable=cyclic-import | ||
from qiskit import transpile | ||
|
||
self = transpile(self, basis_gates=["p", "u", "cx"], optimization_level=0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is quite correct, sorry if I didn't express it correctly before. With this code, the whole circuit will get transpiled to the specified basis -- but we only want the newly added mcrz to be in that basis 🙂 maybe we can just change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @Cryoris , I removed the transpile call. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree it's not the most efficient way, but we should ensure that |
||
|
||
|
||
QuantumCircuit.mcrx = mcrx | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
fixes: | ||
- | | ||
Fixed the gate decomposition of multi-controlled Z rotation gates added via | ||
:meth:`.QuantumCircuit.mcrz`. Previously, this method implemented a multi-controlled | ||
phase gate, which has a relative phase difference to the Z rotation. To obtain the | ||
previous `.QuantumCircuit.mcrz` behaviour, use `.QuantumCircuit.mcp`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because the decomposition is phase correct and the fragment below will change the global phase.