Skip to content

Commit b4b855b

Browse files
authored
Support more classical operations in leakage detection circuits. (#697)
1 parent 2dba929 commit b4b855b

2 files changed

Lines changed: 50 additions & 18 deletions

File tree

pytket/extensions/quantinuum/backends/leakage_gadget.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from pytket import Bit, Circuit, OpType, Qubit
1919
from pytket.backends.backendresult import BackendResult
20+
from pytket.circuit import BitRegister
2021
from pytket.utils.outcomearray import OutcomeArray
2122

2223
if TYPE_CHECKING:
@@ -53,7 +54,7 @@ def get_leakage_gadget_circuit(
5354
return c
5455

5556

56-
def get_detection_circuit(circuit: Circuit, n_device_qubits: int) -> Circuit: # noqa: PLR0912
57+
def get_detection_circuit(circuit: Circuit, n_device_qubits: int) -> Circuit: # noqa: PLR0912 PLR0915
5758
"""
5859
For a passed circuit, appends a leakage detection circuit for
5960
each end of circuit measurement using spare device qubits.
@@ -89,22 +90,48 @@ def get_detection_circuit(circuit: Circuit, n_device_qubits: int) -> Circuit: #
8990
# end of Circuit Measure gates
9091
end_circuit_measures: dict[Qubit, Bit] = {}
9192
for com in circuit:
92-
if com.op.type == OpType.Barrier:
93-
detection_circuit.add_barrier(com.args)
93+
op, args = com.op, com.args
94+
if op.type == OpType.Barrier:
95+
detection_circuit.add_barrier(args)
9496
continue
9597
# first check if a mid circuit measure needs to be readded
9698
for q in com.qubits:
9799
# this condition only true if this Qubit has previously had a
98100
# "mid-circuit" measure operation
99101
if q in end_circuit_measures:
100102
detection_circuit.Measure(q, end_circuit_measures.pop(q))
101-
if com.op.type == OpType.Measure:
103+
if op.type == OpType.Measure:
102104
# if this is "mid-circuit" then this will be rewritten later
103105
end_circuit_measures[com.qubits[0]] = com.bits[0]
104-
elif com.op.params:
105-
detection_circuit.add_gate(com.op.type, com.op.params, com.args)
106+
elif op.is_gate():
107+
detection_circuit.add_gate(op.type, op.params, args)
108+
elif op.type == OpType.SetBits:
109+
detection_circuit.add_c_setbits(op.values, args) # type: ignore
110+
elif op.type == OpType.CopyBits:
111+
assert len(args) % 2 == 0
112+
n = len(args) // 2
113+
detection_circuit.add_c_copybits(args[:n], args[n:]) # type: ignore
114+
elif op.type == OpType.ClExpr:
115+
detection_circuit.add_clexpr(op.expr, args) # type: ignore
116+
elif op.type == OpType.RNGSeed:
117+
creg = BitRegister(args[0].reg_name, 64)
118+
detection_circuit.set_rng_seed(creg)
119+
elif op.type == OpType.RNGBound:
120+
creg = BitRegister(args[0].reg_name, 32)
121+
detection_circuit.set_rng_bound(creg)
122+
elif op.type == OpType.RNGIndex:
123+
creg = BitRegister(args[0].reg_name, 32)
124+
detection_circuit.set_rng_index(creg)
125+
elif op.type == OpType.RNGNum:
126+
creg = BitRegister(args[0].reg_name, 32)
127+
detection_circuit.get_rng_num(creg)
128+
elif op.type == OpType.JobShotNum:
129+
creg = BitRegister(args[0].reg_name, 32)
130+
detection_circuit.get_job_shot_num(creg)
106131
else:
107-
detection_circuit.add_gate(com.op.type, com.args)
132+
raise ValueError(
133+
f"Operation type {op.type} not supported in leakage detection circuit."
134+
)
108135

109136
# for each entry in end_circuit_measures, we want to add a leakage_gadget_circuit
110137
# we try to use each free architecture qubit as few times as possible

tests/unit/leakage_detection_test.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from pytket import Bit, Circuit, OpType, Qubit
2222
from pytket.backends.backendresult import BackendResult
23+
from pytket.circuit import BitRegister
2324
from pytket.extensions.quantinuum.backends.leakage_gadget import (
2425
LEAKAGE_DETECTION_BIT_NAME_,
2526
LEAKAGE_DETECTION_QUBIT_NAME_,
@@ -225,14 +226,18 @@ def test_postselection_discard_1() -> None:
225226
assert discard_result[(1, 1)] == 33
226227

227228

228-
if __name__ == "__main__":
229-
test_postselection_circuits_1qb_task_gen()
230-
test_postselection_circuits_2qb_2_spare_task_gen()
231-
test_postselection_circuits_2qb_1_spare_task_gen()
232-
test_postselection_discard_0()
233-
test_postselection_discard_1()
234-
test_postselection_existing_qubit()
235-
test_postselection_existing_bit()
236-
test_postselection_no_qubits()
237-
test_postselection_not_enough_device_qubits_0()
238-
test_postselection_not_enough_device_qubits_1()
229+
def test_classical_ops() -> None:
230+
c = Circuit(2, 2)
231+
c.add_c_register("reg32", 32)
232+
c.add_c_register("reg64", 64)
233+
c.H(0).CX(0, 1)
234+
c.add_c_setbits([True, False], [Bit(0), Bit(1)])
235+
c.add_c_copybits([Bit(0)], [Bit(1)])
236+
c.set_rng_seed(BitRegister("reg64", 64))
237+
c.set_rng_bound(BitRegister("reg32", 32))
238+
c.set_rng_index(BitRegister("reg32", 32))
239+
c.get_rng_num(BitRegister("reg32", 32))
240+
c.get_job_shot_num(BitRegister("reg32", 32))
241+
c.measure_all()
242+
c_d = get_detection_circuit(c, 100)
243+
assert c_d.n_qubits == 4

0 commit comments

Comments
 (0)