Skip to content

Optimize consecutive RZZ gates into a single RZZ gate #13428

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

Closed
t-imamichi opened this issue Nov 13, 2024 · 10 comments · Fixed by #13884
Closed

Optimize consecutive RZZ gates into a single RZZ gate #13428

t-imamichi opened this issue Nov 13, 2024 · 10 comments · Fixed by #13884
Labels
mod: transpiler Issues and PRs related to Transpiler type: feature request New feature or request
Milestone

Comments

@t-imamichi
Copy link
Member

t-imamichi commented Nov 13, 2024

What should we add?

Since the fractional gates are available, RZZ can be used as a basis gate.
But, optimization of consecutive RZZ gates does not seem to be enough as follows.
It would be nice to merge them into a single RZZ.

from qiskit import generate_preset_pass_manager, QuantumCircuit

qc = QuantumCircuit(2)
qc.rzz(0.1, 0, 1)
qc.rzz(0.2, 0, 1)

pm = generate_preset_pass_manager(optimization_level=3, basis_gates=["rzz"])
qc2 = pm.run(qc)
print(qc2)

output (both 1.2.4 and main branch)

q_0: ─■─────────■────────
      │ZZ(0.1)  │ZZ(0.2)
q_1: ─■─────────■────────
@t-imamichi t-imamichi added type: feature request New feature or request mod: transpiler Issues and PRs related to Transpiler labels Nov 13, 2024
@melechlapson
Copy link
Contributor

Is this issue limited to the rzz gates and not other gates like ryy rzx etc.?

@t-imamichi
Copy link
Member Author

Not limited to RZZ. But I don't mind RYY and RZX because RZZ becomes a basis gate of devices that supports fractional gates. RYY and RZX are not basis gates of any device.
https://docs.quantum.ibm.com/guides/fractional-gates

@ShellyGarion
Copy link
Member

There is a synthesis algorithm TwoQubitControlledUDecomposer that takes a 2q-unitary and synthesizes it using the 2q basis gate RZZGate (with angles in the range [-pi/2, pi/2]. This algorithm has recently been ported to rust in #13139.

Here is an example of the output of this algorithm on the circuit suggested below:

        from qiskit.quantum_info import Operator
        from qiskit.synthesis.two_qubit.two_qubit_decompose import TwoQubitControlledUDecomposer
        unitary = Operator(qc)
        decomposer = TwoQubitControlledUDecomposer(RZZGate)
        qc3 = decomposer(unitary)
        print (qc3)

outputs:

global phase: -π
     ┌─────────┐┌──────────┐                       ┌─────────┐┌──────────┐»
q_0: ┤ Ry(π/2) ├┤ Ry(-π/2) ├─────────────■─────────┤ Ry(π/2) ├┤ Ry(-π/2) ├»
     └┬────────┤├──────────┤┌──────────┐ │ZZ(-0.3) ├─────────┤└┬────────┬┘»
q_1: ─┤ Rz(-π) ├┤ Ry(-π/2) ├┤ Ry(-π/2) ├─■─────────┤ Ry(π/2) ├─┤ Rz(-π) ├─»
      └────────┘└──────────┘└──────────┘           └─────────┘ └────────┘ »
«                 
«q_0: ────────────
«     ┌──────────┐
«q_1: ┤ Ry(-π/2) ├
«     └──────────┘

This algorithm should be added to the unitary synthesis tranpiler pass (#13320).
Then I think that this issues will be solved. Note that the redundant 1q gates should be eliminated by the 1q synthesis transpiler passes.

@ShellyGarion
Copy link
Member

Is this issue limited to the rzz gates and not other gates like ryy rzx etc.?

@melechlapson -
Note that the synthesis algorithm TwoQubitControlledUDecomposer suggested above works also for gates like RYY, RZX, RXX etc. that are equivalent to an RZZ up to 1q-unitary gates.

@t-imamichi
Copy link
Member Author

Thank you for your information, @ShellyGarion. I would like to use the algorithm as a transpiler pass. So I wait for #13320.

@t-imamichi
Copy link
Member Author

Thank you, @ShellyGarion. It looks great.
I tried it with ibm_torino, but it could not merge two RZZ as follows.
Do you have any idea to apply the new pass for a real backend with the fractional gates?

from qiskit import QuantumCircuit, __version__, generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

print(__version__, "\n")
service = QiskitRuntimeService(name="primitives")
backend = service.backend("ibm_torino", use_fractional_gates=True)
target = backend.target

qc = QuantumCircuit(2)
qc.rzz(0.1, 0, 1)
qc.rzz(0.2, 0, 1)

pm = generate_preset_pass_manager(optimization_level=2, target=target)
tqc = pm.run(qc)
print(backend.configuration().basis_gates)
print(tqc.draw(idle_wires=False), "\n")
2.0.0.dev0+f82aa0a

['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']

q_0 -> 87 ─■─────────■────────
           │ZZ(0.1)  │ZZ(0.2)
q_1 -> 88 ─■─────────■────────

I found that the existence of 'cz' in the basis gates prevents the merge as follows.

from qiskit import QuantumCircuit, __version__, generate_preset_pass_manager

print(__version__, "\n")

qc = QuantumCircuit(2)
qc.rzz(0.1, 0, 1)
qc.rzz(0.2, 0, 1)

for basis_gates in [["rz", "rzz", "rx"], ["rz", "rzz", "rx", "cz"]]:
    pm = generate_preset_pass_manager(optimization_level=2, basis_gates=basis_gates)
    tqc = pm.run(qc)
    print(basis_gates)
    print(tqc.draw(idle_wires=False), "\n")
2.0.0.dev0+f82aa0a

['rz', 'rzz', 'rx']
global phase: π

q_0: ──────────■──────────────────
     ┌───────┐ │ZZ(-0.3) ┌───────┐
q_1: ┤ Rx(π) ├─■─────────┤ Rx(π) ├
     └───────┘           └───────┘

['rz', 'rzz', 'rx', 'cz']

q_0: ─■─────────■────────
      │ZZ(0.1)  │ZZ(0.2)
q_1: ─■─────────■────────

@ShellyGarion
Copy link
Member

Thanks @t-imamichi for checking this! This PR should fix it #13958 (and it will hopefully be merged in time for 2.0).

@t-imamichi
Copy link
Member Author

t-imamichi commented Mar 11, 2025

@ShellyGarion I see #12850 might make a regression. Could you check it?

before #12850 (65d041b)

2.0.0.dev0+65d041b

['rz', 'rzz', 'rx']
global phase: π

q_0: ──────────■──────────────────
     ┌───────┐ │ZZ(-0.3) ┌───────┐
q_1: ┤ Rx(π) ├─■─────────┤ Rx(π) ├
     └───────┘           └───────┘

['rz', 'rzz', 'rx', 'cz']
global phase: π

q_0: ──────────■──────────────────
     ┌───────┐ │ZZ(-0.3) ┌───────┐
q_1: ┤ Rx(π) ├─■─────────┤ Rx(π) ├
     └───────┘           └───────┘

after #12850 (246f5f3)

2.0.0.dev0+246f5f3

['rz', 'rzz', 'rx']
global phase: π

q_0: ──────────■──────────────────
     ┌───────┐ │ZZ(-0.3) ┌───────┐
q_1: ┤ Rx(π) ├─■─────────┤ Rx(π) ├
     └───────┘           └───────┘

['rz', 'rzz', 'rx', 'cz']
global phase: 3π/2
      ┌───────┐                  ┌───────┐                ┌────────┐ ┌────────┐
q_0: ─┤ Rz(π) ├───────────────■──┤ Rx(π) ├─────────────■──┤ Rx(-π) ├─┤ Rz(-π) ├
     ┌┴───────┴─┐┌──────────┐ │ ┌┴───────┴┐┌─────────┐ │ ┌┴────────┴┐├────────┤
q_1: ┤ Rx(-π/2) ├┤ Rz(-π/2) ├─■─┤ Rx(0.3) ├┤ Rz(π/2) ├─■─┤ Rx(-π/2) ├┤ Rz(-π) ├
     └──────────┘└──────────┘   └─────────┘└─────────┘   └──────────┘└────────┘

script

from qiskit import QuantumCircuit, __version__, generate_preset_pass_manager

print(__version__, "\n")

qc = QuantumCircuit(2)
qc.rzz(0.1, 0, 1)
qc.rzz(0.2, 0, 1)

for basis_gates in [["rz", "rzz", "rx"], ["rz", "rzz", "rx", "cz"]]:
    pm = generate_preset_pass_manager(optimization_level=2, basis_gates=basis_gates)
    tqc = pm.run(qc)
    print(basis_gates)
    print(tqc.draw(idle_wires=False), "\n")

@ShellyGarion
Copy link
Member

One case that has not been solved yet is the following:

  • the circuit has one CZ gate and one RZZ gate
  • the target has basis gates containing 'cz' and 'rzz'.

In this case, the circuit would not get consolidated and re-synthesized into a single RZZ gate.
I'm not sure that I have a quick fix for this, but hope that it would be solved in #13419.

       basis_gates = ["rzz", "rx", "rz", "cz"]
        qc = QuantumCircuit(2)
        qc.rzz(0.1, 0, 1)
        qc.cz(0, 1)
        consolidate_pass = ConsolidateBlocks(basis_gates=basis_gates)
        res = consolidate_pass(qc)
        pm = generate_preset_pass_manager(optimization_level=2, basis_gates=basis_gates)
        tqc = pm.run(qc)
        print (res)
        print (tqc)

outputs:


q_0: ─■─────────■─
      │ZZ(0.1)  │ 
q_1: ─■─────────■─
                  
                  
q_0: ─■─────────■─
      │ZZ(0.1)  │ 
q_1: ─■─────────■─

@t-imamichi
Copy link
Member Author

Thank you for your information. I wait for #13419.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mod: transpiler Issues and PRs related to Transpiler type: feature request New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants