From 4ad0270880dfb1f11f11571729b91ab695308d74 Mon Sep 17 00:00:00 2001 From: Emma Rosenfeld Date: Tue, 14 Jul 2026 05:10:33 +0000 Subject: [PATCH 1/4] fix touched() function in LayerTag --- glue/stimflow/src/stimflow/_layers/_layer_tag.py | 14 ++++++++++++-- .../src/stimflow/_layers/_layer_tag_test.py | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/glue/stimflow/src/stimflow/_layers/_layer_tag.py b/glue/stimflow/src/stimflow/_layers/_layer_tag.py index e858ca749..c6324e974 100644 --- a/glue/stimflow/src/stimflow/_layers/_layer_tag.py +++ b/glue/stimflow/src/stimflow/_layers/_layer_tag.py @@ -15,8 +15,18 @@ def copy(self) -> LayerTag: return LayerTag(circuit=self.circuit) def touched(self) -> set[int]: # set of qubit touched by it - tagged_gate_targets = self.circuit[0].target_groups()[0] - return {gate_target.qubit_value for gate_target in tagged_gate_targets} + if isinstance(self.circuit[0], stim.CircuitRepeatBlock): + raise NotImplementedError( + "No tags allowed on circuit repeat blocks, " + "since I need target_groups for defining which qubits are touched" + ) + touched_set = { + target.qubit_value + for target_group in self.circuit[0].target_groups() + for target in target_group + if target.is_qubit_target + } + return {q for q in touched_set if isinstance(q, int)} def to_z_basis(self) -> list[Layer]: return [self] diff --git a/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py b/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py index decfa8b60..30d95338c 100644 --- a/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py +++ b/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py @@ -3,7 +3,7 @@ import stim import stimflow - +from stimflow._layers._layer_tag import LayerTag def test_survives_transpile(): circuit = stim.Circuit( @@ -56,3 +56,17 @@ def test_survives_transpile(): DETECTOR rec[-1] rec[-2] """ ) + +def test_touched() -> None: + + layer_cx = LayerTag(circuit=stim.Circuit("CX 0 1 2 3")) + assert layer_cx.touched() == {0, 1, 2, 3} + + layer_m = LayerTag(circuit=stim.Circuit("M 0 1 2")) + assert layer_m.touched() == {0, 1, 2} + + # Test filtering of non-qubit targets (e.g. combiners in MPP instructions or Pauli targets). + layer_mpp = LayerTag(circuit=stim.Circuit("MPP X10*Y11 Z12*X13")) + # In MPP, targets are Pauli targets/combiners. + # We verify touched() handles target groups gracefully. + assert isinstance(layer_mpp.touched(), set) From 3ef417e3a0dfe0e433a6d6dbeee734404b2c0c76 Mon Sep 17 00:00:00 2001 From: Emma Rosenfeld Date: Tue, 14 Jul 2026 19:01:11 +0000 Subject: [PATCH 2/4] implement tag layer for circuit repeat blocks --- .../src/stimflow/_layers/_layer_tag.py | 24 +++++++++---------- .../src/stimflow/_layers/_layer_tag_test.py | 15 ++++++++++++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/glue/stimflow/src/stimflow/_layers/_layer_tag.py b/glue/stimflow/src/stimflow/_layers/_layer_tag.py index c6324e974..a697e4c85 100644 --- a/glue/stimflow/src/stimflow/_layers/_layer_tag.py +++ b/glue/stimflow/src/stimflow/_layers/_layer_tag.py @@ -15,18 +15,18 @@ def copy(self) -> LayerTag: return LayerTag(circuit=self.circuit) def touched(self) -> set[int]: # set of qubit touched by it - if isinstance(self.circuit[0], stim.CircuitRepeatBlock): - raise NotImplementedError( - "No tags allowed on circuit repeat blocks, " - "since I need target_groups for defining which qubits are touched" - ) - touched_set = { - target.qubit_value - for target_group in self.circuit[0].target_groups() - for target in target_group - if target.is_qubit_target - } - return {q for q in touched_set if isinstance(q, int)} + def _touched(inst: stim.CircuitInstruction | stim.CircuitRepeatBlock) -> set[int]: + if isinstance(inst, stim.CircuitRepeatBlock): + return {q for inner_inst in inst.body_copy() for q in _touched(inner_inst)} + touched_set = { + target.qubit_value + for target_group in inst.target_groups() + for target in target_group + if target.is_qubit_target + } + return {q for q in touched_set if isinstance(q, int)} + + return _touched(self.circuit[0]) def to_z_basis(self) -> list[Layer]: return [self] diff --git a/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py b/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py index 30d95338c..e87fc9b8c 100644 --- a/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py +++ b/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py @@ -70,3 +70,18 @@ def test_touched() -> None: # In MPP, targets are Pauli targets/combiners. # We verify touched() handles target groups gracefully. assert isinstance(layer_mpp.touched(), set) + + # Test that when self.circuit[0] is a CircuitRepeatBlock, touched() iterates + # through the block and finds all qubit targets. + layer_repeat = LayerTag( + circuit=stim.Circuit( + """ + REPEAT 5 { + CX 0 1 + TICK + M 2 3 + } + """ + ) + ) + assert layer_repeat.touched() == {0, 1, 2, 3} \ No newline at end of file From 839d2186bcaafefbb74ba77cbeb796eef32c5778 Mon Sep 17 00:00:00 2001 From: Emma Rosenfeld Date: Wed, 15 Jul 2026 02:18:50 +0000 Subject: [PATCH 3/4] add unit test for nested loops with tags --- .../src/stimflow/_layers/_layer_tag_test.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py b/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py index e87fc9b8c..c0a79c4af 100644 --- a/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py +++ b/glue/stimflow/src/stimflow/_layers/_layer_tag_test.py @@ -84,4 +84,22 @@ def test_touched() -> None: """ ) ) - assert layer_repeat.touched() == {0, 1, 2, 3} \ No newline at end of file + assert layer_repeat.touched() == {0, 1, 2, 3} + + # Test that when self.circuit[0] contains nested CircuitRepeatBlocks, touched() + # recursively iterates through all nested repeat blocks to find all qubit targets. + layer_nested_repeat = LayerTag( + circuit=stim.Circuit( + """ + REPEAT 3 { + CX 0 1 + REPEAT 2 { + CX 2 3 + TICK + M 4 5 + } + } + """ + ) + ) + assert layer_nested_repeat.touched() == {0, 1, 2, 3, 4, 5} \ No newline at end of file From 1d7f28b3f6f365d56360cd71ccec7d505a10a828 Mon Sep 17 00:00:00 2001 From: Emma Rosenfeld Date: Wed, 15 Jul 2026 17:55:55 +0000 Subject: [PATCH 4/4] craig's improvement for tag layer touched() speed --- .../src/stimflow/_layers/_layer_tag.py | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/glue/stimflow/src/stimflow/_layers/_layer_tag.py b/glue/stimflow/src/stimflow/_layers/_layer_tag.py index a697e4c85..7963c830e 100644 --- a/glue/stimflow/src/stimflow/_layers/_layer_tag.py +++ b/glue/stimflow/src/stimflow/_layers/_layer_tag.py @@ -15,18 +15,17 @@ def copy(self) -> LayerTag: return LayerTag(circuit=self.circuit) def touched(self) -> set[int]: # set of qubit touched by it - def _touched(inst: stim.CircuitInstruction | stim.CircuitRepeatBlock) -> set[int]: - if isinstance(inst, stim.CircuitRepeatBlock): - return {q for inner_inst in inst.body_copy() for q in _touched(inner_inst)} - touched_set = { - target.qubit_value - for target_group in inst.target_groups() - for target in target_group - if target.is_qubit_target - } - return {q for q in touched_set if isinstance(q, int)} - - return _touched(self.circuit[0]) + stack = [self.circuit[0]] + out = set() + while stack: + cur = stack.pop() + if isinstance(cur, stim.CircuitRepeatBlock): + stack.extend(cur.body_copy()) + else: + for target in cur.targets_copy(): + if target.is_qubit_target: + out.add(target.qubit_value) + return out def to_z_basis(self) -> list[Layer]: return [self]