Skip to content

Commit d0aa100

Browse files
authored
Do not raise deprecation warnings for internal uses of dag.duration and dag.unit (#14133)
* Filter Rust deprecation warning when calling dag.duration/dag.unit internally Filter Rust deprecation warning when calling dag.duration/dag.unit internally * Apply Matt's suggestions: * Refactor access patterns: add dag._duration and dag._unit * Refactor internal uses of dag.duration and dag.unit to rely on internal methods * Remove blanket warning filters from unit test config On top of these: * Extend deprecation warnings to dag.duration and dag.unit setters (previously only in getters) * Clean up unit test config from old filters * Change stacklevel * Fix circuit_to_dag * Handle failing tests * _DAGDependencyV2 is private and not a DAGCircuit, so don't use internal attributes * Reduce duplication in getters and setters
1 parent 241818b commit d0aa100

14 files changed

Lines changed: 188 additions & 165 deletions

File tree

crates/circuit/src/dag_circuit.rs

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,8 @@ pub struct DAGCircuit {
209209
/// Global phase.
210210
global_phase: Param,
211211
/// Duration.
212-
#[pyo3(set)]
213212
duration: Option<PyObject>,
214213
/// Unit of duration.
215-
#[pyo3(set)]
216214
unit: String,
217215

218216
// Note: these are tracked separately from `qubits` and `clbits`
@@ -506,11 +504,11 @@ impl DAGCircuit {
506504
self.clbit_locations.cached(py)
507505
}
508506

509-
/// The total duration of the circuit, set by a scheduling transpiler pass. Its unit is
507+
/// Returns the total duration of the circuit, set by a scheduling transpiler pass. Its unit is
510508
/// specified by :attr:`.unit`
511509
///
512510
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
513-
#[getter]
511+
#[getter("duration")]
514512
fn get_duration(&self, py: Python) -> PyResult<Option<Py<PyAny>>> {
515513
imports::WARNINGS_WARN.get_bound(py).call1((
516514
intern!(
@@ -521,12 +519,49 @@ impl DAGCircuit {
521519
)
522520
),
523521
py.get_type::<PyDeprecationWarning>(),
524-
2,
522+
1,
525523
))?;
524+
self.get_internal_duration(py)
525+
}
526+
527+
/// Returns the total duration of the circuit for internal use (no deprecation warning).
528+
///
529+
/// To be removed with get_duration.
530+
#[getter("_duration")]
531+
fn get_internal_duration(&self, py: Python) -> PyResult<Option<Py<PyAny>>> {
526532
Ok(self.duration.as_ref().map(|x| x.clone_ref(py)))
527533
}
528534

529-
/// The unit that duration is specified in.
535+
/// Sets the total duration of the circuit, set by a scheduling transpiler pass. Its unit is
536+
/// specified by :attr:`.unit`
537+
///
538+
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
539+
#[setter("duration")]
540+
fn set_duration(&mut self, py: Python, duration: Option<PyObject>) -> PyResult<()> {
541+
imports::WARNINGS_WARN.get_bound(py).call1((
542+
intern!(
543+
py,
544+
concat!(
545+
"The property ``qiskit.dagcircuit.dagcircuit.DAGCircuit.duration`` is ",
546+
"deprecated as of Qiskit 1.3.0. It will be removed in Qiskit 3.0.0.",
547+
)
548+
),
549+
py.get_type::<PyDeprecationWarning>(),
550+
1,
551+
))?;
552+
self.set_internal_duration(duration);
553+
Ok(())
554+
}
555+
556+
/// Sets the total duration of the circuit for internal use (no deprecation warning).
557+
///
558+
/// To be removed with set_duration.
559+
#[setter("_duration")]
560+
fn set_internal_duration(&mut self, duration: Option<PyObject>) {
561+
self.duration = duration
562+
}
563+
564+
/// Returns the unit that duration is specified in.
530565
///
531566
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
532567
#[getter]
@@ -540,11 +575,47 @@ impl DAGCircuit {
540575
)
541576
),
542577
py.get_type::<PyDeprecationWarning>(),
543-
2,
578+
1,
544579
))?;
580+
self.get_internal_unit()
581+
}
582+
583+
/// Returns the unit that duration is specified in for internal use (no deprecation warning).
584+
///
585+
/// To be removed with get_unit.
586+
#[getter("_unit")]
587+
fn get_internal_unit(&self) -> PyResult<String> {
545588
Ok(self.unit.clone())
546589
}
547590

591+
/// Sets the unit that duration is specified in.
592+
///
593+
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
594+
#[setter("unit")]
595+
fn set_unit(&mut self, py: Python, unit: String) -> PyResult<()> {
596+
imports::WARNINGS_WARN.get_bound(py).call1((
597+
intern!(
598+
py,
599+
concat!(
600+
"The property ``qiskit.dagcircuit.dagcircuit.DAGCircuit.unit`` is ",
601+
"deprecated as of Qiskit 1.3.0. It will be removed in Qiskit 3.0.0.",
602+
)
603+
),
604+
py.get_type::<PyDeprecationWarning>(),
605+
1,
606+
))?;
607+
self.set_internal_unit(unit);
608+
Ok(())
609+
}
610+
611+
/// Sets the unit that duration is specified in for internal use (no deprecation warning).
612+
///
613+
/// To be removed with set_unit.
614+
#[setter("_unit")]
615+
fn set_internal_unit(&mut self, unit: String) {
616+
self.unit = unit
617+
}
618+
548619
#[getter]
549620
fn input_map(&self, py: Python) -> PyResult<Py<PyDict>> {
550621
let out_dict = PyDict::new(py);

qiskit/circuit/quantumcircuit.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,8 +1420,8 @@ def reverse_ops(self) -> "QuantumCircuit":
14201420
for instruction in reversed(self.data):
14211421
reverse_circ._append(instruction.replace(operation=instruction.operation.reverse_ops()))
14221422

1423-
reverse_circ.duration = self.duration
1424-
reverse_circ.unit = self.unit
1423+
reverse_circ._duration = self._duration
1424+
reverse_circ._unit = self._unit
14251425
return reverse_circ
14261426

14271427
def reverse_bits(self) -> "QuantumCircuit":
@@ -2559,8 +2559,8 @@ def _append(self, instruction, qargs=(), cargs=(), *, _standard_gate: bool = Fal
25592559
"""
25602560
if _standard_gate:
25612561
self._data.append(instruction)
2562-
self.duration = None
2563-
self.unit = "dt"
2562+
self._duration = None
2563+
self._unit = "dt"
25642564
return instruction
25652565

25662566
old_style = not isinstance(instruction, CircuitInstruction)
@@ -2582,8 +2582,8 @@ def _append(self, instruction, qargs=(), cargs=(), *, _standard_gate: bool = Fal
25822582
self._data.append_manual_params(instruction, params)
25832583

25842584
# Invalidate whole circuit duration if an instruction is added
2585-
self.duration = None
2586-
self.unit = "dt"
2585+
self._duration = None
2586+
self._unit = "dt"
25872587
return instruction.operation if old_style else instruction
25882588

25892589
@typing.overload
@@ -6951,7 +6951,7 @@ def qubit_start_time(self, *qubits: Union[Qubit, int]) -> float:
69516951
Raises:
69526952
CircuitError: if ``self`` is a not-yet scheduled circuit.
69536953
"""
6954-
if self.duration is None:
6954+
if self._duration is None:
69556955
# circuit has only delays, this is kind of scheduled
69566956
for instruction in self._data:
69576957
if not isinstance(instruction.operation, Delay):
@@ -6993,7 +6993,7 @@ def qubit_stop_time(self, *qubits: Union[Qubit, int]) -> float:
69936993
Raises:
69946994
CircuitError: if ``self`` is a not-yet scheduled circuit.
69956995
"""
6996-
if self.duration is None:
6996+
if self._duration is None:
69976997
# circuit has only delays, this is kind of scheduled
69986998
for instruction in self._data:
69996999
if not isinstance(instruction.operation, Delay):
@@ -7004,7 +7004,7 @@ def qubit_stop_time(self, *qubits: Union[Qubit, int]) -> float:
70047004

70057005
qubits = [self.qubits[q] if isinstance(q, int) else q for q in qubits]
70067006

7007-
stops = {q: self.duration for q in qubits}
7007+
stops = {q: self._duration for q in qubits}
70087008
dones = {q: False for q in qubits}
70097009
for instruction in reversed(self._data):
70107010
for q in qubits:

qiskit/converters/circuit_to_dag.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,6 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord
7575

7676
dagcircuit = core_circuit_to_dag(circuit, copy_operations, qubit_order, clbit_order)
7777

78-
dagcircuit.duration = circuit._duration
79-
dagcircuit.unit = circuit._unit
78+
dagcircuit._duration = circuit._duration
79+
dagcircuit._unit = circuit._unit
8080
return dagcircuit

qiskit/converters/dag_to_circuit.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ def dag_to_circuit(dag, copy_operations=True):
7474
circuit.add_stretch(stretch)
7575
circuit.metadata = dag.metadata or {}
7676
circuit._data = circuit_data
77-
78-
circuit._duration = dag.duration
79-
circuit._unit = dag.unit
77+
circuit._duration = dag._duration
78+
circuit._unit = dag._unit
8079
return circuit

qiskit/dagcircuit/dagdependency_v2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,16 @@ def copy_empty_like(self):
447447
target_dag = _DAGDependencyV2()
448448
target_dag.name = self.name
449449
target_dag._global_phase = self._global_phase
450-
target_dag.duration = self.duration
451-
target_dag.unit = self.unit
452450
target_dag.metadata = self.metadata
453451
target_dag._key_cache = self._key_cache
454452
target_dag.comm_checker = self.comm_checker
455453

456454
target_dag.add_qubits(self.qubits)
457455
target_dag.add_clbits(self.clbits)
458456

457+
target_dag.duration = self.duration
458+
target_dag.unit = self.unit
459+
459460
for qreg in self.qregs.values():
460461
target_dag.add_qreg(qreg)
461462
for creg in self.cregs.values():

qiskit/transpiler/passes/scheduling/padding/base_padding.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def run(self, dag: DAGCircuit):
124124

125125
new_dag.name = dag.name
126126
new_dag.metadata = dag.metadata
127-
new_dag.unit = self.property_set["time_unit"]
127+
new_dag._unit = self.property_set["time_unit"]
128128
new_dag.global_phase = dag.global_phase
129129

130130
idle_after = {bit: 0 for bit in dag.qubits}
@@ -186,7 +186,7 @@ def run(self, dag: DAGCircuit):
186186
prev_node=prev_node,
187187
)
188188

189-
new_dag.duration = circuit_duration
189+
new_dag._duration = circuit_duration
190190

191191
return new_dag
192192

qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,22 +310,22 @@ def _pad(
310310

311311
if not self.__is_dd_qubit(dag.qubits.index(qubit)):
312312
# Target physical qubit is not the target of this DD sequence.
313-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
313+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
314314
return
315315

316316
if self._skip_reset_qubits and (
317317
isinstance(prev_node, DAGInNode) or isinstance(prev_node.op, Reset)
318318
):
319319
# Previous node is the start edge or reset, i.e. qubit is ground state.
320-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
320+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
321321
return
322322

323323
slack = time_interval - np.sum(self._dd_sequence_lengths[qubit])
324324
sequence_gphase = self._sequence_phase
325325

326326
if slack <= 0:
327327
# Interval too short.
328-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
328+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
329329
return
330330

331331
if len(self._dd_sequence) == 1:
@@ -351,7 +351,7 @@ def _pad(
351351
sequence_gphase += phase
352352
else:
353353
# Don't do anything if there's no single-qubit gate to absorb the inverse
354-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
354+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
355355
return
356356

357357
def _constrained_length(values):
@@ -387,7 +387,7 @@ def _constrained_length(values):
387387
if dd_ind < len(taus):
388388
tau = taus[dd_ind]
389389
if tau > 0:
390-
self._apply_scheduled_op(dag, idle_after, Delay(tau, dag.unit), qubit)
390+
self._apply_scheduled_op(dag, idle_after, Delay(tau, dag._unit), qubit)
391391
idle_after += tau
392392
if dd_ind < len(self._dd_sequence):
393393
gate = self._dd_sequence[dd_ind]

qiskit/transpiler/passes/scheduling/padding/pad_delay.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,4 @@ def _pad(
8787
return
8888

8989
time_interval = t_end - t_start
90-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
90+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)

qiskit/visualization/timeline/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def load_program(self, program: circuit.QuantumCircuit, target: Target | None =
260260
self.add_data(datum)
261261

262262
# update time range
263-
t_end = max(program.duration, self.formatter["margin.minimum_duration"])
263+
t_end = max(program._duration, self.formatter["margin.minimum_duration"])
264264
self.set_time_range(t_start=0, t_end=t_end)
265265

266266
def set_time_range(self, t_start: int, t_end: int):

0 commit comments

Comments
 (0)