Skip to content

Commit

Permalink
Fix scheduling units (#11782)
Browse files Browse the repository at this point in the history
* Fix units

* Add test and reno

* Add support for non-IS units, move test to test_scheduled_circuit.py

* Adapt reno wording

(cherry picked from commit 944e20c)
  • Loading branch information
ElePT authored and mergify[bot] committed Feb 15, 2024
1 parent 21b11b9 commit e3f7bff
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
11 changes: 9 additions & 2 deletions qiskit/circuit/duration.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,15 @@ def convert_durations_to_dt(qc: QuantumCircuit, dt_in_sec: float, inplace=True):
operation.duration = duration_in_dt(duration, dt_in_sec)
operation.unit = "dt"

if circ.duration is not None:
circ.duration = duration_in_dt(circ.duration, dt_in_sec)
if circ.duration is not None and circ.unit != "dt":
if not circ.unit.endswith("s"):
raise CircuitError(f"Invalid time unit: '{circ.unit}'")

duration = circ.duration
if circ.unit != "s":
duration = apply_prefix(duration, circ.unit)

circ.duration = duration_in_dt(duration, dt_in_sec)
circ.unit = "dt"

if not inplace:
Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/fix-scheduling-units-59477912b47d3dc1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
A bug has been fixed in :func:`.convert_durations_to_dt` where the function would blindly apply
a conversion from seconds to ``dt`` on circuit durations, independently of the original units of the attribute.
This could lead to wrong orders of magnitude in the reported circuit durations.
46 changes: 45 additions & 1 deletion test/python/circuit/test_scheduled_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
from qiskit import QuantumCircuit, QiskitError
from qiskit import transpile, assemble
from qiskit.circuit import Parameter
from qiskit.providers.fake_provider import Fake27QPulseV1
from qiskit.circuit.duration import convert_durations_to_dt
from qiskit.providers.fake_provider import Fake27QPulseV1, GenericBackendV2
from qiskit.providers.basic_provider import BasicSimulator
from qiskit.scheduler import ScheduleConfig
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.transpiler.instruction_durations import InstructionDurations
from test import QiskitTestCase # pylint: disable=wrong-import-order
Expand Down Expand Up @@ -300,6 +302,48 @@ def test_per_qubit_durations(self):
self.assertEqual(sc.qubit_start_time(*q), 300)
self.assertEqual(sc.qubit_stop_time(*q), 2400)

def test_convert_duration_to_dt(self):
"""Test that circuit duration unit conversion is applied only when necessary.
Tests fix for bug reported in PR #11782."""

backend = GenericBackendV2(num_qubits=3, calibrate_instructions=True, seed=10)
schedule_config = ScheduleConfig(
inst_map=backend.target.instruction_schedule_map(),
meas_map=backend.meas_map,
dt=backend.dt,
)

circ = QuantumCircuit(2)
circ.cx(0, 1)
circ.measure_all()

circuit_dt = transpile(circ, backend, scheduling_method="asap")
# reference duration and unit in dt
ref_duration = circuit_dt.duration
ref_unit = circuit_dt.unit

circuit_s = circuit_dt.copy()
circuit_s.duration *= backend.dt
circuit_s.unit = "s"

circuit_ms = circuit_s.copy()
circuit_ms.duration *= 1000
circuit_ms.unit = "ms"

for circuit in [circuit_dt, circuit_s, circuit_ms]:
with self.subTest(circuit=circuit):
converted_circ = convert_durations_to_dt(
circuit, dt_in_sec=schedule_config.dt, inplace=False
)
self.assertEqual(
converted_circ.duration,
ref_duration,
)
self.assertEqual(
converted_circ.unit,
ref_unit,
)

def test_change_dt_in_transpile(self):
qc = QuantumCircuit(1, 1)
qc.x(0)
Expand Down

0 comments on commit e3f7bff

Please sign in to comment.