Commit 5d78070
authored
Fix handling of custom gates named unitary in Split2qUnitaries (Qiskit#14108)
Normally creating a custom gate class that overloads the name of a
Qiskit defined operation is not valid and not allowed. The names have
meaning and are often used as identifiers and this overloading the name
will prevent Qiskit from correctly identifying an operation. However as
was discovered in Qiskit#14103 there are some paths available around
serialization and I/O where Qiskit does this itself. For example, qasm
(both 2 and 3) is a lossy serialization format and qasm2 doesn't have a
representation of a UnitaryGate. So when the qasm2 exporter encounteres
a `UnitaryGate` it is serialized as a custom gate definition with the
name "unitary" in the output qasm2 and the definition is a decomposition
of the unitary from the `UnitaryGate`. When that qasm2 program is
subsequently deserialized by qiskit parser the custom gate named "unitary"
is added as a `_DefinedGate` subclass which includes an `__array__`
implementation which computes the unitary from the definition using
the quantum info Operator class. This makes the custom gate parsed from
qasm2 look like a `UnitaryGate` despite not actually one so this is
typically fine for most use cases. However, if you then qpy serialize
the circuit that contains a custom `_DefinedGate` instance that's named
"unitary", QPY doesn't understand what `_DefinedGate` is and assumes that
it can not fully recreate it because it's outside the standard Qiskit data
model. In these cases qpy serializes the fields from the standard data
model defined in Qiskit which it knows about: name, params, definition, etc
and encodes that as a custom gate. When deserializing that custom gate it
populates the standard fields, but anything defined outside of that is
lost through the serialization because it's defined outside of Qiskit.
This means the custom `__array__` implementation is missing from the
qpy round-tripped, previously qasm2 round-tripped, `UnitaryGate`
instance in a circuit. This was then causing the transpiler to panic
(which is a hard crash) in the Split2QUnitaries pass because when it saw
a gate named "unitary" it rightly assumed it was a `UnitaryGate` and
there is always a matrix available (because a `UnitaryGate` is a gate
defined solely by it's matrix). This is an example of why overloading
gate names is typically not allowed and is considered invalid usage of
Qiskit. However, in this case since the resulting gate came from valid
use of Qiskit's API trying to ensure the circuit doesn't hard crash the
transpiler is correct here because it's a result in internal
inconsistencies in Qiskit. Treating the twice round-tripped UnitaryGate
as the original unitary gate is not possible because of the loss of
information via serialization, but qiskit should at least not have
an internal panic!() because of this usage.
Arguably we could fix this in QPY by adding either a matrix field to the
format specification for custom gates, or adding handling for
`_DefinedGate` to qpy. But either will require a new format version
which is not eligble for backport to 1.4.x. So this commit fixes this
issue by updating the transpiler pass in question to just treat the
matrix of a gate named unitary as fallible, and we just ignore the
custom gate named unitary that's missing a matrix.
This already been fixed on main and stable/2.0 as a side effect of
PR Qiskit#13765 which made the typing around UnitaryGate in rust more
explicit. So the custom deserialized gate from QPY which doesn't have a
matrix defined is never treated as a unitary gate and even through the
qasm2 round trip followed by a qpy round trip we don't encounter any
issues.
Fixes Qiskit#141031 parent 2df128f commit 5d78070
File tree
3 files changed
+49
-9
lines changed- crates/accelerate/src
- test/python/transpiler
3 files changed
+49
-9
lines changedSome generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| |||
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| 30 | + | |
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
| |||
266 | 268 | | |
267 | 269 | | |
268 | 270 | | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
0 commit comments