I was reading the O2/O3 pipeline and found two separate problems in
gate-decomposition. They are independent of each other, but both are in the same
file, so I am putting them in one issue.
First one: the original gate is never removed.
#dialect quantum
module @m {
func @f(%q0: qubit) -> qubit {
%a = "quantum.t"(%q0) : (qubit) -> qubit
return %a
}
}
Running GateDecomposition::new(Provider::IbmEagle) on that:
before: ["t"]
after: ["t", "rz(0.785398)"]
The new rz is not dangling, it is wired into the chain:
block: ["quantum.rz", "quantum.t", "core.return"]
quantum.rz inputs=[1v1] results=[3v1]
quantum.t inputs=[3v1] results=[2v1]
So the circuit becomes Rz(pi/4) and then T. Checking the matrices, T . Rz(pi/4)
is S up to global phase, so a T gate turns into an S gate. This is not specific
to T. gate_decompose.rs has no ops.remove and no retain anywhere in it, so
nothing is ever deleted and every decomposition doubles.
test_ibm_decomposes_h does not catch it because it asserts that rz, sx and cx
are present, and never that quantum.h is gone.
Second one: the RX sequence has a sign error, and RX(0) compiles to Z.
Around line 231 the emitted sequence is, in circuit order:
rz(-pi/2), sx, rz(pi + theta), sx, rz(pi/2)
I compared that against RX(theta) up to global phase for theta in
{0, 0.3, 1.0, pi/2, pi, 2.2, -0.7, 3.9}. It does not match at any of them.
Changing the first rotation to rz(+pi/2) matches at all of them.
The clearest case is theta = 0, which should be the identity:
RX(0) as emitted, normalised by global phase:
[[1, 0],
[0, -1]]
which is Z, not I.
The comment above that arm gives two different formulas, one with six gates and
one with five. That may be where the sign was lost.
One thing that changes how urgent this is, so I would rather say it than leave it
out: through the CLI this pass currently does nothing. GateDecomposition::default()
resolves the provider from a lift_provider metadata key, and as far as I can tell
nothing in the repo ever writes that key, so it falls back to Provider::Simulator
and the pass returns Unchanged. Both problems above show up when the pass is built
with an explicit provider, which is what GateDecomposition::new is for.
Built from 9ca5a92, tagged v0.4.4.
I was reading the O2/O3 pipeline and found two separate problems in
gate-decomposition. They are independent of each other, but both are in the same
file, so I am putting them in one issue.
First one: the original gate is never removed.
Running GateDecomposition::new(Provider::IbmEagle) on that:
The new rz is not dangling, it is wired into the chain:
So the circuit becomes Rz(pi/4) and then T. Checking the matrices, T . Rz(pi/4)
is S up to global phase, so a T gate turns into an S gate. This is not specific
to T. gate_decompose.rs has no ops.remove and no retain anywhere in it, so
nothing is ever deleted and every decomposition doubles.
test_ibm_decomposes_h does not catch it because it asserts that rz, sx and cx
are present, and never that quantum.h is gone.
Second one: the RX sequence has a sign error, and RX(0) compiles to Z.
Around line 231 the emitted sequence is, in circuit order:
I compared that against RX(theta) up to global phase for theta in
{0, 0.3, 1.0, pi/2, pi, 2.2, -0.7, 3.9}. It does not match at any of them.
Changing the first rotation to rz(+pi/2) matches at all of them.
The clearest case is theta = 0, which should be the identity:
The comment above that arm gives two different formulas, one with six gates and
one with five. That may be where the sign was lost.
One thing that changes how urgent this is, so I would rather say it than leave it
out: through the CLI this pass currently does nothing. GateDecomposition::default()
resolves the provider from a lift_provider metadata key, and as far as I can tell
nothing in the repo ever writes that key, so it falls back to Provider::Simulator
and the pass returns Unchanged. Both problems above show up when the pass is built
with an explicit provider, which is what GateDecomposition::new is for.
Built from 9ca5a92, tagged v0.4.4.