From 3bd49a471233baccee99caef003eabfe06b31837 Mon Sep 17 00:00:00 2001 From: Manideep3969 Date: Wed, 19 Aug 2026 16:10:12 +0530 Subject: [PATCH] fix(#45): structural batching uses device qubit count for non-overlapping placement _structural_batch used set(range(circuit.num_qubits)) to track qubit usage, making any two same-size circuits always overlap. On a 127-qubit device, four 3-qubit circuits should batch together. Fix: Track cumulative qubit count against max_qubits instead of checking virtual qubit set overlap. Circuits are now batched as long as total qubits fit within the device capacity. --- src/qc_compiler/batching.py | 14 ++++++++------ tests/test_batching.py | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/qc_compiler/batching.py b/src/qc_compiler/batching.py index 4919c09..ebd2829 100644 --- a/src/qc_compiler/batching.py +++ b/src/qc_compiler/batching.py @@ -218,7 +218,9 @@ def _structural_batch( """Batch circuits with same depth on non-overlapping qubit subsets. Circuits using different qubits of the same device can run - in parallel, maximizing qubit utilization. + in parallel, maximizing qubit utilization. Uses the device's + total qubit count (max_qubits) to determine how many circuits + can be placed without overlapping. Args: circuits: List of quantum circuits. @@ -240,22 +242,22 @@ def _structural_batch( batch_sizes = [] for depth, indices in depth_groups.items(): - current_batch_qubits = set() current_batch = [] + total_qubits_used = 0 for idx in indices: circuit = circuits[idx] - circuit_qubits = set(range(circuit.num_qubits)) + n_qubits = circuit.num_qubits - if not current_batch_qubits & circuit_qubits: + if total_qubits_used + n_qubits <= self.max_qubits: current_batch.append(circuit) - current_batch_qubits |= circuit_qubits + total_qubits_used += n_qubits else: if current_batch: batches.append(current_batch) batch_sizes.append(len(current_batch)) current_batch = [circuit] - current_batch_qubits = circuit_qubits.copy() + total_qubits_used = n_qubits if current_batch: batches.append(current_batch) diff --git a/tests/test_batching.py b/tests/test_batching.py index 3935b9c..3cea4da 100644 --- a/tests/test_batching.py +++ b/tests/test_batching.py @@ -318,4 +318,38 @@ def test_estimate_speedup_empty_groups(self, batcher): def test_estimate_structural_speedup_empty(self, batcher): speedup = batcher._estimate_structural_speedup([], []) - assert speedup == 1.0 \ No newline at end of file + assert speedup == 1.0 + + +class TestStructuralBatchingDeviceQubits: + """Regression tests for structural batching with device qubit count (issue #45).""" + + def test_same_size_circuits_can_be_batched_on_large_device(self): + batcher = CircuitBatcher(cost_model=CostModel(), max_qubits=127) + circuits = [QuantumCircuit(3) for _ in range(4)] + for qc in circuits: + qc.h(0) + qc.cx(0, 1) + qc.cx(1, 2) + plan = batcher.create_batch_plan(circuits, strategy="structural") + assert plan.num_batches >= 1 + assert plan.total_circuits == 4 + + def test_small_circuits_batch_together_on_device(self): + batcher = CircuitBatcher(cost_model=CostModel(), max_qubits=10) + circuits = [QuantumCircuit(3) for _ in range(3)] + for qc in circuits: + qc.h(0) + qc.cx(0, 1) + plan = batcher.create_batch_plan(circuits, strategy="structural") + assert plan.total_circuits == 3 + + def test_circuits_exceeding_device_capacity_split_into_batches(self): + batcher = CircuitBatcher(cost_model=CostModel(), max_qubits=5) + circuits = [QuantumCircuit(3) for _ in range(4)] + for qc in circuits: + qc.h(0) + qc.cx(0, 1) + plan = batcher.create_batch_plan(circuits, strategy="structural") + assert plan.total_circuits == 4 + assert plan.num_batches >= 2 \ No newline at end of file