diff --git a/src/qc_compiler/scheduling.py b/src/qc_compiler/scheduling.py index 902f477..5779342 100644 --- a/src/qc_compiler/scheduling.py +++ b/src/qc_compiler/scheduling.py @@ -481,9 +481,12 @@ def _get_gate_duration( ) -> int: """Get the duration of a gate in abstract time units. - Uses device calibration data when available. Falls back to - a simple model: single-qubit gates = 1 unit, two-qubit gates - = 3 units (reflecting typical duration ratios on IBM hardware). + Uses device calibration data when available. Looks up the + actual gate duration from gate_lengths and converts it to + abstract units relative to a single-qubit gate. Falls back + to a simple model: single-qubit gates = 1 unit, two-qubit + gates = 3 units (reflecting typical duration ratios on IBM + hardware). Args: gate_name: Name of the gate. @@ -492,6 +495,26 @@ def _get_gate_duration( Returns: Duration in abstract time units. """ + gate_lengths = self.cost_model.device.gate_lengths + + if gate_lengths: + avg_sq_time = DEFAULT_SINGLE_QUBIT_GATE_TIME + + sq_times = [ + v for (g, qs), v in gate_lengths.items() + if len(qs) == 1 + ] + if sq_times: + avg_sq_time = sum(sq_times) / len(sq_times) + + key = (gate_name, tuple(qubits)) + if key in gate_lengths: + return max(1, round(gate_lengths[key] / avg_sq_time)) + + for (g, qs), v in gate_lengths.items(): + if g == gate_name and len(qs) == len(qubits): + return max(1, round(v / avg_sq_time)) + if qubits and len(qubits) >= 2: return 3 return 1 diff --git a/tests/test_scheduling.py b/tests/test_scheduling.py index 726e135..883d3af 100644 --- a/tests/test_scheduling.py +++ b/tests/test_scheduling.py @@ -442,4 +442,52 @@ def test_alap_produces_different_schedule_than_asap(self, scheduler): assert asap_result.method == "asap" assert alap_result.method == "alap" - assert asap_result.method != alap_result.method \ No newline at end of file + assert asap_result.method != alap_result.method + + +class TestGateDurationCalibration: + """Regression tests for gate duration from device calibration (issue #57).""" + + def test_gate_duration_uses_device_data(self): + from qc_compiler.cost_model import DeviceCharacterization + + device = DeviceCharacterization( + backend_name="test", + num_qubits=2, + gate_lengths={ + ("sx", (0,)): 50e-9, + ("sx", (1,)): 60e-9, + ("cx", (0, 1)): 300e-9, + }, + ) + model = CostModel() + model.device = device + scheduler = CoherenceAwareScheduler(cost_model=model) + + assert scheduler._get_gate_duration("sx", [0]) == 1 + assert scheduler._get_gate_duration("sx", [1]) == 1 + assert scheduler._get_gate_duration("cx", [0, 1]) == 5 + + def test_gate_duration_fallback_without_device(self): + scheduler = CoherenceAwareScheduler(cost_model=CostModel()) + assert scheduler._get_gate_duration("sx", [0]) == 1 + assert scheduler._get_gate_duration("cx", [0, 1]) == 3 + + def test_gate_duration_matches_same_size_gate(self): + from qc_compiler.cost_model import DeviceCharacterization + + device = DeviceCharacterization( + backend_name="test", + num_qubits=3, + gate_lengths={ + ("sx", (0,)): 50e-9, + ("cx", (0, 1)): 250e-9, + ("cx", (1, 2)): 400e-9, + }, + ) + model = CostModel() + model.device = device + scheduler = CoherenceAwareScheduler(cost_model=model) + + assert scheduler._get_gate_duration("cx", [0, 1]) == 5 + assert scheduler._get_gate_duration("cx", [1, 2]) == 8 \ No newline at end of file