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

Add equivalence-library rules between rzz and cp #13019

Merged
merged 2 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
43 changes: 43 additions & 0 deletions qiskit/circuit/library/standard_gates/equivalence_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,21 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True):
cphase_to_cu1.append(CU1Gate(theta), [0, 1])
_sel.add_equivalence(CPhaseGate(theta), cphase_to_cu1)

# CPhaseGate
#
# global phase: ϴ/4
# ┌─────────┐
# q_0: ─■──── q_0: ─■─────────┤ Rz(ϴ/2) ├
# │P(ϴ) ≡ │ZZ(-ϴ/2) ├─────────┤
# q_1: ─■──── q_1: ─■─────────┤ Rz(ϴ/2) ├
# └─────────┘
theta = Parameter("theta")
cphase_to_rzz = QuantumCircuit(2, global_phase=theta / 4)
cphase_to_rzz.rzz(-theta / 2, 0, 1)
cphase_to_rzz.rz(theta / 2, 0)
cphase_to_rzz.rz(theta / 2, 1)
_sel.add_equivalence(CPhaseGate(theta), cphase_to_rzz)

# RGate
#
# ┌────────┐ ┌───────────────────────┐
Expand Down Expand Up @@ -394,6 +409,19 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True):
def_rzx.append(inst, qargs, cargs)
_sel.add_equivalence(RZXGate(theta), def_rzx)

# RZXGate to RZZGate
# ┌─────────┐
# q_0: ┤0 ├ q_0: ──────■───────────
# │ Rzx(ϴ) │ ≡ ┌───┐ │ZZ(ϴ) ┌───┐
# q_1: ┤1 ├ q_1: ┤ H ├─■──────┤ H ├
# └─────────┘ └───┘ └───┘
theta = Parameter("theta")
rzx_to_rzz = QuantumCircuit(2)
rzx_to_rzz.h(1)
rzx_to_rzz.rzz(theta, 0, 1)
rzx_to_rzz.h(1)
_sel.add_equivalence(RZXGate(theta), rzx_to_rzz)


# RYGate
#
Expand Down Expand Up @@ -654,6 +682,21 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True):
rzz_to_rzx.h(1)
_sel.add_equivalence(RZZGate(theta), rzz_to_rzx)

# RZZ to CPhase
#
# global phase: ϴ/2
# ┌───────┐
# q_0: ─■───── q_0: ─■────────┤ Rz(ϴ) ├
# │ZZ(ϴ) ≡ │P(-2*ϴ) ├───────┤
# q_1: ─■───── q_1: ─■────────┤ Rz(ϴ) ├
# └───────┘
theta = Parameter("theta")
rzz_to_cphase = QuantumCircuit(2, global_phase=theta / 2)
rzz_to_cphase.cp(-theta * 2, 0, 1)
rzz_to_cphase.rz(theta, 0)
rzz_to_cphase.rz(theta, 1)
_sel.add_equivalence(RZZGate(theta), rzz_to_cphase)

# RZZ to RYY
q = QuantumRegister(2, "q")
theta = Parameter("theta")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
features_circuits:
- |
New equivalence rules in the standard equivalence library mean that the transpiler can now
directly convert between two-qubit continuous Pauli rotations, rather than always decomposing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it always decompose into CX? There are some existing 2q Pauli equivalences that should allow to convert between some two-qubit rotations, no? 🙂

Suggested change
directly convert between two-qubit continuous Pauli rotations, rather than always decomposing
directly convert between two-qubit continuous Pauli rotations, rather than sometimes decomposing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll tweak this note - I wrote it under the same false assumption about how the basis translator works that's alluded to in the PR comment. We need a new translation algorithm to make any choice of translation reliable - the current system is good at finding an arbitrary valid translation, but not at finding the best translation (for any definition of "best").

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've written a new version of the release note in bbe529b.

into a discrete two-CX-based solution.
1 change: 0 additions & 1 deletion test/python/circuit/test_controlled_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1438,7 +1438,6 @@ def test_control_zero_operand_gate(self, num_ctrl_qubits):
@data(
RXGate,
RYGate,
RZGate,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you need to remove this test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is asserting that a failure occurs, and for most of the gates in the list, they shouldn't really fail - we've got enough equivalence and translation rules that it should be possible to translate the gate into one we can represent better. The add_control logic is just not super smart about gate translation.

As a side effect of this PR, the RZ path now happens to convert things to CPhaseGate rather than CRZGate (or something like that), so the control works further than it did before.

RXXGate,
RYYGate,
RZXGate,
Expand Down
Loading