Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.28k stars 2.37k forks source link

Circuits optimised on transpile level >= 2 are not equivalent #10928

Closed lmondada closed 1 year ago

lmondada commented 1 year ago

Environment

What is happening?

When optimising the circuit below using optimization_level=2 or optimization_level=3 with target gate set basis_gates=['cx', 'u3'], the result is not equivalent to the input.

Input circuit

q_0: ─■───────────────■─
      │ ┌───┐   ┌───┐ │ 
q_1: ─■─┤ H ├─■─┤ H ├─■─
        └───┘ │ └───┘   
q_2: ─────────■─────────

Output circuit:

q_0: ─────────────────────────────────────
     ┌──────────────┐     ┌──────────────┐
q_1: ┤ U3(π/2,0,-π) ├──■──┤ U3(π/2,0,-π) ├
     ├─────────────┬┘┌─┴─┐├─────────────┬┘
q_2: ┤ U3(π/2,0,π) ├─┤ X ├┤ U3(π/2,0,π) ├─
     └─────────────┘ └───┘└─────────────┘ 

How can we reproduce the issue?

The following code outputs "Circuits are not equivalent".

import numpy as np
from qiskit import transpile, QuantumCircuit
import qiskit.quantum_info as qi

circ = QuantumCircuit(3)
circ.cz(0, 1)
circ.h(1)
circ.cz(1, 2)
circ.h(1)
circ.cz(0, 1)

# optimisation
opt_circ = transpile(circ, optimization_level=2, basis_gates=["cx", "u3"])

# check equivalence
def get_unitary(circ):
    op = qi.Operator(circ)
    return np.matrix(op.data)

u = get_unitary(circ)
u_opt = get_unitary(opt_circ)

u_uinv = u * u_opt.H
# fix global phase
u_uinv /= u_uinv[0, 0]

if np.isclose(u_uinv, np.eye(2**circ.num_qubits)).all():
    print("Circuits are equivalent")
else:
    print("Circuits are not equivalent")

What should happen?

The code should output Circuits are equivalent.

Any suggestions?

This only applies to gate sets including the u3 gate. Compiling to e.g. ['cx', 'rz', 'sx', 'x'] does not have this problem.

jakelishman commented 1 year ago

Sorry for the slow reply - I suspect that this is the same issue that #10618 is fixing. Sasha (@alexanderivrii), could you check, and mark your PR as closing this issue if so?

alexanderivrii commented 1 year ago

@jakelishman, you are correct, #10618 does indeed fix this!

At first I did not understand why, since neither CZ(0, 1) nor CZ(1, 2) commutes with H(1), but here is the longer story.

First, BasisTranslator replaces each CZ(a, b) by H(b) CX(a, b) H(b) (and to be pedantic, it's actually U3(pi/2, 0, \pi) rather than H), leading to the circuit H(2) H(1) CX(0, 1) H(1) H(1) CX(1, 2) H(1) H(1) CX(0, 1) H(1) H(2). Note the two pairs of consecutive H-gates in the middle (in each pair one H-gate comes from basis translation and the other H has already been there from the start).

Second, Optimize1qGatesDecomposition combines each pair of consecutive H-gates into "an almost identity" gate (because of the round-off errors it's not exactly identity and is represented by some U3 gate which is very close to identity).

But now we almost have the buggy example from #10618. For all practical purposes the "almost identity" gates commute with any other gates, leading to incorrect detection of pairwise commuting gates and hence incorrect cancellations.