Skip to content

Commit 86a5325

Browse files
Fix UnitarySynthesis for 3+ qubits when compiled for a backend (#13591)
* Fix unitary synthesis for 3+ q * Update releasenotes/notes/fix-unitary-synthesis-3q-2b2de5305bfd11ff.yaml Co-authored-by: Alexander Ivrii <[email protected]> * add more tests * use == over equiv --------- Co-authored-by: Alexander Ivrii <[email protected]>
1 parent 0eeba0d commit 86a5325

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

crates/accelerate/src/unitary_synthesis.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,8 @@ fn py_run_main_loop(
372372
None,
373373
None,
374374
)?;
375-
out_dag = synth_dag;
375+
let out_qargs = dag.get_qargs(packed_instr.qubits);
376+
apply_synth_dag(py, &mut out_dag, out_qargs, &synth_dag)?;
376377
}
377378
}
378379
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
fixes:
3+
- |
4+
Fixed a bug in the :class:`.UnitarySynthesis` transpiler pass, where blocks of
5+
:class:`.UnitaryGate`\s on 3 qubits or more were not correctly synthesized.
6+
This led, e.g., to the circuit being overwritten with the last processed block or
7+
to internal panics when encountering measurements after such a block.
8+
Fixed `#13586 <https://github.com/Qiskit/qiskit/issues/13586>`__.

test/python/transpiler/test_unitary_synthesis.py

+51
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@
5757
RYYGate,
5858
RZZGate,
5959
RXXGate,
60+
PauliEvolutionGate,
6061
)
62+
from qiskit.quantum_info import SparsePauliOp
6163
from qiskit.circuit import Measure
6264
from qiskit.circuit.controlflow import IfElseOp
6365
from qiskit.circuit import Parameter, Gate
@@ -1050,6 +1052,55 @@ def test_qsd(self, opt):
10501052
qc_transpiled = transpile(qc, target=target, optimization_level=opt)
10511053
self.assertTrue(np.allclose(mat, Operator(qc_transpiled).data))
10521054

1055+
def test_3q_with_measure(self):
1056+
"""Test 3-qubit synthesis with measurements."""
1057+
backend = FakeBackend5QV2()
1058+
1059+
qc = QuantumCircuit(3, 1)
1060+
qc.unitary(np.eye(2**3), range(3))
1061+
qc.measure(0, 0)
1062+
1063+
qc_transpiled = transpile(qc, backend)
1064+
self.assertTrue(qc_transpiled.size, 1)
1065+
self.assertTrue(qc_transpiled.count_ops().get("measure", 0), 1)
1066+
1067+
def test_3q_series(self):
1068+
"""Test a series of 3-qubit blocks."""
1069+
backend = GenericBackendV2(5, basis_gates=["u", "cx"])
1070+
1071+
x = QuantumCircuit(3)
1072+
x.x(2)
1073+
x_mat = Operator(x)
1074+
1075+
qc = QuantumCircuit(3)
1076+
qc.unitary(x_mat, range(3))
1077+
qc.unitary(np.eye(2**3), range(3))
1078+
1079+
tqc = transpile(qc, backend, optimization_level=0, initial_layout=[0, 1, 2])
1080+
1081+
expected = np.kron(np.eye(2**2), x_mat)
1082+
self.assertEqual(Operator(tqc), Operator(expected))
1083+
1084+
def test_3q_measure_all(self):
1085+
"""Regression test of #13586."""
1086+
hamiltonian = SparsePauliOp.from_list(
1087+
[("IXX", 1), ("IYY", 1), ("IZZ", 1), ("XXI", 1), ("YYI", 1), ("ZZI", 1)]
1088+
)
1089+
1090+
qc = QuantumCircuit(3)
1091+
qc.x([1, 2])
1092+
op = PauliEvolutionGate(hamiltonian, time=1)
1093+
qc.append(op.power(8), [0, 1, 2])
1094+
qc.measure_all()
1095+
1096+
backend = GenericBackendV2(5, basis_gates=["u", "cx"])
1097+
tqc = transpile(qc, backend)
1098+
1099+
ops = tqc.count_ops()
1100+
self.assertIn("u", ops)
1101+
self.assertIn("cx", ops)
1102+
self.assertIn("measure", ops)
1103+
10531104

10541105
if __name__ == "__main__":
10551106
unittest.main()

0 commit comments

Comments
 (0)