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

EchoRZXWeylDecomposition Transpiler Pass #6784

Merged
merged 66 commits into from
Oct 1, 2021

Conversation

catornow
Copy link
Contributor

@catornow catornow commented Jul 21, 2021

Summary

This PR implements a new transpiler pass EchoRZXWeylDecomposition that, in combination with other transpiler passes, allows users to transpile circuits to RZX gate-based and pulse-efficient circuits. The circuits typically have shorter pulse schedule durations and higher fidelities in comparison to the standard digital CNOT-based transpired circuits (see Reference https://arxiv.org/pdf/2105.01063.pdf).
First, all consecutive two-qubit operations in a circuit need to be consolidated. The new transpiler pass EchoRZXWeylDecomposition then leverages Cartan's decomposition of arbitrary two-qubit gates and decomposes the two-qubit gates in terms of echoed RZX gates. Lastly, calibrations can be added to the RZX gates by leveraging the RZXCalibrationBuilderNoEcho, see PR #6300. Most importantly, no additional calibration is needed.

Details and comments

The output of this self-contained code should illustrate the transpilation of a randomly chosen circuit to an RZX gate-based, pulse-efficient circuit.

from qiskit import QuantumCircuit, transpile, schedule, IBMQ
from qiskit.transpiler import PassManager

import numpy as np

IBMQ.load_account()
provider = IBMQ.get_provider(...)

backend = provider.get_backend("ibm_lagos")

from qiskit.circuit.library.standard_gates.equivalence_library import (
    StandardEquivalenceLibrary as std_eqlib,
)

# Transpiler passes
from qiskit.transpiler.passes import Collect2qBlocks
from qiskit.transpiler.passes import ConsolidateBlocks
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes.basis import BasisTranslator, UnrollCustomDefinitions
from qiskit.transpiler.passes.calibration.builders import RZXCalibrationBuilderNoEcho

# New transpiler pass
from qiskit.transpiler.passes.optimization.echo_rzx_weyl_decomposition import (
    EchoRZXWeylDecomposition,
)

# Random circuit

delta = 8 * np.pi / 5
epsilon = np.pi / 2
eta = -5.1
theta = 0.02

qc = QuantumCircuit(3)
qc.ryy(theta, 0, 1)
qc.s(0)
qc.rz(eta, 1)
qc.rzz(epsilon, 0, 1)
qc.swap(0, 1)
qc.cx(1, 0)
qc.rzz(delta, 1, 2)
qc.swap(1, 2)
qc.h(2)

print("Original circuit:")
print(qc)

qct = transpile(qc, backend)

print("Transpiled circuit:")
print(qct)

rzx_basis = ["rzx", "rz", "x", "sx"]

# Build a pass manager that contains all needed transpiler passes
pm = PassManager(
    [
        # Consolidate consecutive two-qubit operations.
        Collect2qBlocks(),
        ConsolidateBlocks(basis_gates=["rz", "sx", "x", "rxx"]),
        # Rewrite circuit in terms of Weyl-decomposed echoed RZX gates.
        EchoRZXWeylDecomposition(backend),
        # Attach scaled CR pulse schedules to the RZX gates.
        RZXCalibrationBuilderNoEcho(backend),
        # Simplify single-qubit gates.
        UnrollCustomDefinitions(std_eqlib, rzx_basis),
        BasisTranslator(std_eqlib, rzx_basis),
        Optimize1qGatesDecomposition(rzx_basis),
    ]
)

# Run the pass manager
qc_pulse_efficient = pm.run(qct)

print("Pulse-efficient, RZX-based circuit:")
print(qc_pulse_efficient)

# Compare the schedule durations
print("Duration of standard CNOT-based circuit:")
print(schedule(qct, backend).duration)
print("Duration of pulse-efficient circuit:")
print(schedule(qc_pulse_efficient, backend).duration)

Output (I removed the ancilla qubits for better readability):

Original circuit:
     ┌────────────┐   ┌───┐                 ┌───┐                   
q_0: ┤0           ├───┤ S ├─────■─────────X─┤ X ├───────────────────
     │  Ryy(0.02) │┌──┴───┴───┐ │ZZ(π/2)  │ └─┬─┘                   
q_1: ┤1           ├┤ Rz(-5.1) ├─■─────────X───■───■──────────X──────
     └────────────┘└──────────┘                   │ZZ(8π/5)  │ ┌───┐
q_2: ─────────────────────────────────────────────■──────────X─┤ H ├
                                                               └───┘
Transpiled circuit:
global phase: π/2
               ┌────┐                      ┌────────┐┌────┐  ┌──────────┐      »
      q_0 -> 0 ┤ √X ├──■────────────────■──┤ Rz(-π) ├┤ √X ├──┤ Rz(-π/2) ├───■──»
               ├────┤┌─┴─┐┌──────────┐┌─┴─┐├────────┤├────┤┌─┴──────────┴┐┌─┴─┐»
      q_1 -> 1 ┤ √X ├┤ X ├┤ Rz(0.02) ├┤ X ├┤ Rz(-π) ├┤ √X ├┤ Rz(-1.9584) ├┤ X ├»
               └────┘└───┘└──────────┘└───┘└────────┘└────┘└─────────────┘└───┘»
      q_2 -> 2 ────────────────────────────────────────────────────────────────»
                                                                               »
«                          ┌───┐     ┌───┐                           »
«      q_0 -> 0 ───────────┤ X ├──■──┤ X ├───────────────────────────»
«               ┌─────────┐└─┬─┘┌─┴─┐└─┬─┘                 ┌───┐     »
«      q_1 -> 1 ┤ Rz(π/2) ├──■──┤ X ├──■────■──────────────┤ X ├──■──»
«               └─────────┘     └───┘     ┌─┴─┐┌──────────┐└─┬─┘┌─┴─┐»
«      q_2 -> 2 ──────────────────────────┤ X ├┤ Rz(8π/5) ├──■──┤ X ├»
«                                         └───┘└──────────┘     └───┘»
«                                           
«      q_0 -> 0 ────────────────────────────
«                                           
«      q_1 -> 1 ────────────────────────────
«               ┌─────────┐┌────┐┌─────────┐
«      q_2 -> 2 ┤ Rz(π/2) ├┤ √X ├┤ Rz(π/2) ├
«               └─────────┘└────┘└─────────┘
«                                           
Pulse-efficient, RZX-based circuit:
global phase: 7π/4
        ┌──────────┐  ┌────┐ ┌──────────┐┌────────────┐┌───┐┌───────────┐»
q_0: ───┤ Rz(-π/2) ├──┤ √X ├─┤ Rz(-π/2) ├┤0           ├┤ X ├┤0          ├»
      ┌─┴──────────┴┐ ├────┤ ├──────────┤│  Rzx(-π/4) │└───┘│  Rzx(π/4) │»
q_1: ─┤ Rz(0.39786) ├─┤ √X ├─┤ Rz(-π/2) ├┤1           ├─────┤1          ├»
     ┌┴─────────────┴┐├────┤┌┴──────────┤└────────────┘     └───────────┘»
q_2: ┤ Rz(-0.053432) ├┤ √X ├┤ Rz(-3π/4) ├────────────────────────────────»
     └───────────────┘└────┘└───────────┘                                »

«        ┌────────┐   ┌────┐                                 ┌────────────────┐»
«q_0: ───┤ Rz(-π) ├───┤ √X ├─────────────────────────────────┤0               ├»
«     ┌──┴────────┴──┐├────┤┌──────────┐┌────┐┌─────────────┐│  Rzx(-0.78162) │»
«q_1: ┤ Rz(-0.61548) ├┤ √X ├┤ Rz(-π/3) ├┤ √X ├┤ Rz(0.61548) ├┤1               ├»
«     └──────────────┘└────┘└──────────┘└────┘└─────────────┘└────────────────┘»
«q_2: ─────────────────────────────────────────────────────────────────────────»
«                                                                              »
«     ┌───┐┌───────────────┐ ┌──────────┐                           »
«q_0: ┤ X ├┤0              ├─┤ Rz(-π/2) ├───────────────────────────»
«     └───┘│  Rzx(0.78162) │┌┴──────────┴┐┌────┐┌────────────┐┌────┐»
«q_1: ─────┤1              ├┤ Rz(1.5446) ├┤ √X ├┤ Rz(-2.356) ├┤ √X ├»
«          └───────────────┘└────────────┘└────┘└────────────┘└────┘»
«q_2: ──────────────────────────────────────────────────────────────»
«                                                                   »
«                                                                   »
«                                                                          »
«q_0: ─────────────────────────────────────────────────────────────────────»
«     ┌────────────┐┌────────────┐     ┌───────────┐   ┌───┐    ┌─────────┐»
«q_1: ┤ Rz(1.5359) ├┤1           ├─────┤1          ├───┤ X ├────┤ Rz(π/2) ├»
«     └────────────┘│  Rzx(-π/4) │┌───┐│  Rzx(π/4) │┌──┴───┴───┐└──┬────┬─┘»
«q_2: ──────────────┤0           ├┤ X ├┤0          ├┤ Rz(-π/4) ├───┤ √X ├──»
«                   └────────────┘└───┘└───────────┘└──────────┘   └────┘  »
«q_0: ─────────────────────────────────────────────────────────────────────»
«                 ┌────────────┐     ┌───────────┐    ┌────┐   ┌──────────┐»
«q_1: ────────────┤1           ├─────┤1          ├────┤ √X ├───┤ Rz(-π/2) ├»
«     ┌──────────┐│  Rzx(-π/4) │┌───┐│  Rzx(π/4) │┌───┴────┴──┐└──┬────┬──┘»
«q_2: ┤ Rz(3π/4) ├┤0           ├┤ X ├┤0          ├┤ Rz(-3π/4) ├───┤ √X ├───»
«     └──────────┘└────────────┘└───┘└───────────┘└───────────┘   └────┘   »
«                                                                          »
«                                                                       »
«q_0: ──────────────────────────────────────────────────────────────────»
«                 ┌────────────┐     ┌─────────────┐ ┌──────────┐ ┌────┐»
«q_1: ────────────┤1           ├─────┤1            ├─┤ Rz(-π/2) ├─┤ √X ├»
«     ┌──────────┐│  Rzx(π/20) │┌───┐│  Rzx(-π/20) │┌┴──────────┴┐├────┤»
«q_2: ┤ Rz(3π/4) ├┤0           ├┤ X ├┤0            ├┤ Rz(2.3028) ├┤ √X ├»
«     └──────────┘└────────────┘└───┘└─────────────┘└────────────┘└────┘»
«q_0: ────────────────
«     ┌──────────────┐
«q_1: ┤ Rz(0.053432) ├
«     └─┬─────────┬──┘
«q_2: ──┤ Rz(π/2) ├───
«       └─────────┘   
Duration of standard CNOT-based circuit:
13312
Duration of pulse-efficient circuit:
6688

@catornow catornow requested review from chriseclectic and a team as code owners July 21, 2021 18:18
@catornow catornow changed the title Echo rzx weyl decomposition EchoRZXWeylDecomposition Transpiler Pass Jul 21, 2021
Copy link
Contributor

@eggerdj eggerdj left a comment

Choose a reason for hiding this comment

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

Looking good. We can simplify the TwoQubitWeylEchoRZX a bit by giving it only one argument instead of giving it two arguments that are used to infer one argument. See suggestions.

qiskit/quantum_info/synthesis/two_qubit_decompose.py Outdated Show resolved Hide resolved
qiskit/quantum_info/synthesis/two_qubit_decompose.py Outdated Show resolved Hide resolved
qiskit/quantum_info/synthesis/two_qubit_decompose.py Outdated Show resolved Hide resolved
test/python/transpiler/test_echo_rzx_weyl_decomposition.py Outdated Show resolved Hide resolved
test/python/transpiler/test_echo_rzx_weyl_decomposition.py Outdated Show resolved Hide resolved
@levbishop levbishop self-assigned this Jul 26, 2021
@levbishop
Copy link
Member

levbishop commented Sep 3, 2021

I left a few comments inline. I didn't get a chance to review the whole thing will write more next week.

ecpeterson
ecpeterson previously approved these changes Sep 29, 2021
Copy link
Contributor

@ecpeterson ecpeterson left a comment

Choose a reason for hiding this comment

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

I feel pretty OK about this PR. I do think it should be integrated into UnitarySynthesis (even better: into the plug-in interface from #6124), but that's a fair bit of work, and I don't think it's a requirement that that be accomplished before merge.

Copy link
Contributor

@eggerdj eggerdj left a comment

Choose a reason for hiding this comment

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

LGTM.

@kdk kdk added the automerge label Oct 1, 2021
@kdk kdk added the Changelog: New Feature Include in the "Added" section of the changelog label Oct 1, 2021
@kdk kdk added this to the 0.19 milestone Oct 1, 2021
@mergify mergify bot merged commit a8a0d1b into Qiskit:main Oct 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants