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.05k stars 2.33k forks source link

Transpiler fails for QFT for optimization level 3 #10708

Closed jli0108 closed 1 year ago

jli0108 commented 1 year ago

Environment

What is happening?

The Qiskit transpiler seems to give incorrect circuits for the QFT when the optimization level is set to 3.

How can we reproduce the issue?

Minimal working example provided here:

import numpy as np

from qiskit import transpile
from qiskit.quantum_info import Operator
from qiskit.circuit.library import QFT

n = 6
N = 2 ** n

# Qiskit QFT should be the same as numpy IFFT
circuit = QFT(n)
IFFT = np.fft.ifft(np.eye(N), N, norm="ortho")

for i in range(4):
    compiled_circuit = transpile(circuit, optimization_level=i)
    fidelity = np.abs(np.trace(Operator(compiled_circuit).to_matrix() @ np.conj(IFFT.T))) / N
    print(f"(Optimization level {i}) Fidelity: {fidelity}")

    if fidelity > 0.99:
        print("Good.")
    else:
        print("Bad.")

Output:

(Optimization level 0) Fidelity: 0.9999999999999999
Good.
(Optimization level 1) Fidelity: 0.9999999999999999
Good.
(Optimization level 2) Fidelity: 0.9999999999999999
Good.
(Optimization level 3) Fidelity: 0.12499999999999997
Bad.

What should happen?

The Qiskit transpiler is supposed to give a correct circuit even if the optimization level is set to 3.

Any suggestions?

No response

Cryoris commented 1 year ago

The optimization level 3 removes swaps at the end of a circuit or before a measurement, as they can be implemented as a classical postprocessing on the measurements. The QFT has such a final layer of swaps which is removed in optimization level 3.

You can verify the circuit is still correct, either by re-ordering the entries in the IFFT matrix, or by re-inserting the swaps:

for i in range(4):
    compiled_circuit = transpile(circuit, optimization_level=i)
    # insert swaps for the check
    if i == 3:
        for j in range(n // 2):
            compiled_circuit.swap(j, n - j - 1)

    fidelity = np.abs(np.trace(Operator(compiled_circuit).to_matrix() @ np.conj(IFFT.T))) / N
    print(f"(Optimization level {i}) Fidelity: {fidelity}")

    if fidelity > 0.99:
        print("Good.")
    else:
        print("Bad.")
jli0108 commented 1 year ago

I see, thanks for the clarification. I didn't know about this. I'll close the issue.