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.13k stars 2.35k forks source link

Circuit transpilation generates imaginary angles on random circuits #10534

Open Sola85 opened 1 year ago

Sola85 commented 1 year ago

Environment

What is happening?

Transpilation fails with a CircuitError: "Invalid param type <class 'complex'> for gate ry."

How can we reproduce the issue?

from qiskit import transpile
from qiskit.circuit.random.utils import random_circuit

qc = random_circuit(num_qubits=5, depth=10, reset=False, seed=0)
qc = transpile(qc, basis_gates=["id", "rx", "ry", "cx"], optimization_level=3)

What should happen?

Transpilations succeeds

Any suggestions?

No response

jakelishman commented 1 year ago

This is a pretty weird one, thanks. For others, this is a more minimal reproducer:

from qiskit import QuantumCircuit
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary
from qiskit.circuit.library import XXPlusYYGate
from qiskit.transpiler.passes import BasisTranslator

qc = QuantumCircuit(2)
qc.append(XXPlusYYGate(0.5, 0.5), [0, 1])
pass_ = BasisTranslator(SessionEquivalenceLibrary, ["rx", "ry", "cx"])
pass_(qc)

I suspect that the root cause for us is an issue in symengine that can introduce spurious imaginary components when it encounters powers of numbers in a context that it cannot prove is fully real, in which case it's going to be tricky for us to fix in the near term, because we have very little control over how symengine decides to represent its expressions.

The issue is showing itself when using XXPlusYYGate, but it's not really the culprit itself. It's just that the particular basis translation path from that gate to the ["rx", "ry", "cx"] basis happens to give symengine problems. If you're able to use a basis that includes rz, that should step around the bug. Alternatively, and a bit more arcanely, if you run this at the start of your Python session, it'll also work around the bug:

from math import pi

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary
from qiskit.circuit.library import XXPlusYYGate

a, b = Parameter("a"), Parameter("b")

qc = QuantumCircuit(2)
qc.rx(pi / 2, 0)
qc.ry(-b - pi / 2, 0)
qc.rx(-pi / 2, 0)
qc.ry(pi/2, 1)
qc.cx(1, 0)
qc.ry(-a/2, 0)
qc.ry(-a/2, 1)
qc.cx(1, 0)
qc.rx(pi/2, 0)
qc.ry(b + pi/2, 0)
qc.rx(-pi/2, 0)
qc.ry(-pi/2, 1)
SessionEquivalenceLibrary.add_equivalence(XXPlusYYGate(a, b), qc)
galeinston commented 1 year ago

@jakelishman I would like to work on this issue. Please assign this to me. Thank you!

jakelishman commented 1 year ago

Thanks @galeinston: I can assign you. There's really not a clear general-solution path forwards with regards to how symengine can sometimes spurious imaginary components to enter when evaluating complex powers.

For the immediate problem at hand, it might be sufficient to add the equivalence rule I wrote out above to the StandardEquivalenceLibrary that Qiskit maintains, and probably a similar one for XXMinusYYGate.

galeinston commented 1 year ago

@jakelishman thanks for the pointer. I'll start with your suggestion and see if there's anything else to improve