diff --git a/crates/accelerate/src/basis/basis_translator/mod.rs b/crates/accelerate/src/basis/basis_translator/mod.rs index 6a5e57f2e938..26f7d7d3051b 100644 --- a/crates/accelerate/src/basis/basis_translator/mod.rs +++ b/crates/accelerate/src/basis/basis_translator/mod.rs @@ -218,7 +218,7 @@ fn run( Ok(out_dag) } -/// Method that extracts all non-calibrated gate instances identifiers from a DAGCircuit. +/// Method that extracts all gate instances identifiers from a DAGCircuit. fn extract_basis( py: Python, circuit: &DAGCircuit, @@ -232,10 +232,8 @@ fn extract_basis( basis: &mut IndexSet, min_qubits: usize, ) -> PyResult<()> { - for (node, operation) in circuit.op_nodes(true) { - if !circuit.has_calibration_for_index(py, node)? - && circuit.get_qargs(operation.qubits).len() >= min_qubits - { + for (_node, operation) in circuit.op_nodes(true) { + if circuit.get_qargs(operation.qubits).len() >= min_qubits { basis.insert((operation.op.name().to_string(), operation.op.num_qubits())); } if operation.op.control_flow() { @@ -264,11 +262,7 @@ fn extract_basis( .borrow(); for (index, inst) in circuit_data.iter().enumerate() { let instruction_object = circuit.get_item(index)?; - let has_calibration = circuit - .call_method1(intern!(py, "_has_calibration_for"), (&instruction_object,))?; - if !has_calibration.is_truthy()? - && circuit_data.get_qargs(inst.qubits).len() >= min_qubits - { + if circuit_data.get_qargs(inst.qubits).len() >= min_qubits { basis.insert((inst.op.name().to_string(), inst.op.num_qubits())); } if inst.op.control_flow() { @@ -287,7 +281,7 @@ fn extract_basis( } /// Method that extracts a mapping of all the qargs in the local_source basis -/// obtained from the [Target], to all non-calibrated gate instances identifiers from a DAGCircuit. +/// obtained from the [Target], to all gate instances identifiers from a DAGCircuit. /// When dealing with `ControlFlowOp` instances the function will perform a recursion call /// to a variant design to handle instances of `QuantumCircuit`. fn extract_basis_target( @@ -306,9 +300,9 @@ fn extract_basis_target( ahash::RandomState, >, ) -> PyResult<()> { - for (node, node_obj) in dag.op_nodes(true) { + for (_node, node_obj) in dag.op_nodes(true) { let qargs: &[Qubit] = dag.get_qargs(node_obj.qubits); - if dag.has_calibration_for_index(py, node)? || qargs.len() < min_qubits { + if qargs.len() < min_qubits { continue; } // Treat the instruction as on an incomplete basis if the qargs are in the @@ -351,8 +345,9 @@ fn extract_basis_target( unreachable!("Control flow op is not a control flow op. But control_flow is `true`") }; let bound_inst = op.instruction.bind(py); - // Use python side extraction instead of the Rust method `op.blocks` due to - // required usage of a python-space method `QuantumCircuit.has_calibration_for`. + // TODO: Use Rust method `op.blocks` instead of Python side extraction now that + // the python-space method `QuantumCircuit.has_calibration_for` + // has been removed and we don't need to account for it. let blocks = bound_inst.getattr("blocks")?.try_iter()?; for block in blocks { extract_basis_target_circ( @@ -390,13 +385,9 @@ fn extract_basis_target_circ( let py = circuit.py(); let circ_data_bound = circuit.getattr("_data")?.downcast_into::()?; let circ_data = circ_data_bound.borrow(); - for (index, node_obj) in circ_data.iter().enumerate() { + for node_obj in circ_data.iter() { let qargs = circ_data.get_qargs(node_obj.qubits); - if circuit - .call_method1("_has_calibration_for", (circuit.get_item(index)?,))? - .is_truthy()? - || qargs.len() < min_qubits - { + if qargs.len() < min_qubits { continue; } // Treat the instruction as on an incomplete basis if the qargs are in the @@ -578,29 +569,6 @@ fn apply_translation( continue; } - if dag.has_calibration_for_index(py, node)? { - out_dag.apply_operation_back( - py, - node_obj.op.clone(), - node_qarg, - node_carg, - if node_obj.params_view().is_empty() { - None - } else { - Some( - node_obj - .params_view() - .iter() - .map(|param| param.clone_ref(py)) - .collect(), - ) - }, - node_obj.label.as_ref().map(|x| x.as_ref().clone()), - #[cfg(feature = "cache_pygates")] - None, - )?; - continue; - } let unique_qargs: Option = if qubit_set.is_empty() { None } else { diff --git a/crates/accelerate/src/check_map.rs b/crates/accelerate/src/check_map.rs index 68281d0ca198..d439cdc48c5d 100644 --- a/crates/accelerate/src/check_map.rs +++ b/crates/accelerate/src/check_map.rs @@ -36,7 +36,7 @@ fn recurse<'py>( None => edge_set.contains(&[qubits[0].into(), qubits[1].into()]), } }; - for (node, inst) in dag.op_nodes(false) { + for (_node, inst) in dag.op_nodes(false) { let qubits = dag.get_qargs(inst.qubits); if inst.op.control_flow() { if let OperationRef::Instruction(py_inst) = inst.op.view() { @@ -65,10 +65,7 @@ fn recurse<'py>( } } } - } else if qubits.len() == 2 - && (dag.calibrations_empty() || !dag.has_calibration_for_index(py, node)?) - && !check_qubits(qubits) - { + } else if qubits.len() == 2 && !check_qubits(qubits) { return Ok(Some(( inst.op.name().to_string(), [qubits[0].0, qubits[1].0], diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index bc4da40e57d6..30aec7922c22 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -1094,18 +1094,6 @@ pub(crate) fn optimize_1q_gates_decomposition( } else { unreachable!("nodes in runs will always be op nodes") }; - if !dag.calibrations_empty() { - let mut has_calibration = false; - for node in &raw_run { - if dag.has_calibration_for_index(py, *node)? { - has_calibration = true; - break; - } - } - if has_calibration { - continue; - } - } if basis_gates_per_qubit[qubit.index()].is_none() { let basis_gates = match target { Some(target) => Some( diff --git a/crates/accelerate/src/gate_direction.rs b/crates/accelerate/src/gate_direction.rs index d024074439d9..d86641abe522 100755 --- a/crates/accelerate/src/gate_direction.rs +++ b/crates/accelerate/src/gate_direction.rs @@ -20,10 +20,8 @@ use pyo3::types::PyTuple; use qiskit_circuit::operations::OperationRef; use qiskit_circuit::packed_instruction::PackedOperation; use qiskit_circuit::{ - circuit_instruction::CircuitInstruction, converters::{circuit_to_dag, QuantumCircuitData}, dag_circuit::DAGCircuit, - dag_node::{DAGNode, DAGOpNode}, imports, imports::get_std_gate_class, operations::Operation, @@ -291,7 +289,7 @@ where } } - if op_args.len() != 2 || dag.has_calibration_for_index(py, node)? { + if op_args.len() != 2 { continue; }; @@ -334,9 +332,7 @@ where } } // No matching replacement found - if gate_complies(packed_inst, &[op_args1, op_args0]) - || has_calibration_for_op_node(py, dag, packed_inst, &[op_args1, op_args0])? - { + if gate_complies(packed_inst, &[op_args1, op_args0]) { return Err(TranspilerError::new_err(format!("{} would be supported on {:?} if the direction was swapped, but no rules are known to do that. {:?} can be automatically flipped.", packed_inst.op.name(), op_args, vec!["cx", "cz", "ecr", "swap", "rzx", "rxx", "ryy", "rzz"]))); // NOTE: Make sure to update the list of the supported gates if adding more replacements } else { @@ -375,36 +371,6 @@ where Ok(dag) } -// Check whether the dag as calibration for a DAGOpNode -fn has_calibration_for_op_node( - py: Python, - dag: &DAGCircuit, - packed_inst: &PackedInstruction, - qargs: &[Qubit], -) -> PyResult { - let py_args = PyTuple::new(py, dag.qubits().map_indices(qargs))?; - - let dag_op_node = Py::new( - py, - ( - DAGOpNode { - instruction: CircuitInstruction { - operation: packed_inst.op.clone(), - qubits: py_args.unbind(), - clbits: PyTuple::empty(py).unbind(), - params: packed_inst.params_view().iter().cloned().collect(), - label: packed_inst.label.clone(), - #[cfg(feature = "cache_pygates")] - py_op: packed_inst.py_op.clone(), - }, - }, - DAGNode { node: None }, - ), - )?; - - dag.has_calibration_for(py, dag_op_node.borrow(py)) -} - // Return a replacement DAG for the given standard gate in the supported list // TODO: optimize it by caching the DAGs of the non-parametric gates and caching and // mutating upon request the DAGs of the parametric gates diff --git a/crates/accelerate/src/target_transpiler/instruction_properties.rs b/crates/accelerate/src/target_transpiler/instruction_properties.rs index a7a31c87924c..5de5b656913e 100644 --- a/crates/accelerate/src/target_transpiler/instruction_properties.rs +++ b/crates/accelerate/src/target_transpiler/instruction_properties.rs @@ -37,7 +37,6 @@ impl InstructionProperties { /// specified set of qubits /// error (Option): The average error rate for the instruction on the specified /// set of qubits. - /// calibration (Option): The pulse representation of the instruction. #[new] #[pyo3(signature = (duration=None, error=None))] pub fn new(_py: Python<'_>, duration: Option, error: Option) -> Self { diff --git a/crates/circuit/src/converters.rs b/crates/circuit/src/converters.rs index 62cffe210905..2952bbac2acc 100644 --- a/crates/circuit/src/converters.rs +++ b/crates/circuit/src/converters.rs @@ -13,12 +13,8 @@ #[cfg(feature = "cache_pygates")] use std::sync::OnceLock; -use hashbrown::HashMap; use pyo3::prelude::*; -use pyo3::{ - intern, - types::{PyDict, PyList}, -}; +use pyo3::{intern, types::PyList}; use crate::circuit_data::CircuitData; use crate::dag_circuit::{DAGCircuit, NodeType}; @@ -30,7 +26,6 @@ use crate::packed_instruction::PackedInstruction; pub struct QuantumCircuitData<'py> { pub data: CircuitData, pub name: Option>, - pub calibrations: Option>>, pub metadata: Option>, pub qregs: Option>, pub cregs: Option>, @@ -47,10 +42,6 @@ impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> { Ok(QuantumCircuitData { data: data_borrowed, name: ob.getattr(intern!(py, "name")).ok(), - calibrations: ob - .getattr(intern!(py, "_calibrations_prop"))? - .extract() - .ok(), metadata: ob.getattr(intern!(py, "metadata")).ok(), qregs: ob .getattr(intern!(py, "qregs")) diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 682ec7c1061c..d8884b3e188f 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -42,7 +42,7 @@ use pyo3::prelude::*; use pyo3::IntoPyObjectExt; use pyo3::types::{ - IntoPyDict, PyDict, PyInt, PyIterator, PyList, PySequence, PySet, PyString, PyTuple, PyType, + IntoPyDict, PyDict, PyInt, PyIterator, PyList, PySet, PyString, PyTuple, PyType, }; use rustworkx_core::dag_algo::layers; @@ -186,8 +186,6 @@ pub struct DAGCircuit { #[pyo3(get, set)] metadata: Option, - calibrations: HashMap>, - dag: StableDiGraph, #[pyo3(get)] @@ -369,7 +367,6 @@ impl DAGCircuit { Ok(DAGCircuit { name: None, metadata: Some(PyDict::new(py).unbind().into()), - calibrations: HashMap::new(), dag: StableDiGraph::default(), qregs: PyDict::new(py).unbind(), cregs: PyDict::new(py).unbind(), @@ -518,7 +515,6 @@ impl DAGCircuit { let out_dict = PyDict::new(py); out_dict.set_item("name", self.name.as_ref().map(|x| x.clone_ref(py)))?; out_dict.set_item("metadata", self.metadata.as_ref().map(|x| x.clone_ref(py)))?; - out_dict.set_item("_calibrations_prop", self.calibrations.clone())?; out_dict.set_item("qregs", self.qregs.clone_ref(py))?; out_dict.set_item("cregs", self.cregs.clone_ref(py))?; out_dict.set_item("global_phase", self.global_phase.clone())?; @@ -604,10 +600,6 @@ impl DAGCircuit { let dict_state = state.downcast_bound::(py)?; self.name = dict_state.get_item("name")?.unwrap().extract()?; self.metadata = dict_state.get_item("metadata")?.unwrap().extract()?; - self.calibrations = dict_state - .get_item("_calibrations_prop")? - .unwrap() - .extract()?; self.qregs = dict_state.get_item("qregs")?.unwrap().extract()?; self.cregs = dict_state.get_item("cregs")?.unwrap().extract()?; self.global_phase = dict_state.get_item("global_phase")?.unwrap().extract()?; @@ -825,182 +817,6 @@ impl DAGCircuit { Ok(()) } - /// Return calibration dictionary. - /// - /// The custom pulse definition of a given gate is of the form - /// {'gate_name': {(qubits, params): schedule}} - /// - /// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 2.0.0 - #[getter] - fn get_calibrations(&self, py: Python) -> HashMap> { - emit_pulse_dependency_deprecation( - py, - "property ``qiskit.dagcircuit.dagcircuit.DAGCircuit.calibrations``", - ); - - self.calibrations.clone() - } - - /// Set the circuit calibration data from a dictionary of calibration definition. - /// - /// Args: - /// calibrations (dict): A dictionary of input in the format - /// {'gate_name': {(qubits, gate_params): schedule}} - /// - /// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 2.0.0 - #[setter] - fn set_calibrations(&mut self, py: Python, calibrations: HashMap>) { - emit_pulse_dependency_deprecation( - py, - "property ``qiskit.dagcircuit.dagcircuit.DAGCircuit.calibrations``", - ); - - self.calibrations = calibrations; - } - - // This is an alternative and Python-private path to 'get_calibration' to avoid - // deprecation warnings - #[getter(_calibrations_prop)] - fn get_calibrations_prop(&self) -> HashMap> { - self.calibrations.clone() - } - - // This is an alternative and Python-private path to 'set_calibration' to avoid - // deprecation warnings - #[setter(_calibrations_prop)] - fn set_calibrations_prop(&mut self, calibrations: HashMap>) { - self.calibrations = calibrations; - } - - /// Register a low-level, custom pulse definition for the given gate. - /// - /// Args: - /// gate (Union[Gate, str]): Gate information. - /// qubits (Union[int, Tuple[int]]): List of qubits to be measured. - /// schedule (Schedule): Schedule information. - /// params (Optional[List[Union[float, Parameter]]]): A list of parameters. - /// - /// Raises: - /// Exception: if the gate is of type string and params is None. - /// - /// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 2.0.0 - #[pyo3(signature=(gate, qubits, schedule, params=None))] - fn add_calibration<'py>( - &mut self, - py: Python<'py>, - mut gate: Bound<'py, PyAny>, - qubits: Bound<'py, PyAny>, - schedule: Py, - mut params: Option>, - ) -> PyResult<()> { - emit_pulse_dependency_deprecation( - py, - "method ``qiskit.dagcircuit.dagcircuit.DAGCircuit.add_calibration``", - ); - - if gate.is_instance(imports::GATE.get_bound(py))? { - params = Some(gate.getattr(intern!(py, "params"))?); - gate = gate.getattr(intern!(py, "name"))?; - } - - let params_tuple = if let Some(operands) = params { - let add_calibration = PyModule::from_code( - py, - std::ffi::CString::new( - r#" -import numpy as np - -def _format(operand): - try: - # Using float/complex value as a dict key is not good idea. - # This makes the mapping quite sensitive to the rounding error. - # However, the mechanism is already tied to the execution model (i.e. pulse gate) - # and we cannot easily update this rule. - # The same logic exists in QuantumCircuit.add_calibration. - evaluated = complex(operand) - if np.isreal(evaluated): - evaluated = float(evaluated.real) - if evaluated.is_integer(): - evaluated = int(evaluated) - return evaluated - except TypeError: - # Unassigned parameter - return operand - "#, - )? - .as_c_str(), - std::ffi::CString::new("add_calibration.py")?.as_c_str(), - std::ffi::CString::new("add_calibration")?.as_c_str(), - )?; - - let format = add_calibration.getattr("_format")?; - let mapped: PyResult> = - operands.try_iter()?.map(|p| format.call1((p?,))).collect(); - PyTuple::new(py, mapped?)?.into_any() - } else { - PyTuple::empty(py).into_any() - }; - - let calibrations = self - .calibrations - .entry(gate.extract()?) - .or_insert_with(|| PyDict::new(py).unbind()) - .bind(py); - - let qubits = if let Ok(qubits) = qubits.downcast::() { - qubits.to_tuple()?.into_any() - } else { - PyTuple::new(py, [qubits])?.into_any() - }; - let key = PyTuple::new(py, &[qubits.unbind(), params_tuple.into_any().unbind()])?; - calibrations.set_item(key, schedule)?; - Ok(()) - } - - /// Return True if the dag has a calibration defined for the node operation. In this - /// case, the operation does not need to be translated to the device basis. - /// - /// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 2.0.0 - pub fn has_calibration_for(&self, py: Python, node: PyRef) -> PyResult { - emit_pulse_dependency_deprecation( - py, - "method ``qiskit.dagcircuit.dagcircuit.DAGCircuit.has_calibration_for``", - ); - - self._has_calibration_for(py, node) - } - - fn _has_calibration_for(&self, py: Python, node: PyRef) -> PyResult { - if !self - .calibrations - .contains_key(node.instruction.operation.name()) - { - return Ok(false); - } - let mut params = Vec::new(); - for p in &node.instruction.params { - if let Param::ParameterExpression(exp) = p { - let exp = exp.bind(py); - if !exp.getattr(intern!(py, "parameters"))?.is_truthy()? { - let as_py_float = exp.call_method0(intern!(py, "__float__"))?; - params.push(as_py_float.unbind()); - continue; - } - } - params.push(p.into_py_any(py)?); - } - let qubits: Vec = self - .qubits - .map_bits(node.instruction.qubits.bind(py).iter())? - .map(|bit| bit.0) - .collect(); - let qubits = PyTuple::new(py, qubits)?; - let params = PyTuple::new(py, params)?; - self.calibrations[node.instruction.operation.name()] - .bind(py) - .contains((qubits, params)) - } - /// Remove all operation nodes with the given name. fn remove_all_ops_named(&mut self, opname: &str) { let mut to_remove = Vec::new(); @@ -1985,18 +1801,6 @@ def _format(operand): dag.global_phase = add_global_phase(py, &dag.global_phase, &other.global_phase)?; - for (gate, cals) in other.calibrations.iter() { - let calibrations = match dag.calibrations.get(gate) { - Some(calibrations) => calibrations, - None => { - dag.calibrations - .insert(gate.clone(), PyDict::new(py).unbind()); - &dag.calibrations[gate] - } - }; - calibrations.bind(py).update(cals.bind(py).as_mapping())?; - } - // This is all the handling we need for realtime variables, if there's no remapping. They: // // * get added to the DAG and then operations involving them get appended on normally. @@ -2431,22 +2235,6 @@ def _format(operand): if !phase_eq { return Ok(false); } - if self.calibrations.len() != other.calibrations.len() { - return Ok(false); - } - - for (k, v1) in &self.calibrations { - match other.calibrations.get(k) { - Some(v2) => { - if !v1.bind(py).eq(v2.bind(py))? { - return Ok(false); - } - } - None => { - return Ok(false); - } - } - } // We don't do any semantic equivalence between Var nodes, as things stand; DAGs can only be // equal in our mind if they use the exact same UUID vars. @@ -6098,7 +5886,6 @@ impl DAGCircuit { Ok(Self { name: None, metadata: Some(PyDict::new(py).unbind().into()), - calibrations: HashMap::default(), dag: StableDiGraph::with_capacity(num_nodes, num_edges), qregs: PyDict::new(py).unbind(), cregs: PyDict::new(py).unbind(), @@ -6281,44 +6068,6 @@ impl DAGCircuit { Ok(()) } - pub fn calibrations_empty(&self) -> bool { - self.calibrations.is_empty() - } - - pub fn has_calibration_for_index(&self, py: Python, node_index: NodeIndex) -> PyResult { - let node = &self.dag[node_index]; - if let NodeType::Operation(instruction) = node { - if !self.calibrations.contains_key(instruction.op.name()) { - return Ok(false); - } - let params = match &instruction.params { - Some(params) => { - let mut out_params = Vec::new(); - for p in params.iter() { - if let Param::ParameterExpression(exp) = p { - let exp = exp.bind(py); - if !exp.getattr(intern!(py, "parameters"))?.is_truthy()? { - let as_py_float = exp.call_method0(intern!(py, "__float__"))?; - out_params.push(as_py_float.unbind()); - continue; - } - } - out_params.push(p.into_pyobject(py)?.into_any().unbind()); - } - PyTuple::new(py, out_params) - } - None => Ok(PyTuple::empty(py)), - }?; - let qargs = self.qargs_interner.get(instruction.qubits); - let qubits = PyTuple::new(py, qargs.iter().map(|x| x.0))?; - self.calibrations[instruction.op.name()] - .bind(py) - .contains((qubits, params).into_py_any(py)?) - } else { - Err(DAGCircuitError::new_err("Specified node is not an op node")) - } - } - /// Return the op name counts in the circuit /// /// Args: @@ -6576,10 +6325,6 @@ impl DAGCircuit { _ => unreachable!("Incorrect parameter assigned for global phase"), }; - if let Some(calibrations) = qc.calibrations { - new_dag.calibrations = calibrations; - } - new_dag.metadata = qc.metadata.map(|meta| meta.unbind()); // Add the qubits depending on order, and produce the qargs map. @@ -6704,7 +6449,6 @@ impl DAGCircuit { let circ = QuantumCircuitData { data: circuit_data, name: None, - calibrations: None, metadata: None, qregs: None, cregs: None, @@ -6982,23 +6726,6 @@ pub(crate) fn add_global_phase(py: Python, phase: &Param, other: &Param) -> PyRe type SortKeyType<'a> = (&'a [Qubit], &'a [Clbit]); -/// Emit a Python `DeprecationWarning` for pulse-related dependencies. -fn emit_pulse_dependency_deprecation(py: Python, msg: &str) { - let _ = imports::WARNINGS_WARN.get_bound(py).call1(( - PyString::new( - py, - &format!( - "The {} is deprecated as of Qiskit 1.3.0. It will be removed in Qiskit 2.0.0. \ - The entire Qiskit Pulse package is being deprecated \ - and this is a dependency on the package.", - msg - ), - ), - py.get_type::(), - 1, - )); -} - #[cfg(all(test, not(miri)))] mod test { use crate::dag_circuit::{DAGCircuit, Wire}; diff --git a/docs/apidoc/index.rst b/docs/apidoc/index.rst index d6578570951c..d24b7514487e 100644 --- a/docs/apidoc/index.rst +++ b/docs/apidoc/index.rst @@ -75,7 +75,6 @@ Pulse-level programming: :maxdepth: 1 pulse - scheduler Other: diff --git a/docs/apidoc/scheduler.rst b/docs/apidoc/scheduler.rst deleted file mode 100644 index 53328863ebee..000000000000 --- a/docs/apidoc/scheduler.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. _qiskit-scheduler: - -.. automodule:: qiskit.scheduler - :no-members: - :no-inherited-members: - :no-special-members: diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 9cfc9de1909f..9ca5a6e87741 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -21,7 +21,7 @@ import itertools import multiprocessing import typing -from collections import OrderedDict, defaultdict, namedtuple +from collections import OrderedDict, namedtuple from typing import ( Union, Optional, @@ -33,7 +33,6 @@ Mapping, Iterable, Any, - DefaultDict, Literal, overload, ) @@ -48,7 +47,6 @@ from qiskit.circuit.parameter import Parameter from qiskit.circuit.exceptions import CircuitError from qiskit.utils import deprecate_func -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency from . import _classical_resource_map from .controlflow import ControlFlowOp, _builder_utils from .controlflow.builder import CircuitScopeInterface, ControlFlowBuilderBlock @@ -150,7 +148,6 @@ class QuantumCircuit: Immutable data attribute Summary ========================= ====================================================================== :attr:`ancillas` List of :class:`AncillaQubit`\\ s tracked by the circuit. - :attr:`calibrations` Custom user-supplied pulse calibrations for individual instructions. :attr:`cregs` List of :class:`ClassicalRegister`\\ s tracked by the circuit. :attr:`clbits` List of :class:`Clbit`\\ s tracked by the circuit. @@ -231,12 +228,6 @@ class QuantumCircuit: .. autoattribute:: parameters - The storage of any :ref:`manual pulse-level calibrations ` for individual - instructions on the circuit is in :attr:`calibrations`. This presents as a :class:`dict`, but - should not be mutated directly; use the methods discussed in :ref:`circuit-calibrations`. - - .. autoattribute:: calibrations - If you have transpiled your circuit, so you have a physical circuit, you can inspect the :attr:`layout` attribute for information stored by the transpiler about how the virtual qubits of the source circuit map to the hardware qubits of your physical circuit, both at the start and @@ -815,17 +806,6 @@ class QuantumCircuit: .. automethod:: clear .. automethod:: remove_final_measurements - .. _circuit-calibrations: - - Manual calibration of instructions - ---------------------------------- - - :class:`QuantumCircuit` can store :attr:`calibrations` of instructions that define the pulses - used to run them on one particular hardware backend. You can - - .. automethod:: add_calibration - .. automethod:: has_calibration_for - Circuit properties ================== @@ -1105,7 +1085,6 @@ def __init__( self._data: CircuitData = CircuitData() self._ancillas: list[AncillaQubit] = [] - self._calibrations: DefaultDict[str, dict[tuple, Any]] = defaultdict(dict) self.add_register(*regs) self._layout = None @@ -1320,67 +1299,6 @@ def op_start_times(self) -> list[int]: ) return self._op_start_times - @property - @deprecate_pulse_dependency(is_property=True) - def calibrations(self) -> dict: - """Return calibration dictionary. - - The custom pulse definition of a given gate is of the form - ``{'gate_name': {(qubits, params): schedule}}`` - """ - return self._calibrations_prop - - @calibrations.setter - @deprecate_pulse_dependency(is_property=True) - def calibrations(self, calibrations: dict): - """Set the circuit calibration data from a dictionary of calibration definition. - - Args: - calibrations (dict): A dictionary of input in the format - ``{'gate_name': {(qubits, gate_params): schedule}}`` - """ - self._calibrations_prop = calibrations - - @property - def _calibrations_prop(self) -> dict: - """An alternative private path to the `calibrations` property for - avoiding deprecation warnings.""" - return dict(self._calibrations) - - @_calibrations_prop.setter - def _calibrations_prop(self, calibrations: dict): - """An alternative private path to the `calibrations` property for - avoiding deprecation warnings.""" - self._calibrations = defaultdict(dict, calibrations) - - @deprecate_pulse_dependency - def has_calibration_for(self, instruction: CircuitInstruction | tuple): - """Return True if the circuit has a calibration defined for the instruction context. In this - case, the operation does not need to be translated to the device basis. - """ - - return self._has_calibration_for(instruction) - - def _has_calibration_for(self, instruction: CircuitInstruction | tuple): - """An alternative private path to the `has_calibration_for` method for - avoiding deprecation warnings.""" - if isinstance(instruction, CircuitInstruction): - operation = instruction.operation - qubits = instruction.qubits - else: - operation, qubits, _ = instruction - if not self._calibrations_prop or operation.name not in self._calibrations_prop: - return False - qubits = tuple(self.qubits.index(qubit) for qubit in qubits) - params = [] - for p in operation.params: - if isinstance(p, ParameterExpression) and not p.parameters: - params.append(float(p)) - else: - params.append(p) - params = tuple(params) - return (qubits, params) in self._calibrations_prop[operation.name] - @property def metadata(self) -> dict: """The user provided metadata associated with the circuit. @@ -1996,9 +1914,6 @@ def replace_var(var: expr.Var, cache: Mapping[expr.Var, expr.Var]) -> expr.Var: ) edge_map.update(zip(other.clbits, dest._cbit_argument_conversion(clbits))) - for gate, cals in other._calibrations_prop.items(): - dest._calibrations[gate].update(cals) - dest.duration = None dest.unit = "dt" dest.global_phase += other.global_phase @@ -3608,7 +3523,7 @@ def copy_empty_like( That structure includes: - * name, calibrations and other metadata + * name and other metadata * global phase * all the qubits and clbits, including the registers * the realtime variables defined in the circuit, handled according to the ``vars`` keyword @@ -3660,7 +3575,7 @@ def copy_empty_like( def clear(self) -> None: """Clear all instructions in self. - Clearing the circuits will keep the metadata and calibrations. + Clearing the circuits will keep the metadata. .. seealso:: :meth:`copy_empty_like` @@ -4275,70 +4190,10 @@ def assign_parameters( # pylint: disable=missing-raises-doc " the circuit." ) - def create_mapping_view(): - return raw_mapping - target._data.assign_parameters_mapping(raw_mapping) else: - # This should be a cache retrieval, since we warmed the cache. We need to keep hold of - # what the parameters were before anything is assigned, because we assign parameters in - # the calibrations (which aren't tracked in the internal parameter table) after, which - # would change what we create. We don't make the full Python-space mapping object of - # parameters to values eagerly because 99.9% of the time we don't need it, and it's - # relatively expensive to do for large numbers of parameters. - initial_parameters = target._data.parameters - - def create_mapping_view(): - return dict(zip(initial_parameters, parameters)) - target._data.assign_parameters_iterable(parameters) - # Finally, assign the parameters inside any of the calibrations. We don't track these in - # the `ParameterTable`, so we manually reconstruct things. We lazily construct the mapping - # `{parameter: bound_value}` the first time we encounter a binding (we have to scan for - # this, because calibrations don't use a parameter-table lookup), rather than always paying - # the cost - most circuits don't have parametric calibrations, and it's expensive. - mapping_view = None - - def map_calibration(qubits, parameters, schedule): - # All calls to this function should share the same `{Parameter: bound_value}` mapping, - # which we only want to lazily construct a single time. - nonlocal mapping_view - if mapping_view is None: - mapping_view = create_mapping_view() - - modified = False - new_parameters = list(parameters) - for i, parameter in enumerate(new_parameters): - if not isinstance(parameter, ParameterExpression): - continue - if not (contained := parameter.parameters & mapping_view.keys()): - continue - for to_bind in contained: - parameter = parameter.assign(to_bind, mapping_view[to_bind]) - if not parameter.parameters: - parameter = parameter.numeric() - if isinstance(parameter, complex): - raise TypeError(f"Calibration cannot use complex number: '{parameter}'") - new_parameters[i] = parameter - modified = True - if modified: - schedule.assign_parameters(mapping_view) - return (qubits, tuple(new_parameters)), schedule - - target._calibrations = defaultdict( - dict, - ( - ( - gate, - dict( - map_calibration(qubits, parameters, schedule) - for (qubits, parameters), schedule in calibrations.items() - ), - ) - for gate, calibrations in target._calibrations.items() - ), - ) return None if inplace else target def _unroll_param_dict( @@ -6665,57 +6520,6 @@ def continue_loop(self) -> InstructionSet: ContinueLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits, copy=False ) - @deprecate_pulse_dependency - def add_calibration( - self, - gate: Union[Gate, str], - qubits: Sequence[int], - # Schedule has the type `qiskit.pulse.Schedule`, but `qiskit.pulse` cannot be imported - # while this module is, and so Sphinx will not accept a forward reference to it. Sphinx - # needs the types available at runtime, whereas mypy will accept it, because it handles the - # type checking by static analysis. - schedule, - params: Sequence[ParameterValueType] | None = None, - ) -> None: - """Register a low-level, custom pulse definition for the given gate. - - Args: - gate (Union[Gate, str]): Gate information. - qubits (Union[int, Tuple[int]]): List of qubits to be measured. - schedule (Schedule): Schedule information. - params (Optional[List[Union[float, Parameter]]]): A list of parameters. - - Raises: - Exception: if the gate is of type string and params is None. - """ - - def _format(operand): - try: - # Using float/complex value as a dict key is not good idea. - # This makes the mapping quite sensitive to the rounding error. - # However, the mechanism is already tied to the execution model (i.e. pulse gate) - # and we cannot easily update this rule. - # The same logic exists in DAGCircuit.add_calibration. - evaluated = complex(operand) - if np.isreal(evaluated): - evaluated = float(evaluated.real) - if evaluated.is_integer(): - evaluated = int(evaluated) - return evaluated - except TypeError: - # Unassigned parameter - return operand - - if isinstance(gate, Gate): - params = gate.params - gate = gate.name - if params is not None: - params = tuple(map(_format, params)) - else: - params = () - - self._calibrations[gate][(tuple(qubits), params)] = schedule - # Functions only for scheduled circuits def qubit_duration(self, *qubits: Union[Qubit, int]) -> float: """Return the duration between the start and stop time of the first and last instructions, @@ -7049,5 +6853,4 @@ def _copy_metadata(original, cpy, vars_mode): else: # pragma: no cover raise ValueError(f"unknown vars_mode: '{vars_mode}'") - cpy._calibrations = _copy.deepcopy(original._calibrations) cpy._metadata = _copy.deepcopy(original._metadata) diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index 1e7b6157042c..a57f740fec4e 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -23,7 +23,7 @@ from qiskit.dagcircuit import DAGCircuit from qiskit.providers.backend import Backend from qiskit.providers.backend_compat import BackendV2Converter -from qiskit.pulse import Schedule, InstructionScheduleMap +from qiskit.pulse import Schedule from qiskit.transpiler import Layout, CouplingMap, PropertySet from qiskit.transpiler.basepasses import BasePass from qiskit.transpiler.exceptions import TranspilerError, CircuitTooWideForTarget @@ -32,7 +32,6 @@ from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.transpiler.target import Target from qiskit.utils import deprecate_arg -from qiskit.utils.deprecate_pulse import deprecate_pulse_arg logger = logging.getLogger(__name__) @@ -57,12 +56,10 @@ "with defined timing constraints with " "`Target.from_configuration(..., timing_constraints=...)`", ) -@deprecate_pulse_arg("inst_map", predicate=lambda inst_map: inst_map is not None) def transpile( # pylint: disable=too-many-return-statements circuits: _CircuitT, backend: Optional[Backend] = None, basis_gates: Optional[List[str]] = None, - inst_map: Optional[List[InstructionScheduleMap]] = None, coupling_map: Optional[Union[CouplingMap, List[List[int]]]] = None, initial_layout: Optional[Union[Layout, Dict, List]] = None, layout_method: Optional[str] = None, @@ -95,7 +92,7 @@ def transpile( # pylint: disable=too-many-return-statements The prioritization of transpilation target constraints works as follows: if a ``target`` input is provided, it will take priority over any ``backend`` input or loose constraints - (``basis_gates``, ``inst_map``, ``coupling_map``, ``instruction_durations``, + (``basis_gates``, ``coupling_map``, ``instruction_durations``, ``dt`` or ``timing_constraints``). If a ``backend`` is provided together with any loose constraint from the list above, the loose constraint will take priority over the corresponding backend constraint. This behavior is independent of whether the ``backend`` instance is of type @@ -110,7 +107,6 @@ def transpile( # pylint: disable=too-many-return-statements **basis_gates** target basis_gates basis_gates **coupling_map** target coupling_map coupling_map **instruction_durations** target instruction_durations instruction_durations - **inst_map** target inst_map inst_map **dt** target dt dt **timing_constraints** target timing_constraints timing_constraints ============================ ========= ======================== ======================= @@ -122,12 +118,6 @@ def transpile( # pylint: disable=too-many-return-statements will override the backend's. basis_gates: List of basis gate names to unroll to (e.g: ``['u1', 'u2', 'u3', 'cx']``). If ``None``, do not unroll. - inst_map: DEPRECATED. Mapping of unrolled gates to pulse schedules. If this is not provided, - transpiler tries to get from the backend. If any user defined calibration - is found in the map and this is used in a circuit, transpiler attaches - the custom gate definition to the circuit. This enables one to flexibly - override the low-level instruction implementation. This feature is available - iff the backend supports the pulse gate experiment. coupling_map: Directed coupling map (perhaps custom) to target in mapping. If the coupling map is symmetric, both directions need to be specified. @@ -379,14 +369,8 @@ def callback_func(**kwargs): # Edge cases require using the old model (loose constraints) instead of building a target, # but we don't populate the passmanager config with loose constraints unless it's one of # the known edge cases to control the execution path. - # Filter instruction_durations, timing_constraints and inst_map deprecation + # Filter instruction_durations and timing_constraints deprecation with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message=".*``inst_map`` is deprecated as of Qiskit 1.3.*", - module="qiskit", - ) warnings.filterwarnings( "ignore", category=DeprecationWarning, @@ -407,7 +391,6 @@ def callback_func(**kwargs): coupling_map=coupling_map, instruction_durations=instruction_durations, timing_constraints=timing_constraints, - inst_map=inst_map, initial_layout=initial_layout, layout_method=layout_method, routing_method=routing_method, diff --git a/qiskit/converters/circuit_to_dagdependency.py b/qiskit/converters/circuit_to_dagdependency.py index e617cf30c4fd..26b5896f69f4 100644 --- a/qiskit/converters/circuit_to_dagdependency.py +++ b/qiskit/converters/circuit_to_dagdependency.py @@ -46,6 +46,4 @@ def circuit_to_dagdependency(circuit, create_preds_and_succs=True): dagdependency._add_predecessors() dagdependency._add_successors() - dagdependency._calibrations = circuit._calibrations_prop - return dagdependency diff --git a/qiskit/converters/circuit_to_dagdependency_v2.py b/qiskit/converters/circuit_to_dagdependency_v2.py index f55a0cf6716c..32a429ab1bac 100644 --- a/qiskit/converters/circuit_to_dagdependency_v2.py +++ b/qiskit/converters/circuit_to_dagdependency_v2.py @@ -27,7 +27,6 @@ def _circuit_to_dagdependency_v2(circuit): dagdependency = _DAGDependencyV2() dagdependency.name = circuit.name dagdependency.metadata = circuit.metadata - dagdependency._calibrations = circuit._calibrations_prop dagdependency.global_phase = circuit.global_phase dagdependency.add_qubits(circuit.qubits) diff --git a/qiskit/converters/dag_to_circuit.py b/qiskit/converters/dag_to_circuit.py index 8918b5c5d4c4..21e6a10b1574 100644 --- a/qiskit/converters/dag_to_circuit.py +++ b/qiskit/converters/dag_to_circuit.py @@ -71,7 +71,6 @@ def dag_to_circuit(dag, copy_operations=True): for var in dag.iter_declared_vars(): circuit.add_uninitialized_var(var) circuit.metadata = dag.metadata - circuit._calibrations_prop = dag._calibrations_prop circuit._data = circuit_data diff --git a/qiskit/converters/dag_to_dagdependency.py b/qiskit/converters/dag_to_dagdependency.py index 19fb70a31bd6..55f88b0883d8 100644 --- a/qiskit/converters/dag_to_dagdependency.py +++ b/qiskit/converters/dag_to_dagdependency.py @@ -50,6 +50,5 @@ def dag_to_dagdependency(dag, create_preds_and_succs=True): # copy metadata dagdependency.global_phase = dag.global_phase - dagdependency._calibrations_prop = dag._calibrations_prop return dagdependency diff --git a/qiskit/converters/dag_to_dagdependency_v2.py b/qiskit/converters/dag_to_dagdependency_v2.py index 29eb12300f00..ce38f378aec1 100644 --- a/qiskit/converters/dag_to_dagdependency_v2.py +++ b/qiskit/converters/dag_to_dagdependency_v2.py @@ -27,7 +27,6 @@ def _dag_to_dagdependency_v2(dag): dagdependency.name = dag.name dagdependency.metadata = dag.metadata dagdependency.global_phase = dag.global_phase - dagdependency.calibrations = dag._calibrations_prop dagdependency.add_qubits(dag.qubits) dagdependency.add_clbits(dag.clbits) diff --git a/qiskit/converters/dagdependency_to_circuit.py b/qiskit/converters/dagdependency_to_circuit.py index 541207d175d2..9599adb84ac6 100644 --- a/qiskit/converters/dagdependency_to_circuit.py +++ b/qiskit/converters/dagdependency_to_circuit.py @@ -34,12 +34,6 @@ def dagdependency_to_circuit(dagdependency): ) circuit.metadata = dagdependency.metadata - if hasattr(dagdependency, "_calibrations_prop"): - circuit._calibrations_prop = dagdependency._calibrations_prop - else: - # This can be _DAGDependencyV2 - circuit._calibrations_prop = dagdependency.calibrations - for node in dagdependency.topological_nodes(): circuit._append(CircuitInstruction(node.op.copy(), node.qargs, node.cargs)) diff --git a/qiskit/converters/dagdependency_to_dag.py b/qiskit/converters/dagdependency_to_dag.py index 3b500d82c884..d1f0e80836ca 100644 --- a/qiskit/converters/dagdependency_to_dag.py +++ b/qiskit/converters/dagdependency_to_dag.py @@ -12,7 +12,6 @@ """Helper function for converting a dag dependency to a dag circuit""" from qiskit.dagcircuit.dagcircuit import DAGCircuit -from qiskit.dagcircuit.dagdependency import DAGDependency def dagdependency_to_dag(dagdependency): @@ -45,10 +44,5 @@ def dagdependency_to_dag(dagdependency): # copy metadata dagcircuit.global_phase = dagdependency.global_phase - if isinstance(dagdependency, DAGDependency): - dagcircuit._calibrations_prop = dagdependency._calibrations_prop - else: - # This can be _DAGDependencyV2 - dagcircuit._calibrations_prop = dagdependency.calibrations return dagcircuit diff --git a/qiskit/dagcircuit/dagdependency.py b/qiskit/dagcircuit/dagdependency.py index 63e9114a6ca1..e398ada92c99 100644 --- a/qiskit/dagcircuit/dagdependency.py +++ b/qiskit/dagcircuit/dagdependency.py @@ -17,7 +17,7 @@ import math import heapq import typing -from collections import OrderedDict, defaultdict +from collections import OrderedDict from collections.abc import Iterator import rustworkx as rx @@ -28,8 +28,6 @@ from qiskit.circuit.classicalregister import ClassicalRegister, Clbit from qiskit.dagcircuit.exceptions import DAGDependencyError from qiskit.dagcircuit.dagdepnode import DAGDepNode -from qiskit.pulse import Schedule -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency if typing.TYPE_CHECKING: from qiskit.circuit.parameterexpression import ParameterExpression @@ -115,7 +113,6 @@ def __init__(self): self.clbits = [] self._global_phase: float | ParameterExpression = 0.0 - self._calibrations: dict[str, dict[tuple, Schedule]] = defaultdict(dict) self.duration = None self.unit = "dt" @@ -146,37 +143,6 @@ def global_phase(self, angle: float | ParameterExpression): else: self._global_phase = angle % (2 * math.pi) - @property - @deprecate_pulse_dependency(is_property=True) - def calibrations(self) -> dict[str, dict[tuple, Schedule]]: - """Return calibration dictionary. - - The custom pulse definition of a given gate is of the form - ``{'gate_name': {(qubits, params): schedule}}``. - """ - return self._calibrations_prop - - @calibrations.setter - @deprecate_pulse_dependency(is_property=True) - def calibrations(self, calibrations: dict[str, dict[tuple, Schedule]]): - """Set the circuit calibration data from a dictionary of calibration definition. - - Args: - calibrations (dict): A dictionary of input in the format - {'gate_name': {(qubits, gate_params): schedule}} - """ - self._calibrations_prop = calibrations - - @property - def _calibrations_prop(self) -> dict[str, dict[tuple, Schedule]]: - """An alternative path to be used internally to avoid deprecation warnings""" - return dict(self._calibrations) - - @_calibrations_prop.setter - def _calibrations_prop(self, calibrations: dict[str, dict[tuple, Schedule]]): - """An alternative path to be used internally to avoid deprecation warnings""" - self._calibrations = defaultdict(dict, calibrations) - def to_retworkx(self): """Returns the DAGDependency in retworkx format.""" return self._multi_graph diff --git a/qiskit/dagcircuit/dagdependency_v2.py b/qiskit/dagcircuit/dagdependency_v2.py index 2f14c07e2049..cfa49a7cd16f 100644 --- a/qiskit/dagcircuit/dagdependency_v2.py +++ b/qiskit/dagcircuit/dagdependency_v2.py @@ -15,10 +15,9 @@ import itertools import math -from collections import OrderedDict, defaultdict, namedtuple +from collections import OrderedDict, namedtuple from typing import Dict, List, Generator, Any -import numpy as np import rustworkx as rx from qiskit.circuit import ( @@ -26,7 +25,6 @@ ClassicalRegister, Qubit, Clbit, - Gate, ParameterExpression, ) from qiskit.circuit.controlflow import condition_resources @@ -110,7 +108,6 @@ def __init__(self): self._clbit_indices: Dict[Clbit, BitLocations] = {} self._global_phase = 0 - self._calibrations = defaultdict(dict) # Map of number of each kind of op, keyed on op name self._op_names = {} @@ -142,81 +139,6 @@ def global_phase(self, angle): else: self._global_phase = angle % (2 * math.pi) - @property - def calibrations(self): - """Return calibration dictionary. - - The custom pulse definition of a given gate is of the form - ``{'gate_name': {(qubits, params): schedule}}``. - """ - return dict(self._calibrations) - - @calibrations.setter - def calibrations(self, calibrations): - """Set the circuit calibration data from a dictionary of calibration definition. - - Args: - calibrations (dict): A dictionary of input in the format - {'gate_name': {(qubits, gate_params): schedule}} - """ - self._calibrations = defaultdict(dict, calibrations) - - def add_calibration(self, gate, qubits, schedule, params=None): - """Register a low-level, custom pulse definition for the given gate. - - Args: - gate (Union[Gate, str]): Gate information. - qubits (Union[int, Tuple[int]]): List of qubits to be measured. - schedule (Schedule): Schedule information. - params (Optional[List[Union[float, Parameter]]]): A list of parameters. - - Raises: - Exception: if the gate is of type string and params is None. - """ - - def _format(operand): - try: - # Using float/complex value as a dict key is not good idea. - # This makes the mapping quite sensitive to the rounding error. - # However, the mechanism is already tied to the execution model (i.e. pulse gate) - # and we cannot easily update this rule. - # The same logic exists in QuantumCircuit.add_calibration. - evaluated = complex(operand) - if np.isreal(evaluated): - evaluated = float(evaluated.real) - if evaluated.is_integer(): - evaluated = int(evaluated) - return evaluated - except TypeError: - # Unassigned parameter - return operand - - if isinstance(gate, Gate): - params = gate.params - gate = gate.name - if params is not None: - params = tuple(map(_format, params)) - else: - params = () - - self._calibrations[gate][(tuple(qubits), params)] = schedule - - def has_calibration_for(self, node): - """Return True if the dag has a calibration defined for the node operation. In this - case, the operation does not need to be translated to the device basis. - """ - if not self.calibrations or node.op.name not in self.calibrations: - return False - qubits = tuple(self.qubits.index(qubit) for qubit in node.qargs) - params = [] - for p in node.op.params: - if isinstance(p, ParameterExpression) and not p.parameters: - params.append(float(p)) - else: - params.append(p) - params = tuple(params) - return (qubits, params) in self.calibrations[node.op.name] - def size(self): """Returns the number of gates in the circuit""" return len(self._multi_graph) diff --git a/qiskit/providers/backend_compat.py b/qiskit/providers/backend_compat.py index 571500fa35e9..b4c34ee5b55c 100644 --- a/qiskit/providers/backend_compat.py +++ b/qiskit/providers/backend_compat.py @@ -15,27 +15,23 @@ from __future__ import annotations import logging import warnings -from typing import List, Iterable, Any, Dict, Optional +from typing import List, Any, Dict, Optional from qiskit.providers.backend import BackendV1, BackendV2 from qiskit.providers.backend import QubitProperties from qiskit.providers.models.backendconfiguration import BackendConfiguration from qiskit.providers.models.backendproperties import BackendProperties from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES, get_control_flow_name_mapping -from qiskit.providers.models.pulsedefaults import PulseDefaults from qiskit.providers.options import Options from qiskit.providers.exceptions import BackendPropertyError -from qiskit.utils.deprecate_pulse import deprecate_pulse_arg, deprecate_pulse_dependency logger = logging.getLogger(__name__) -@deprecate_pulse_arg("defaults") def convert_to_target( configuration: BackendConfiguration, properties: BackendProperties = None, - defaults: PulseDefaults = None, custom_name_mapping: Optional[Dict[str, Any]] = None, add_delay: bool = True, filter_faulty: bool = True, @@ -43,13 +39,12 @@ def convert_to_target( """Decode transpiler target from backend data set. This function generates :class:`.Target`` instance from intermediate - legacy objects such as :class:`.BackendProperties` and :class:`.PulseDefaults`. + legacy objects such as :class:`.BackendProperties`. These objects are usually components of the legacy :class:`.BackendV1` model. Args: configuration: Backend configuration as ``BackendConfiguration`` properties: Backend property dictionary or ``BackendProperties`` - defaults: DEPRECATED. Backend pulse defaults dictionary or ``PulseDefaults`` custom_name_mapping: A name mapping must be supplied for the operation not included in Qiskit Standard Gate name mapping, otherwise the operation will be dropped in the resulting ``Target`` object. @@ -59,20 +54,6 @@ def convert_to_target( Returns: A ``Target`` instance. """ - return _convert_to_target( - configuration, properties, defaults, custom_name_mapping, add_delay, filter_faulty - ) - - -def _convert_to_target( - configuration: BackendConfiguration, - properties: BackendProperties = None, - defaults: PulseDefaults = None, - custom_name_mapping: Optional[Dict[str, Any]] = None, - add_delay: bool = True, - filter_faulty: bool = True, -): - """An alternative private path to avoid pulse deprecations""" # importing packages where they are needed, to avoid cyclic-import. # pylint: disable=cyclic-import from qiskit.transpiler.target import ( @@ -248,44 +229,6 @@ def _get_value(prop_dict, prop_name): if not filter_faulty or (q not in faulty_qubits) } - if defaults: - inst_sched_map = defaults.instruction_schedule_map - - for name in inst_sched_map.instructions: - for qubits in inst_sched_map.qubits_with_instruction(name): - if not isinstance(qubits, tuple): - qubits = (qubits,) - if ( - name not in all_instructions - or name not in prop_name_map - or prop_name_map[name] is None - or qubits not in prop_name_map[name] - ): - logger.info( - "Gate calibration for instruction %s on qubits %s is found " - "in the PulseDefaults payload. However, this entry is not defined in " - "the gate mapping of Target. This calibration is ignored.", - name, - qubits, - ) - continue - - if (name, qubits) in faulty_ops: - continue - - entry = inst_sched_map._get_calibration_entry(name, qubits) - try: - prop_name_map[name][qubits]._calibration_prop = entry - except AttributeError: - # if instruction properties are "None", add entry - prop_name_map[name].update({qubits: InstructionProperties(None, None, entry)}) - logger.info( - "The PulseDefaults payload received contains an instruction %s on " - "qubits %s which is not present in the configuration or properties payload." - "A new properties entry will be added to include the new calibration data.", - name, - qubits, - ) # Add parsed properties to target target = Target(**in_data) for inst_name in all_instructions: @@ -345,21 +288,6 @@ class BackendV2Converter(BackendV2): common access patterns between :class:`~.BackendV1` and :class:`~.BackendV2`. This class should only be used if you need a :class:`~.BackendV2` and still need compatibility with :class:`~.BackendV1`. - - When using custom calibrations (or other custom workflows) it is **not** recommended - to mutate the ``BackendV1`` object before applying this converter. For example, in order to - convert a ``BackendV1`` object with a customized ``defaults().instruction_schedule_map``, - which has a custom calibration for an operation, the operation name must be in - ``configuration().basis_gates`` and ``name_mapping`` must be supplied for the operation. - Otherwise, the operation will be dropped in the resulting ``BackendV2`` object. - - Instead it is typically better to add custom calibrations **after** applying this converter - instead of updating ``BackendV1.defaults()`` in advance. For example:: - - backend_v2 = BackendV2Converter(backend_v1) - backend_v2.target.add_instruction( - custom_gate, {(0, 1): InstructionProperties(calibration=custom_sched)} - ) """ def __init__( @@ -398,15 +326,12 @@ def __init__( ) self._options = self._backend._options self._properties = None - self._defaults = None with warnings.catch_warnings(): # The class QobjExperimentHeader is deprecated warnings.filterwarnings("ignore", category=DeprecationWarning, module="qiskit") if hasattr(self._backend, "properties"): self._properties = self._backend.properties() - if hasattr(self._backend, "defaults"): - self._defaults = self._backend.defaults() self._target = None self._name_mapping = name_mapping @@ -420,10 +345,9 @@ def target(self): :rtype: Target """ if self._target is None: - self._target = _convert_to_target( + self._target = convert_to_target( configuration=self._config, properties=self._properties, - defaults=self._defaults, custom_name_mapping=self._name_mapping, add_delay=self._add_delay, filter_faulty=self._filter_faulty, @@ -446,21 +370,5 @@ def dtm(self) -> float: def meas_map(self) -> List[List[int]]: return self._config.meas_map - @deprecate_pulse_dependency - def drive_channel(self, qubit: int): - return self._config.drive(qubit) - - @deprecate_pulse_dependency - def measure_channel(self, qubit: int): - return self._config.measure(qubit) - - @deprecate_pulse_dependency - def acquire_channel(self, qubit: int): - return self._config.acquire(qubit) - - @deprecate_pulse_dependency - def control_channel(self, qubits: Iterable[int]): - return self._config.control(qubits) - def run(self, run_input, **options): return self._backend.run(run_input, **options) diff --git a/qiskit/providers/basic_provider/basic_simulator.py b/qiskit/providers/basic_provider/basic_simulator.py index 74ede03c93a2..d9d72a2b883e 100644 --- a/qiskit/providers/basic_provider/basic_simulator.py +++ b/qiskit/providers/basic_provider/basic_simulator.py @@ -123,7 +123,7 @@ def target(self) -> Target: def _build_basic_target(self) -> Target: """Helper method that returns a minimal target with a basis gate set but - no coupling map, instruction properties or calibrations. + no coupling map or instruction properties. Returns: The configured target. diff --git a/qiskit/providers/fake_provider/generic_backend_v2.py b/qiskit/providers/fake_provider/generic_backend_v2.py index 28a1061a9499..4d4aded058b7 100644 --- a/qiskit/providers/fake_provider/generic_backend_v2.py +++ b/qiskit/providers/fake_provider/generic_backend_v2.py @@ -300,7 +300,7 @@ def _add_noisy_instruction_to_target( rounded_duration = round(duration / dt) * dt # Clamp rounded duration to be between min and max values duration = max(noise_params[0], min(rounded_duration, noise_params[1])) - props.update({qargs: InstructionProperties(duration, error, None)}) + props.update({qargs: InstructionProperties(duration, error)}) self._target.add_instruction(instruction, props) diff --git a/qiskit/providers/fake_provider/utils/backend_converter.py b/qiskit/providers/fake_provider/utils/backend_converter.py index 9e038c39df38..c5268dc2f414 100644 --- a/qiskit/providers/fake_provider/utils/backend_converter.py +++ b/qiskit/providers/fake_provider/utils/backend_converter.py @@ -44,7 +44,7 @@ def convert_to_target(conf_dict: dict, props_dict: dict = None, defs_dict: dict if props_dict: qubit_props = qubit_props_from_props(props_dict) target = Target(qubit_properties=qubit_props, concurrent_measurements=conf_dict.get("meas_map")) - # Parse from properties if it exsits + # Parse from properties if it exists if props_dict is not None: # Parse instructions gates = {} diff --git a/qiskit/qpy/__init__.py b/qiskit/qpy/__init__.py index c16ecbb89ff4..4aa6b8b818db 100644 --- a/qiskit/qpy/__init__.py +++ b/qiskit/qpy/__init__.py @@ -171,10 +171,10 @@ def open(*args): .. note:: - Starting with Qiskit version 2.0.0, which removed the Pulse module from the library, QPY provides - limited support for loading payloads that include pulse data. Loading a ``ScheduleBlock`` payload, - a :class:`.QpyError` exception will be raised. Loading a payload for a circuit that contained pulse - gates, the output circuit will contain custom instructions **without** calibration data attached + Starting with Qiskit version 2.0.0, which removed the Pulse module from the library, QPY provides + limited support for loading payloads that include pulse data. Loading a ``ScheduleBlock`` payload, + a :class:`.QpyError` exception will be raised. Loading a payload for a circuit that contained pulse + gates, the output circuit will contain custom instructions **without** calibration data attached for each pulse gate, leaving them undefined. QPY format version history diff --git a/qiskit/scheduler/__init__.py b/qiskit/scheduler/__init__.py deleted file mode 100644 index 7062e01a941e..000000000000 --- a/qiskit/scheduler/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -=========================================== -Circuit Scheduler (:mod:`qiskit.scheduler`) -=========================================== - -.. currentmodule:: qiskit.scheduler - -A circuit scheduler compiles a circuit program to a pulse program. - -Core API -======== - -.. autoclass:: ScheduleConfig - -.. currentmodule:: qiskit.scheduler.schedule_circuit -.. autofunction:: schedule_circuit -.. currentmodule:: qiskit.scheduler - -Pulse scheduling methods -======================== - -.. currentmodule:: qiskit.scheduler.methods -.. autofunction:: as_soon_as_possible -.. autofunction:: as_late_as_possible -.. currentmodule:: qiskit.scheduler -""" -from qiskit.scheduler import schedule_circuit -from qiskit.scheduler.config import ScheduleConfig diff --git a/qiskit/scheduler/config.py b/qiskit/scheduler/config.py deleted file mode 100644 index a1c5ba9a2c59..000000000000 --- a/qiskit/scheduler/config.py +++ /dev/null @@ -1,37 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Scheduling container classes.""" - -from typing import List - -from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap -from qiskit.pulse.utils import format_meas_map -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency - - -class ScheduleConfig: - """Configuration for pulse scheduling.""" - - @deprecate_pulse_dependency(moving_to_dynamics=True) - def __init__(self, inst_map: InstructionScheduleMap, meas_map: List[List[int]], dt: float): - """ - Container for information needed to schedule a QuantumCircuit into a pulse Schedule. - - Args: - inst_map: The schedule definition of all gates supported on a backend. - meas_map: A list of groups of qubits which have to be measured together. - dt: Sample duration. - """ - self.inst_map = inst_map - self.meas_map = format_meas_map(meas_map) - self.dt = dt diff --git a/qiskit/scheduler/lowering.py b/qiskit/scheduler/lowering.py deleted file mode 100644 index f0fb33957d9e..000000000000 --- a/qiskit/scheduler/lowering.py +++ /dev/null @@ -1,187 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2020. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Lower gates to schedules. The relative timing within gates is respected. This -module handles the translation, but does not handle timing. -""" -from collections import namedtuple -from typing import Dict, List, Optional, Union - -from qiskit.circuit.barrier import Barrier -from qiskit.circuit.delay import Delay -from qiskit.circuit.duration import convert_durations_to_dt -from qiskit.circuit.measure import Measure -from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.exceptions import QiskitError -from qiskit.pulse import Schedule -from qiskit.pulse import instructions as pulse_inst -from qiskit.pulse.channels import AcquireChannel, MemorySlot, DriveChannel -from qiskit.pulse.exceptions import PulseError -from qiskit.pulse.macros import measure -from qiskit.scheduler.config import ScheduleConfig -from qiskit.providers import BackendV1, BackendV2 - -CircuitPulseDef = namedtuple( - "CircuitPulseDef", - ["schedule", "qubits"], # The schedule which implements the quantum circuit command -) # The labels of the qubits involved in the command according to the circuit - - -def lower_gates( - circuit: QuantumCircuit, - schedule_config: ScheduleConfig, - backend: Optional[Union[BackendV1, BackendV2]] = None, -) -> List[CircuitPulseDef]: - """ - Return a list of Schedules and the qubits they operate on, for each element encountered in the - input circuit. - - Without concern for the final schedule, extract and return a list of Schedules and the qubits - they operate on, for each element encountered in the input circuit. Measures are grouped when - possible, so ``qc.measure(q0, c0)`` or ``qc.measure(q1, c1)`` will generate a synchronous - measurement pulse. - - Args: - circuit: The quantum circuit to translate. - schedule_config: Backend specific parameters used for building the Schedule. - backend: Pass in the backend used to build the Schedule, the backend could be BackendV1 - or BackendV2 - - Returns: - A list of CircuitPulseDefs: the pulse definition for each circuit element. - - Raises: - QiskitError: If circuit uses a command that isn't defined in config.inst_map. - """ - from qiskit.pulse.transforms.base_transforms import target_qobj_transform - - circ_pulse_defs = [] - - inst_map = schedule_config.inst_map - qubit_mem_slots = {} # Map measured qubit index to classical bit index - - # convert the unit of durations from SI to dt before lowering - circuit = convert_durations_to_dt(circuit, dt_in_sec=schedule_config.dt, inplace=False) - - def get_measure_schedule(qubit_mem_slots: Dict[int, int]) -> CircuitPulseDef: - """Create a schedule to measure the qubits queued for measuring.""" - sched = Schedule() - # Exclude acquisition on these qubits, since they are handled by the user calibrations - acquire_excludes = {} - if Measure().name in circuit.calibrations.keys(): - qubits = tuple(sorted(qubit_mem_slots.keys())) - params = () - for qubit in qubits: - try: - meas_q = circuit.calibrations[Measure().name][((qubit,), params)] - meas_q = target_qobj_transform(meas_q) - acquire_q = meas_q.filter(channels=[AcquireChannel(qubit)]) - mem_slot_index = [ - chan.index for chan in acquire_q.channels if isinstance(chan, MemorySlot) - ][0] - if mem_slot_index != qubit_mem_slots[qubit]: - raise KeyError( - "The measurement calibration is not defined on " - "the requested classical bits" - ) - sched |= meas_q - del qubit_mem_slots[qubit] - acquire_excludes[qubit] = mem_slot_index - except KeyError: - pass - - if qubit_mem_slots: - qubits = list(qubit_mem_slots.keys()) - qubit_mem_slots.update(acquire_excludes) - meas_sched = measure( - qubits=qubits, - backend=backend, - inst_map=inst_map, - meas_map=schedule_config.meas_map, - qubit_mem_slots=qubit_mem_slots, - ) - meas_sched = target_qobj_transform(meas_sched) - meas_sched = meas_sched.exclude( - channels=[AcquireChannel(qubit) for qubit in acquire_excludes] - ) - sched |= meas_sched - qubit_mem_slots.clear() - return CircuitPulseDef( - schedule=sched, - qubits=[chan.index for chan in sched.channels if isinstance(chan, AcquireChannel)], - ) - - qubit_indices = {bit: idx for idx, bit in enumerate(circuit.qubits)} - clbit_indices = {bit: idx for idx, bit in enumerate(circuit.clbits)} - - for instruction in circuit.data: - inst_qubits = [qubit_indices[qubit] for qubit in instruction.qubits] - - if any(q in qubit_mem_slots for q in inst_qubits): - # If we are operating on a qubit that was scheduled to be measured, process that first - circ_pulse_defs.append(get_measure_schedule(qubit_mem_slots)) - - if isinstance(instruction.operation, Barrier): - circ_pulse_defs.append( - CircuitPulseDef(schedule=instruction.operation, qubits=inst_qubits) - ) - elif isinstance(instruction.operation, Delay): - sched = Schedule(name=instruction.operation.name) - for qubit in inst_qubits: - for channel in [DriveChannel]: - sched += pulse_inst.Delay( - duration=instruction.operation.duration, channel=channel(qubit) - ) - circ_pulse_defs.append(CircuitPulseDef(schedule=sched, qubits=inst_qubits)) - elif isinstance(instruction.operation, Measure): - if len(inst_qubits) != 1 and len(instruction.clbits) != 1: - raise QiskitError( - f"Qubit '{inst_qubits}' or classical bit '{instruction.clbits}' errored because the " - "circuit Measure instruction only takes one of " - "each." - ) - qubit_mem_slots[inst_qubits[0]] = clbit_indices[instruction.clbits[0]] - else: - try: - gate_cals = circuit.calibrations[instruction.operation.name] - schedule = gate_cals[ - ( - tuple(inst_qubits), - tuple( - p if getattr(p, "parameters", None) else float(p) - for p in instruction.operation.params - ), - ) - ] - schedule = target_qobj_transform(schedule) - circ_pulse_defs.append(CircuitPulseDef(schedule=schedule, qubits=inst_qubits)) - continue - except KeyError: - pass # Calibration not defined for this operation - - try: - schedule = inst_map.get( - instruction.operation, inst_qubits, *instruction.operation.params - ) - schedule = target_qobj_transform(schedule) - circ_pulse_defs.append(CircuitPulseDef(schedule=schedule, qubits=inst_qubits)) - except PulseError as ex: - raise QiskitError( - f"Operation '{instruction.operation.name}' on qubit(s) {inst_qubits} " - "not supported by the backend command definition. Did you remember to " - "transpile your input circuit for the same backend?" - ) from ex - - if qubit_mem_slots: - circ_pulse_defs.append(get_measure_schedule(qubit_mem_slots)) - - return circ_pulse_defs diff --git a/qiskit/scheduler/methods/__init__.py b/qiskit/scheduler/methods/__init__.py deleted file mode 100644 index 6df887d54995..000000000000 --- a/qiskit/scheduler/methods/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Scheduling methods.""" - -from qiskit.scheduler.methods.basic import as_soon_as_possible, as_late_as_possible diff --git a/qiskit/scheduler/methods/basic.py b/qiskit/scheduler/methods/basic.py deleted file mode 100644 index b08f0f866ab0..000000000000 --- a/qiskit/scheduler/methods/basic.py +++ /dev/null @@ -1,140 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -The most straightforward scheduling methods: scheduling **as early** or **as late** as possible. -""" -from collections import defaultdict -from typing import List, Optional, Union - -from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.circuit.barrier import Barrier -from qiskit.pulse.schedule import Schedule - -from qiskit.scheduler.config import ScheduleConfig -from qiskit.scheduler.lowering import lower_gates -from qiskit.providers import BackendV1, BackendV2 -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency - - -@deprecate_pulse_dependency(moving_to_dynamics=True) -def as_soon_as_possible( - circuit: QuantumCircuit, - schedule_config: ScheduleConfig, - backend: Optional[Union[BackendV1, BackendV2]] = None, -) -> Schedule: - """ - Return the pulse Schedule which implements the input circuit using an "as soon as possible" - (asap) scheduling policy. - - Circuit instructions are first each mapped to equivalent pulse - Schedules according to the command definition given by the schedule_config. Then, this circuit - instruction-equivalent Schedule is appended at the earliest time at which all qubits involved - in the instruction are available. - - Args: - circuit: The quantum circuit to translate. - schedule_config: Backend specific parameters used for building the Schedule. - backend: A backend used to build the Schedule, the backend could be BackendV1 - or BackendV2. - - Returns: - A schedule corresponding to the input ``circuit`` with pulses occurring as early as - possible. - """ - qubit_time_available = defaultdict(int) - - def update_times(inst_qubits: List[int], time: int = 0) -> None: - """Update the time tracker for all inst_qubits to the given time.""" - for q in inst_qubits: - qubit_time_available[q] = time - - start_times = [] - circ_pulse_defs = lower_gates(circuit, schedule_config, backend) - for circ_pulse_def in circ_pulse_defs: - start_time = max(qubit_time_available[q] for q in circ_pulse_def.qubits) - stop_time = start_time - if not isinstance(circ_pulse_def.schedule, Barrier): - stop_time += circ_pulse_def.schedule.duration - - start_times.append(start_time) - update_times(circ_pulse_def.qubits, stop_time) - - timed_schedules = [ - (time, cpd.schedule) - for time, cpd in zip(start_times, circ_pulse_defs) - if not isinstance(cpd.schedule, Barrier) - ] - schedule = Schedule.initialize_from(circuit) - for time, inst in timed_schedules: - schedule.insert(time, inst, inplace=True) - return schedule - - -@deprecate_pulse_dependency(moving_to_dynamics=True) -def as_late_as_possible( - circuit: QuantumCircuit, - schedule_config: ScheduleConfig, - backend: Optional[Union[BackendV1, BackendV2]] = None, -) -> Schedule: - """ - Return the pulse Schedule which implements the input circuit using an "as late as possible" - (alap) scheduling policy. - - Circuit instructions are first each mapped to equivalent pulse - Schedules according to the command definition given by the schedule_config. Then, this circuit - instruction-equivalent Schedule is appended at the latest time that it can be without allowing - unnecessary time between instructions or allowing instructions with common qubits to overlap. - - This method should improves the outcome fidelity over ASAP scheduling, because we may - maximize the time that the qubit remains in the ground state. - - Args: - circuit: The quantum circuit to translate. - schedule_config: Backend specific parameters used for building the Schedule. - backend: A backend used to build the Schedule, the backend could be BackendV1 - or BackendV2. - - Returns: - A schedule corresponding to the input ``circuit`` with pulses occurring as late as - possible. - """ - qubit_time_available = defaultdict(int) - - def update_times(inst_qubits: List[int], time: int = 0) -> None: - """Update the time tracker for all inst_qubits to the given time.""" - for q in inst_qubits: - qubit_time_available[q] = time - - rev_stop_times = [] - circ_pulse_defs = lower_gates(circuit, schedule_config, backend) - for circ_pulse_def in reversed(circ_pulse_defs): - start_time = max(qubit_time_available[q] for q in circ_pulse_def.qubits) - stop_time = start_time - if not isinstance(circ_pulse_def.schedule, Barrier): - stop_time += circ_pulse_def.schedule.duration - - rev_stop_times.append(stop_time) - update_times(circ_pulse_def.qubits, stop_time) - - last_stop = max(t for t in qubit_time_available.values()) if qubit_time_available else 0 - start_times = [last_stop - t for t in reversed(rev_stop_times)] - - timed_schedules = [ - (time, cpd.schedule) - for time, cpd in zip(start_times, circ_pulse_defs) - if not isinstance(cpd.schedule, Barrier) - ] - schedule = Schedule.initialize_from(circuit) - for time, inst in timed_schedules: - schedule.insert(time, inst, inplace=True) - return schedule diff --git a/qiskit/scheduler/schedule_circuit.py b/qiskit/scheduler/schedule_circuit.py deleted file mode 100644 index 2cc32a8a7b3c..000000000000 --- a/qiskit/scheduler/schedule_circuit.py +++ /dev/null @@ -1,69 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""QuantumCircuit to Pulse scheduler.""" -from typing import Optional, Union - -from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.exceptions import QiskitError - -from qiskit.pulse.schedule import Schedule -from qiskit.scheduler.config import ScheduleConfig -from qiskit.scheduler.methods import as_soon_as_possible, as_late_as_possible -from qiskit.providers import BackendV1, BackendV2 -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency - - -@deprecate_pulse_dependency(moving_to_dynamics=True) -def schedule_circuit( - circuit: QuantumCircuit, - schedule_config: ScheduleConfig, - method: Optional[str] = None, - backend: Optional[Union[BackendV1, BackendV2]] = None, -) -> Schedule: - """ - Basic scheduling pass from a circuit to a pulse Schedule, using the backend. If no method is - specified, then a basic, as late as possible scheduling pass is performed, i.e. pulses are - scheduled to occur as late as possible. - - Supported methods: - - * ``'as_soon_as_possible'``: Schedule pulses greedily, as early as possible on a - qubit resource. (alias: ``'asap'``) - * ``'as_late_as_possible'``: Schedule pulses late-- keep qubits in the ground state when - possible. (alias: ``'alap'``) - - Args: - circuit: The quantum circuit to translate. - schedule_config: Backend specific parameters used for building the Schedule. - method: The scheduling pass method to use. - backend: A backend used to build the Schedule, the backend could be BackendV1 - or BackendV2. - - Returns: - Schedule corresponding to the input circuit. - - Raises: - QiskitError: If method isn't recognized. - """ - methods = { - "as_soon_as_possible": as_soon_as_possible, - "asap": as_soon_as_possible, - "as_late_as_possible": as_late_as_possible, - "alap": as_late_as_possible, - } - if method is None: - method = "as_late_as_possible" - try: - return methods[method](circuit, schedule_config, backend) - except KeyError as ex: - raise QiskitError(f"Scheduling method {method} isn't recognized.") from ex diff --git a/qiskit/scheduler/sequence.py b/qiskit/scheduler/sequence.py deleted file mode 100644 index 7f69f5f65a6a..000000000000 --- a/qiskit/scheduler/sequence.py +++ /dev/null @@ -1,104 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2020. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -Mapping a scheduled QuantumCircuit to a pulse Schedule. -""" -from collections import defaultdict - -from typing import Optional, Union -from qiskit.circuit.barrier import Barrier -from qiskit.circuit.measure import Measure -from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.exceptions import QiskitError -from qiskit.pulse.schedule import Schedule -from qiskit.pulse.transforms import pad -from qiskit.scheduler.config import ScheduleConfig -from qiskit.scheduler.lowering import lower_gates -from qiskit.providers import BackendV1, BackendV2 -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency - - -@deprecate_pulse_dependency(moving_to_dynamics=True) -def sequence( - scheduled_circuit: QuantumCircuit, - schedule_config: ScheduleConfig, - backend: Optional[Union[BackendV1, BackendV2]] = None, -) -> Schedule: - """ - Return the pulse Schedule which implements the input scheduled circuit. - - Assume all measurements are done at once at the last of the circuit. - Schedules according to the command definition given by the schedule_config. - - Args: - scheduled_circuit: The scheduled quantum circuit to translate. - schedule_config: Backend specific parameters used for building the Schedule. - backend: A backend used to build the Schedule, the backend could be BackendV1 - or BackendV2 - - Returns: - A schedule corresponding to the input ``circuit``. - - Raises: - QiskitError: If invalid scheduled circuit is supplied. - """ - circ_pulse_defs = lower_gates(scheduled_circuit, schedule_config, backend) - - # find the measurement start time (assume measurement once) - def _meas_start_time(): - _qubit_time_available = defaultdict(int) - for instruction in scheduled_circuit.data: - if isinstance(instruction.operation, Measure): - return _qubit_time_available[instruction.qubits[0]] - for q in instruction.qubits: - _qubit_time_available[q] += instruction.operation.duration - return None - - meas_time = _meas_start_time() - - # restore start times - qubit_time_available = {} - start_times = [] - out_circ_pulse_defs = [] - for circ_pulse_def in circ_pulse_defs: - active_qubits = [q for q in circ_pulse_def.qubits if q in qubit_time_available] - - start_time = max((qubit_time_available[q] for q in active_qubits), default=0) - - for q in active_qubits: - if qubit_time_available[q] != start_time: - # print(q, ":", qubit_time_available[q], "!=", start_time) - raise QiskitError("Invalid scheduled circuit.") - - stop_time = start_time - if not isinstance(circ_pulse_def.schedule, Barrier): - stop_time += circ_pulse_def.schedule.duration - - delay_overlaps_meas = False - for q in circ_pulse_def.qubits: - qubit_time_available[q] = stop_time - if ( - meas_time is not None - and circ_pulse_def.schedule.name == "delay" - and stop_time > meas_time - ): - qubit_time_available[q] = meas_time - delay_overlaps_meas = True - # skip to delays overlapping measures and barriers - if not delay_overlaps_meas and not isinstance(circ_pulse_def.schedule, Barrier): - start_times.append(start_time) - out_circ_pulse_defs.append(circ_pulse_def) - - timed_schedules = [(time, cpd.schedule) for time, cpd in zip(start_times, out_circ_pulse_defs)] - sched = Schedule(*timed_schedules, name=scheduled_circuit.name) - return pad(sched) diff --git a/qiskit/transpiler/basepasses.py b/qiskit/transpiler/basepasses.py index b4993915c1cc..1e51e4165457 100644 --- a/qiskit/transpiler/basepasses.py +++ b/qiskit/transpiler/basepasses.py @@ -199,10 +199,7 @@ def execute( ) if state.workflow_status.previous_run == RunState.SUCCESS: - if isinstance(new_dag, DAGCircuit): - # Copy calibration data from the original program - new_dag._calibrations_prop = passmanager_ir._calibrations_prop - else: + if not isinstance(new_dag, DAGCircuit): raise TranspilerError( "Transformation passes should return a transformed dag." f"The pass {self.__class__.__name__} is returning a {type(new_dag)}" diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py index aab89daba173..1551ab076e92 100644 --- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py @@ -54,8 +54,6 @@ def run(self, dag): QiskitError: if a 3q+ gate is not decomposable """ for node in dag.multi_qubit_ops(): - if dag._has_calibration_for(node): - continue if isinstance(node.op, ControlFlowOp): dag.substitute_node(node, control_flow.map_blocks(self.run, node.op)) diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index 4209e8e89e67..a5ca1861c524 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -75,7 +75,7 @@ def run(self, dag): if getattr(node.op, "_directive", False): continue - if dag._has_calibration_for(node) or len(node.qargs) < self._min_qubits: + if len(node.qargs) < self._min_qubits: continue controlled_gate_open_ctrl = isinstance(node.op, ControlledGate) and node.op._open_ctrl diff --git a/qiskit/transpiler/passes/calibration/base_builder.py b/qiskit/transpiler/passes/calibration/base_builder.py deleted file mode 100644 index d69dcb171871..000000000000 --- a/qiskit/transpiler/passes/calibration/base_builder.py +++ /dev/null @@ -1,79 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Calibration builder base class.""" - -from abc import abstractmethod -from typing import List, Union - -from qiskit.circuit import Instruction as CircuitInst -from qiskit.dagcircuit import DAGCircuit -from qiskit.pulse import Schedule, ScheduleBlock -from qiskit.pulse.calibration_entries import CalibrationPublisher -from qiskit.transpiler.basepasses import TransformationPass - -from .exceptions import CalibrationNotAvailable - - -class CalibrationBuilder(TransformationPass): - """Abstract base class to inject calibrations into circuits.""" - - @abstractmethod - def supported(self, node_op: CircuitInst, qubits: List) -> bool: - """Determine if a given node supports the calibration. - - Args: - node_op: Target instruction object. - qubits: Integer qubit indices to check. - - Returns: - Return ``True`` is calibration can be provided. - """ - - @abstractmethod - def get_calibration(self, node_op: CircuitInst, qubits: List) -> Union[Schedule, ScheduleBlock]: - """Gets the calibrated schedule for the given instruction and qubits. - - Args: - node_op: Target instruction object. - qubits: Integer qubit indices to check. - - Returns: - Return Schedule of target gate instruction. - """ - - def run(self, dag: DAGCircuit) -> DAGCircuit: - """Run the calibration adder pass on `dag`. - - Args: - dag: DAG to schedule. - - Returns: - A DAG with calibrations added to it. - """ - for node in dag.gate_nodes(): - qubits = [dag.find_bit(q).index for q in node.qargs] - - if self.supported(node.op, qubits) and not dag.has_calibration_for(node): - # calibration can be provided and no user-defined calibration is already provided - try: - schedule = self.get_calibration(node.op, qubits) - except CalibrationNotAvailable: - # Fail in schedule generation. Just ignore. - continue - publisher = schedule.metadata.get("publisher", CalibrationPublisher.QISKIT) - - # add calibration if it is not backend default - if publisher != CalibrationPublisher.BACKEND_PROVIDER: - dag.add_calibration(gate=node.op, qubits=qubits, schedule=schedule) - - return dag diff --git a/qiskit/transpiler/passes/calibration/exceptions.py b/qiskit/transpiler/passes/calibration/exceptions.py deleted file mode 100644 index 7785f49d1d30..000000000000 --- a/qiskit/transpiler/passes/calibration/exceptions.py +++ /dev/null @@ -1,22 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Exception for errors raised by the calibration pass module.""" -from qiskit.exceptions import QiskitError - - -class CalibrationNotAvailable(QiskitError): - """Raised when calibration generation fails. - - .. note:: - This error is meant to caught by CalibrationBuilder and ignored. - """ diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py b/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py index 450490734e46..7c4acb1b59e1 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py @@ -224,7 +224,6 @@ def _step(self, dag): # perform the replacement if it was indeed a good idea if self._optimize1q._substitution_checks( - dag, (preceding_run or []) + run + (succeeding_run or []), new_preceding_run.op_nodes() + new_run.op_nodes() + new_succeeding_run.op_nodes(), self._optimize1q._basis_gates, diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py index 55232ac1be20..b00e4c9e5112 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py @@ -160,33 +160,24 @@ def _gate_sequence_to_dag(self, best_synth_circuit): out_dag.apply_operation_back(op.operation, qubits, check=False) return out_dag - def _substitution_checks( - self, dag, old_run, new_circ, basis, qubit, old_error=None, new_error=None - ): + def _substitution_checks(self, old_run, new_circ, basis, qubit, old_error=None, new_error=None): """ Returns `True` when it is recommended to replace `old_run` with `new_circ` over `basis`. """ if new_circ is None: return False - # do we even have calibrations? - has_cals_p = dag._calibrations_prop is not None and len(dag._calibrations_prop) > 0 - # does this run have uncalibrated gates? - uncalibrated_p = not has_cals_p or any(not dag._has_calibration_for(g) for g in old_run) - # does this run have gates not in the image of ._decomposers _and_ uncalibrated? + # does this run have gates not in the image of ._decomposers? if basis is not None: - uncalibrated_and_not_basis_p = any( - g.name not in basis and (not has_cals_p or not dag._has_calibration_for(g)) - for g in old_run - ) + not_basis_p = any(g.name not in basis for g in old_run) else: # If no basis is specified then we're always in the basis - uncalibrated_and_not_basis_p = False + not_basis_p = False # if we're outside of the basis set, we're obligated to logically decompose. # if we're outside of the set of gates for which we have physical definitions, # then we _try_ to decompose, using the results if we see improvement. - if not uncalibrated_and_not_basis_p: + if not not_basis_p: if new_error is None: new_error = self._error(new_circ, qubit) if old_error is None: @@ -196,8 +187,8 @@ def _substitution_checks( old_error = 0.0 return ( - uncalibrated_and_not_basis_p - or (uncalibrated_p and new_error < old_error) + not_basis_p + or (True and new_error < old_error) or (math.isclose(new_error[0], 0) and not math.isclose(old_error[0], 0)) ) diff --git a/qiskit/transpiler/passes/scheduling/alignments/__init__.py b/qiskit/transpiler/passes/scheduling/alignments/__init__.py index 507fb95d3486..50882354a7ea 100644 --- a/qiskit/transpiler/passes/scheduling/alignments/__init__.py +++ b/qiskit/transpiler/passes/scheduling/alignments/__init__.py @@ -63,7 +63,7 @@ configuration in units of dt. This is the constraint for a single pulse :class:`Play` instruction that may constitute your pulse gate. The length of waveform samples should be multiple of this constraint value. - Violation of this constraint may result in failue in backend execution. + Violation of this constraint may result in failure in backend execution. Minimum pulse length constraint @@ -71,7 +71,7 @@ configuration in units of dt. This is the constraint for a single pulse :class:`Play` instruction that may constitute your pulse gate. The length of waveform samples should be greater than this constraint value. - Violation of this constraint may result in failue in backend execution. + Violation of this constraint may result in failure in backend execution. """ diff --git a/qiskit/transpiler/passes/scheduling/alignments/check_durations.py b/qiskit/transpiler/passes/scheduling/alignments/check_durations.py index 3edfdf7ec741..134f1c116a08 100644 --- a/qiskit/transpiler/passes/scheduling/alignments/check_durations.py +++ b/qiskit/transpiler/passes/scheduling/alignments/check_durations.py @@ -68,11 +68,3 @@ def run(self, dag: DAGCircuit): if not (dur % self.acquire_align == 0 and dur % self.pulse_align == 0): self.property_set["reschedule_required"] = True return - - # Check custom gate durations - for inst_defs in dag._calibrations_prop.values(): - for caldef in inst_defs.values(): - dur = caldef.duration - if not (dur % self.acquire_align == 0 and dur % self.pulse_align == 0): - self.property_set["reschedule_required"] = True - return diff --git a/qiskit/transpiler/passes/scheduling/padding/base_padding.py b/qiskit/transpiler/passes/scheduling/padding/base_padding.py index 1904fb9ed510..cdb3478f72bc 100644 --- a/qiskit/transpiler/passes/scheduling/padding/base_padding.py +++ b/qiskit/transpiler/passes/scheduling/padding/base_padding.py @@ -15,7 +15,6 @@ from collections.abc import Iterable import logging -import warnings from qiskit.circuit import Qubit, Clbit, Instruction from qiskit.circuit.delay import Delay @@ -81,14 +80,6 @@ def get_duration(self, node, dag): # pylint: disable=too-many-return-statements if not self.target and not self.durations: return None indices = [dag.find_bit(qarg).index for qarg in node.qargs] - if dag._has_calibration_for(node): - # If node has calibration, this value should be the highest priority - cal_key = tuple(indices), tuple(float(p) for p in node.op.params) - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # `schedule.duration` emits pulse deprecation warnings which we don't want - # to see here - return dag._calibrations_prop[node.op.name][cal_key].duration if self.target: props_dict = self.target.get(node.name) @@ -134,7 +125,6 @@ def run(self, dag: DAGCircuit): new_dag.name = dag.name new_dag.metadata = dag.metadata new_dag.unit = self.property_set["time_unit"] - new_dag._calibrations_prop = dag._calibrations_prop new_dag.global_phase = dag.global_phase idle_after = {bit: 0 for bit in dag.qubits} diff --git a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py index 5522e99ce61a..3de058c8da53 100644 --- a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +++ b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py @@ -14,7 +14,6 @@ from __future__ import annotations import logging -import warnings import numpy as np from qiskit.circuit import Gate, ParameterExpression, Qubit @@ -182,6 +181,7 @@ def __init__( self._dd_sequence_lengths: dict[Qubit, list[int]] = {} self._sequence_phase = 0 if target is not None: + # The priority order for instruction durations is: target > standalone. self._durations = target.durations() self._alignment = target.pulse_alignment for gate in dd_sequence: @@ -190,35 +190,12 @@ def __init__( f"{gate.name} in dd_sequence is not supported in the target" ) - def _update_inst_durations(self, dag): - """Update instruction durations with circuit information. If the dag contains gate - calibrations and no instruction durations were provided through the target or as a - standalone input, the circuit calibration durations will be used. - The priority order for instruction durations is: target > standalone > circuit. - """ - circ_durations = InstructionDurations() - - if dag._calibrations_prop: - cal_durations = [] - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # `schedule.duration` emits pulse deprecation warnings which we don't want - # to see here - for gate, gate_cals in dag._calibrations_prop.items(): - for (qubits, parameters), schedule in gate_cals.items(): - cal_durations.append((gate, qubits, parameters, schedule.duration)) - circ_durations.update(cal_durations, circ_durations.dt) - - if self._durations is not None: - circ_durations.update(self._durations, getattr(self._durations, "dt", None)) - - return circ_durations - def _pre_runhook(self, dag: DAGCircuit): super()._pre_runhook(dag) - durations = self._update_inst_durations(dag) - + durations = InstructionDurations() + if self._durations is not None: + durations.update(self._durations, getattr(self._durations, "dt", None)) num_pulses = len(self._dd_sequence) # Check if physical circuit is given @@ -264,31 +241,7 @@ def _pre_runhook(self, dag: DAGCircuit): sequence_lengths = [] for index, gate in enumerate(self._dd_sequence): - try: - # Check calibration. - params = self._resolve_params(gate) - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # `schedule.duration` emits pulse deprecation warnings which we don't want - # to see here - gate_length = dag._calibrations_prop[gate.name][ - ((physical_index,), params) - ].duration - if gate_length % self._alignment != 0: - # This is necessary to implement lightweight scheduling logic for this pass. - # Usually the pulse alignment constraint and pulse data chunk size take - # the same value, however, we can intentionally violate this pattern - # at the gate level. For example, we can create a schedule consisting of - # a pi-pulse of 32 dt followed by a post buffer, i.e. delay, of 4 dt - # on the device with 16 dt constraint. Note that the pi-pulse length - # is multiple of 16 dt but the gate length of 36 is not multiple of it. - # Such pulse gate should be excluded. - raise TranspilerError( - f"Pulse gate {gate.name} with length non-multiple of {self._alignment} " - f"is not acceptable in {self.__class__.__name__} pass." - ) - except KeyError: - gate_length = durations.get(gate, physical_index) + gate_length = durations.get(gate, physical_index) sequence_lengths.append(gate_length) # Update gate duration. This is necessary for current timeline drawer, i.e. scheduled. gate = gate.to_mutable() diff --git a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py index 65cd2266059e..8928d23e45a1 100644 --- a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +++ b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py @@ -61,20 +61,12 @@ def _get_node_duration( node: DAGOpNode, dag: DAGCircuit, ) -> int: - """A helper method to get duration from node or calibration.""" + """A helper method to get duration from node""" indices = [dag.find_bit(qarg).index for qarg in node.qargs] if node.name == "delay": # `TimeUnitConversion` already handled the unit conversions. duration = node.op.duration - elif dag._has_calibration_for(node): - # If node has calibration, this value should be the highest priority - cal_key = tuple(indices), tuple(float(p) for p in node.op.params) - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # `schedule.duration` emits pulse deprecation warnings which we don't want - # to see here - duration = dag._calibrations_prop[node.op.name][cal_key].duration else: unit = "s" if self.durations.dt is None else "dt" try: diff --git a/qiskit/transpiler/passes/scheduling/time_unit_conversion.py b/qiskit/transpiler/passes/scheduling/time_unit_conversion.py index 40baf44a8ce8..8332cbf04bc4 100644 --- a/qiskit/transpiler/passes/scheduling/time_unit_conversion.py +++ b/qiskit/transpiler/passes/scheduling/time_unit_conversion.py @@ -12,7 +12,6 @@ """Unify time unit in circuit for scheduling and following passes.""" from typing import Set -import warnings from qiskit.circuit import Delay from qiskit.dagcircuit import DAGCircuit @@ -51,6 +50,7 @@ def __init__(self, inst_durations: InstructionDurations = None, target: Target = super().__init__() self.inst_durations = inst_durations or InstructionDurations() if target is not None: + # The priority order for instruction durations is: target > standalone. self.inst_durations = target.durations() self._durations_provided = inst_durations is not None or target is not None @@ -67,7 +67,9 @@ def run(self, dag: DAGCircuit): TranspilerError: if the units are not unifiable """ - inst_durations = self._update_inst_durations(dag) + inst_durations = InstructionDurations() + if self._durations_provided: + inst_durations.update(self.inst_durations, getattr(self.inst_durations, "dt", None)) # Choose unit if inst_durations.dt is not None: @@ -108,30 +110,6 @@ def run(self, dag: DAGCircuit): self.property_set["time_unit"] = time_unit return dag - def _update_inst_durations(self, dag): - """Update instruction durations with circuit information. If the dag contains gate - calibrations and no instruction durations were provided through the target or as a - standalone input, the circuit calibration durations will be used. - The priority order for instruction durations is: target > standalone > circuit. - """ - circ_durations = InstructionDurations() - - if dag._calibrations_prop: - cal_durations = [] - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # `schedule.duration` emits pulse deprecation warnings which we don't want - # to see here - for gate, gate_cals in dag._calibrations_prop.items(): - for (qubits, parameters), schedule in gate_cals.items(): - cal_durations.append((gate, qubits, parameters, schedule.duration)) - circ_durations.update(cal_durations, circ_durations.dt) - - if self._durations_provided: - circ_durations.update(self.inst_durations, getattr(self.inst_durations, "dt", None)) - - return circ_durations - @staticmethod def _units_used_in_delays(dag: DAGCircuit) -> Set[str]: units_used = set() diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index 95adee1d05c7..de0679387594 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -313,7 +313,7 @@ def _run( if top_level: for node in dag.op_nodes(): qubits = tuple(dag.find_bit(q).index for q in node.qargs) - if not self._definitely_skip_node(node, qubits, dag): + if not self._definitely_skip_node(node, qubits): break else: # The for-loop terminates without reaching the break statement @@ -353,7 +353,7 @@ def _run( processed = True # check if synthesis for the operation can be skipped - elif self._definitely_skip_node(node, qubits, dag): + elif self._definitely_skip_node(node, qubits): tracker.set_dirty(context.to_globals(qubits)) # next check control flow @@ -800,9 +800,7 @@ def _apply_annotations( return synthesized - def _definitely_skip_node( - self, node: DAGOpNode, qubits: tuple[int] | None, dag: DAGCircuit - ) -> bool: + def _definitely_skip_node(self, node: DAGOpNode, qubits: tuple[int] | None) -> bool: """Fast-path determination of whether a node can certainly be skipped (i.e. nothing will attempt to synthesise it) without accessing its Python-space `Operation`. @@ -811,8 +809,7 @@ def _definitely_skip_node( node (which is _most_ nodes).""" if ( - dag._has_calibration_for(node) - or len(node.qargs) < self._min_qubits + len(node.qargs) < self._min_qubits or node.is_directive() or (self._instruction_supported(node.name, qubits) and not node.is_control_flow()) ): diff --git a/qiskit/transpiler/passmanager_config.py b/qiskit/transpiler/passmanager_config.py index 1d473014b981..52c43a24cb9d 100644 --- a/qiskit/transpiler/passmanager_config.py +++ b/qiskit/transpiler/passmanager_config.py @@ -16,18 +16,15 @@ from qiskit.transpiler.coupling import CouplingMap from qiskit.transpiler.instruction_durations import InstructionDurations -from qiskit.utils.deprecate_pulse import deprecate_pulse_arg class PassManagerConfig: """Pass Manager Configuration.""" - @deprecate_pulse_arg("inst_map", predicate=lambda inst_map: inst_map is not None) def __init__( self, initial_layout=None, basis_gates=None, - inst_map=None, coupling_map=None, layout_method=None, routing_method=None, @@ -51,7 +48,6 @@ def __init__( initial_layout (Layout): Initial position of virtual qubits on physical qubits. basis_gates (list): List of basis gate names to unroll to. - inst_map (InstructionScheduleMap): Mapping object that maps gate to schedule. coupling_map (CouplingMap): Directed graph represented a coupling map. layout_method (str): the pass to use for choosing initial qubit @@ -88,7 +84,6 @@ def __init__( """ self.initial_layout = initial_layout self.basis_gates = basis_gates - self.inst_map = inst_map self.coupling_map = coupling_map self.init_method = init_method self.layout_method = layout_method @@ -149,14 +144,6 @@ def from_backend(cls, backend, _skip_target=False, **pass_manager_options): res.basis_gates = getattr(config, "basis_gates", None) else: res.basis_gates = backend.operation_names - if res.inst_map is None: - if backend_version < 2: - if hasattr(backend, "defaults"): - defaults = backend.defaults() - if defaults is not None: - res.inst_map = defaults.instruction_schedule_map - else: - res.inst_map = backend._instruction_schedule_map if res.coupling_map is None: if backend_version < 2: cmap_edge_list = getattr(config, "coupling_map", None) @@ -185,7 +172,6 @@ def __str__(self): "Pass Manager Config:\n" f"\tinitial_layout: {self.initial_layout}\n" f"\tbasis_gates: {self.basis_gates}\n" - f"\tinst_map: {str(self.inst_map).replace(newline, newline_tab)}\n" f"\tcoupling_map: {self.coupling_map}\n" f"\tlayout_method: {self.layout_method}\n" f"\trouting_method: {self.routing_method}\n" diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index c06f483606d3..7adf53f2651b 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -13,7 +13,6 @@ """Built-in transpiler stage plugins for preset pass managers.""" import os -import warnings from qiskit.transpiler.passes.optimization.split_2q_unitaries import Split2QUnitaries from qiskit.transpiler.passmanager import PassManager @@ -647,16 +646,11 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana instruction_durations = pass_manager_config.instruction_durations scheduling_method = pass_manager_config.scheduling_method timing_constraints = pass_manager_config.timing_constraints - inst_map = pass_manager_config.inst_map target = pass_manager_config.target - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # Passing `inst_map` to `generate_scheduling` is deprecated in Qiskit 1.3 - # so filtering these warning when building pass managers - return common.generate_scheduling( - instruction_durations, scheduling_method, timing_constraints, inst_map, target - ) + return common.generate_scheduling( + instruction_durations, scheduling_method, timing_constraints, target + ) class AsapSchedulingPassManager(PassManagerStagePlugin): @@ -668,16 +662,11 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana instruction_durations = pass_manager_config.instruction_durations scheduling_method = pass_manager_config.scheduling_method timing_constraints = pass_manager_config.timing_constraints - inst_map = pass_manager_config.inst_map target = pass_manager_config.target - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # Passing `inst_map` to `generate_scheduling` is deprecated in Qiskit 1.3 - # so filtering these warning when building pass managers - return common.generate_scheduling( - instruction_durations, scheduling_method, timing_constraints, inst_map, target - ) + return common.generate_scheduling( + instruction_durations, scheduling_method, timing_constraints, target + ) class DefaultSchedulingPassManager(PassManagerStagePlugin): @@ -689,16 +678,11 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana instruction_durations = pass_manager_config.instruction_durations scheduling_method = None timing_constraints = pass_manager_config.timing_constraints or TimingConstraints() - inst_map = pass_manager_config.inst_map target = pass_manager_config.target - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # Passing `inst_map` to `generate_scheduling` is deprecated in Qiskit 1.3 - # so filtering these warning when building pass managers - return common.generate_scheduling( - instruction_durations, scheduling_method, timing_constraints, inst_map, target - ) + return common.generate_scheduling( + instruction_durations, scheduling_method, timing_constraints, target + ) class DefaultLayoutPassManager(PassManagerStagePlugin): diff --git a/qiskit/transpiler/preset_passmanagers/common.py b/qiskit/transpiler/preset_passmanagers/common.py index 10c738e4720d..fe85d31209ac 100644 --- a/qiskit/transpiler/preset_passmanagers/common.py +++ b/qiskit/transpiler/preset_passmanagers/common.py @@ -563,9 +563,7 @@ def _direction_condition(property_set): return PassManager(unroll) -def generate_scheduling( - instruction_durations, scheduling_method, timing_constraints, _, target=None -): +def generate_scheduling(instruction_durations, scheduling_method, timing_constraints, target=None): """Generate a post optimization scheduling :class:`~qiskit.transpiler.PassManager` Args: diff --git a/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py b/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py index 0deb1879a07e..38a9ae26f67a 100644 --- a/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +++ b/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py @@ -14,7 +14,6 @@ Preset pass manager generation function """ -import copy import warnings from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES, get_control_flow_name_mapping @@ -30,7 +29,6 @@ from qiskit.transpiler.target import Target from qiskit.transpiler.timing_constraints import TimingConstraints from qiskit.utils import deprecate_arg -from qiskit.utils.deprecate_pulse import deprecate_pulse_arg from .level0 import level_0_pass_manager from .level1 import level_1_pass_manager @@ -56,13 +54,11 @@ "with defined timing constraints with " "`Target.from_configuration(..., timing_constraints=...)`", ) -@deprecate_pulse_arg("inst_map", predicate=lambda inst_map: inst_map is not None) def generate_preset_pass_manager( optimization_level=2, backend=None, target=None, basis_gates=None, - inst_map=None, coupling_map=None, instruction_durations=None, timing_constraints=None, @@ -93,7 +89,7 @@ def generate_preset_pass_manager( The target constraints for the pass manager construction can be specified through a :class:`.Target` instance, a :class:`.BackendV1` or :class:`.BackendV2` instance, or via loose constraints - (``basis_gates``, ``inst_map``, ``coupling_map``, ``instruction_durations``, + (``basis_gates``, ``coupling_map``, ``instruction_durations``, ``dt`` or ``timing_constraints``). The order of priorities for target constraints works as follows: if a ``target`` input is provided, it will take priority over any ``backend`` input or loose constraints. @@ -111,7 +107,6 @@ def generate_preset_pass_manager( **basis_gates** target basis_gates basis_gates **coupling_map** target coupling_map coupling_map **instruction_durations** target instruction_durations instruction_durations - **inst_map** target inst_map inst_map **dt** target dt dt **timing_constraints** target timing_constraints timing_constraints ============================ ========= ======================== ======================= @@ -129,7 +124,7 @@ def generate_preset_pass_manager( * 3: even heavier optimization backend (Backend): An optional backend object which can be used as the - source of the default values for the ``basis_gates``, ``inst_map``, + source of the default values for the ``basis_gates``, ``coupling_map``, ``instruction_durations``, ``timing_constraints``, and ``target``. If any of those other arguments are specified in addition to ``backend`` they will take precedence @@ -137,14 +132,9 @@ def generate_preset_pass_manager( target (Target): The :class:`~.Target` representing a backend compilation target. The following attributes will be inferred from this argument if they are not set: ``coupling_map``, ``basis_gates``, - ``instruction_durations``, ``inst_map`` and ``timing_constraints``. + ``instruction_durations`` and ``timing_constraints``. basis_gates (list): List of basis gate names to unroll to (e.g: ``['u1', 'u2', 'u3', 'cx']``). - inst_map (InstructionScheduleMap): DEPRECATED. Mapping object that maps gates to schedules. - If any user defined calibration is found in the map and this is used in a - circuit, transpiler attaches the custom gate definition to the circuit. - This enables one to flexibly override the low-level instruction - implementation. coupling_map (CouplingMap or list): Directed graph represented a coupling map. Multiple formats are supported: @@ -283,8 +273,6 @@ def generate_preset_pass_manager( ) backend = BackendV2Converter(backend) - # Check if a custom inst_map was specified before overwriting inst_map - _given_inst_map = bool(inst_map) # If there are no loose constraints => use backend target if available _no_loose_constraints = ( basis_gates is None @@ -306,12 +294,9 @@ def generate_preset_pass_manager( dt = _parse_dt(dt, backend) instruction_durations = _parse_instruction_durations(backend, instruction_durations, dt) timing_constraints = _parse_timing_constraints(backend, timing_constraints) - inst_map = _parse_inst_map(inst_map, backend) # The basis gates parser will set _skip_target to True if a custom basis gate is found # (known edge case). - basis_gates, name_mapping, _skip_target = _parse_basis_gates( - basis_gates, backend, inst_map, _skip_target - ) + basis_gates, name_mapping, _skip_target = _parse_basis_gates(basis_gates, backend, _skip_target) coupling_map = _parse_coupling_map(coupling_map, backend) if target is None: @@ -319,38 +304,21 @@ def generate_preset_pass_manager( # If a backend is specified without loose constraints, use its target directly. target = backend.target elif not _skip_target: - # Only parse backend properties when the target isn't skipped to - # preserve the former behavior of transpile. - with warnings.catch_warnings(): - # TODO: inst_map will be removed in 2.0 - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message=".*``inst_map`` is deprecated as of Qiskit 1.3.*", - module="qiskit", - ) - # Build target from constraints. - target = Target.from_configuration( - basis_gates=basis_gates, - num_qubits=backend.num_qubits if backend is not None else None, - coupling_map=coupling_map, - # If the instruction map has custom gates, do not give as config, the information - # will be added to the target with update_from_instruction_schedule_map - inst_map=inst_map if inst_map and not inst_map.has_custom_gate() else None, - instruction_durations=instruction_durations, - concurrent_measurements=( - backend.target.concurrent_measurements if backend is not None else None - ), - dt=dt, - timing_constraints=timing_constraints, - custom_name_mapping=name_mapping, - ) - - # Update target with custom gate information. Note that this is an exception to the priority - # order (target > loose constraints), added to handle custom gates for scheduling passes. - if target is not None and _given_inst_map and inst_map.has_custom_gate(): - target = copy.deepcopy(target) - target.update_from_instruction_schedule_map(inst_map) + # Build target from constraints. + target = Target.from_configuration( + basis_gates=basis_gates, + num_qubits=backend.num_qubits if backend is not None else None, + coupling_map=coupling_map, + # If the instruction map has custom gates, do not give as config, the information + # will be added to the target with update_from_instruction_schedule_map + instruction_durations=instruction_durations, + concurrent_measurements=( + backend.target.concurrent_measurements if backend is not None else None + ), + dt=dt, + timing_constraints=timing_constraints, + custom_name_mapping=name_mapping, + ) if target is not None: if coupling_map is None: @@ -359,8 +327,6 @@ def generate_preset_pass_manager( basis_gates = target.operation_names if instruction_durations is None: instruction_durations = target.durations() - if inst_map is None: - inst_map = target._get_instruction_schedule_map() if timing_constraints is None: timing_constraints = target.timing_constraints() @@ -372,7 +338,6 @@ def generate_preset_pass_manager( pm_options = { "target": target, "basis_gates": basis_gates, - "inst_map": inst_map, "coupling_map": coupling_map, "instruction_durations": instruction_durations, "timing_constraints": timing_constraints, @@ -391,32 +356,25 @@ def generate_preset_pass_manager( "qubits_initially_zero": qubits_initially_zero, } - with warnings.catch_warnings(): - # inst_map is deprecated in the PassManagerConfig initializer - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message=".*argument ``inst_map`` is deprecated as of Qiskit 1.3", - ) - if backend is not None: - pm_options["_skip_target"] = _skip_target - pm_config = PassManagerConfig.from_backend(backend, **pm_options) - else: - pm_config = PassManagerConfig(**pm_options) - if optimization_level == 0: - pm = level_0_pass_manager(pm_config) - elif optimization_level == 1: - pm = level_1_pass_manager(pm_config) - elif optimization_level == 2: - pm = level_2_pass_manager(pm_config) - elif optimization_level == 3: - pm = level_3_pass_manager(pm_config) - else: - raise ValueError(f"Invalid optimization level {optimization_level}") + if backend is not None: + pm_options["_skip_target"] = _skip_target + pm_config = PassManagerConfig.from_backend(backend, **pm_options) + else: + pm_config = PassManagerConfig(**pm_options) + if optimization_level == 0: + pm = level_0_pass_manager(pm_config) + elif optimization_level == 1: + pm = level_1_pass_manager(pm_config) + elif optimization_level == 2: + pm = level_2_pass_manager(pm_config) + elif optimization_level == 3: + pm = level_3_pass_manager(pm_config) + else: + raise ValueError(f"Invalid optimization level {optimization_level}") return pm -def _parse_basis_gates(basis_gates, backend, inst_map, skip_target): +def _parse_basis_gates(basis_gates, backend, skip_target): standard_gates = get_standard_gate_name_mapping() # Add control flow gates by default to basis set and name mapping default_gates = {"measure", "delay", "reset"}.union(CONTROL_FLOW_OP_NAMES) @@ -455,7 +413,7 @@ def _parse_basis_gates(basis_gates, backend, inst_map, skip_target): {name: backend.target.operation_from_name(name) for name in backend.operation_names} ) - # Check for custom instructions before removing calibrations + # Check for custom instructions for inst in instructions: if inst not in standard_gates and inst not in default_gates: if inst not in backend.operation_names: @@ -472,24 +430,9 @@ def _parse_basis_gates(basis_gates, backend, inst_map, skip_target): skip_target = True break - # Remove calibrated instructions, as they will be added later from the instruction schedule map - if inst_map is not None and not skip_target: - for inst in inst_map.instructions: - for qubit in inst_map.qubits_with_instruction(inst): - entry = inst_map._get_calibration_entry(inst, qubit) - if entry.user_provided and inst in instructions: - instructions.remove(inst) - return list(instructions) if instructions else None, name_mapping, skip_target -def _parse_inst_map(inst_map, backend): - # try getting inst_map from user, else backend - if inst_map is None and backend is not None: - inst_map = backend.target._get_instruction_schedule_map() - return inst_map - - def _parse_dt(dt, backend): # try getting dt from user, else backend if dt is None and backend is not None: diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index d1d1d7f7b3dd..6ee764c2fc06 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -37,28 +37,19 @@ BaseInstructionProperties, ) -from qiskit.circuit.parameter import Parameter -from qiskit.circuit.parameterexpression import ParameterValueType -from qiskit.circuit.gate import Gate from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping from qiskit.circuit.duration import duration_in_dt -from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap -from qiskit.pulse.calibration_entries import CalibrationEntry, ScheduleDef -from qiskit.pulse.schedule import Schedule, ScheduleBlock from qiskit.transpiler.coupling import CouplingMap from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.instruction_durations import InstructionDurations from qiskit.transpiler.timing_constraints import TimingConstraints from qiskit.providers.exceptions import BackendPropertyError -from qiskit.pulse.exceptions import PulseError, UnassignedDurationError -from qiskit.exceptions import QiskitError # import QubitProperties here to provide convenience alias for building a # full target from qiskit.providers.backend import QubitProperties # pylint: disable=unused-import from qiskit.providers.models.backendproperties import BackendProperties from qiskit.utils import deprecate_func -from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency, deprecate_pulse_arg logger = logging.getLogger(__name__) @@ -73,10 +64,6 @@ class InstructionProperties(BaseInstructionProperties): custom attributes for those custom/additional properties by the backend. """ - __slots__ = [ - "_calibration", - ] - def __new__( # pylint: disable=keyword-arg-before-vararg cls, duration=None, # pylint: disable=keyword-arg-before-vararg @@ -88,12 +75,10 @@ def __new__( # pylint: disable=keyword-arg-before-vararg cls, duration, error ) - @deprecate_pulse_arg("calibration", predicate=lambda cals: cals is not None) def __init__( self, duration: float | None = None, # pylint: disable=unused-argument error: float | None = None, # pylint: disable=unused-argument - calibration: Schedule | ScheduleBlock | CalibrationEntry | None = None, ): """Create a new ``InstructionProperties`` object @@ -102,79 +87,11 @@ def __init__( specified set of qubits error: The average error rate for the instruction on the specified set of qubits. - calibration: DEPRECATED. The pulse representation of the instruction. """ super().__init__() - self._calibration: CalibrationEntry | None = None - self._calibration_prop = calibration - - @property - @deprecate_pulse_dependency(is_property=True) - def calibration(self): - """The pulse representation of the instruction. - - .. note:: - - This attribute always returns a Qiskit pulse program, but it is internally - wrapped by the :class:`.CalibrationEntry` to manage unbound parameters - and to uniformly handle different data representation, - for example, un-parsed Pulse Qobj JSON that a backend provider may provide. - - This value can be overridden through the property setter in following manner. - When you set either :class:`.Schedule` or :class:`.ScheduleBlock` this is - always treated as a user-defined (custom) calibration and - the transpiler may automatically attach the calibration data to the output circuit. - This calibration data may appear in the wire format as an inline calibration, - which may further update the backend standard instruction set architecture. - - If you are a backend provider who provides a default calibration data - that is not needed to be attached to the transpiled quantum circuit, - you can directly set :class:`.CalibrationEntry` instance to this attribute, - in which you should set :code:`user_provided=False` when you define - calibration data for the entry. End users can still intentionally utilize - the calibration data, for example, to run pulse-level simulation of the circuit. - However, such entry doesn't appear in the wire format, and backend must - use own definition to compile the circuit down to the execution format. - - """ - return self._calibration_prop - - @calibration.setter - @deprecate_pulse_dependency(is_property=True) - def calibration(self, calibration: Schedule | ScheduleBlock | CalibrationEntry): - self._calibration_prop = calibration - - @property - def _calibration_prop(self): - if self._calibration is None: - return None - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # Clean this alternative path from deprecation warning emitted by `get_schedule` - return self._calibration.get_schedule() - - @_calibration_prop.setter - def _calibration_prop(self, calibration: Schedule | ScheduleBlock | CalibrationEntry): - if isinstance(calibration, (Schedule, ScheduleBlock)): - new_entry = ScheduleDef() - new_entry.define(calibration, user_provided=True) - else: - new_entry = calibration - self._calibration = new_entry def __repr__(self): - return ( - f"InstructionProperties(duration={self.duration}, error={self.error}" - f", calibration={self._calibration})" - ) - - def __getstate__(self) -> tuple: - return (super().__getstate__(), self._calibration_prop, self._calibration) - - def __setstate__(self, state: tuple): - super().__setstate__(state[0]) - self._calibration_prop = state[1] - self._calibration = state[2] + return f"InstructionProperties(duration={self.duration}, error={self.error})" class Target(BaseTarget): @@ -463,125 +380,6 @@ def update_instruction_properties(self, instruction, qargs, properties): self._instruction_durations = None self._instruction_schedule_map = None - @deprecate_pulse_dependency - def update_from_instruction_schedule_map(self, inst_map, inst_name_map=None, error_dict=None): - """Update the target from an instruction schedule map. - - If the input instruction schedule map contains new instructions not in - the target they will be added. However, if it contains additional qargs - for an existing instruction in the target it will error. - - Args: - inst_map (InstructionScheduleMap): The instruction - inst_name_map (dict): An optional dictionary that maps any - instruction name in ``inst_map`` to an instruction object. - If not provided, instruction is pulled from the standard Qiskit gates, - and finally custom gate instance is created with schedule name. - error_dict (dict): A dictionary of errors of the form:: - - {gate_name: {qarg: error}} - - for example:: - - {'rx': {(0, ): 1.4e-4, (1, ): 1.2e-4}} - - For each entry in the ``inst_map`` if ``error_dict`` is defined - a when updating the ``Target`` the error value will be pulled from - this dictionary. If one is not found in ``error_dict`` then - ``None`` will be used. - """ - get_calibration = getattr(inst_map, "_get_calibration_entry") - - # Expand name mapping with custom gate name provided by user. - qiskit_inst_name_map = get_standard_gate_name_mapping() - if inst_name_map is not None: - qiskit_inst_name_map.update(inst_name_map) - - for inst_name in inst_map.instructions: - # Prepare dictionary of instruction properties - out_props = {} - for qargs in inst_map.qubits_with_instruction(inst_name): - try: - qargs = tuple(qargs) - except TypeError: - qargs = (qargs,) - try: - props = self._gate_map[inst_name][qargs] - except (KeyError, TypeError): - props = None - - entry = get_calibration(inst_name, qargs) - if entry.user_provided and getattr(props, "_calibration", None) != entry: - # It only copies user-provided calibration from the inst map. - # Backend defined entry must already exist in Target. - if self.dt is not None: - try: - duration = entry.get_schedule().duration * self.dt - except UnassignedDurationError: - # duration of schedule is parameterized - duration = None - else: - duration = None - props = InstructionProperties( - duration=duration, - calibration=entry, - ) - else: - if props is None: - # Edge case. Calibration is backend defined, but this is not - # registered in the backend target. Ignore this entry. - continue - try: - # Update gate error if provided. - props.error = error_dict[inst_name][qargs] - except (KeyError, TypeError): - pass - out_props[qargs] = props - if not out_props: - continue - # Prepare Qiskit Gate object assigned to the entries - if inst_name not in self._gate_map: - # Entry not found: Add new instruction - if inst_name in qiskit_inst_name_map: - # Remove qargs with length that doesn't match with instruction qubit number - inst_obj = qiskit_inst_name_map[inst_name] - normalized_props = {} - for qargs, prop in out_props.items(): - if len(qargs) != inst_obj.num_qubits: - continue - normalized_props[qargs] = prop - self.add_instruction(inst_obj, normalized_props, name=inst_name) - else: - # Check qubit length parameter name uniformity. - qlen = set() - param_names = set() - for qargs in inst_map.qubits_with_instruction(inst_name): - if isinstance(qargs, int): - qargs = (qargs,) - qlen.add(len(qargs)) - cal = getattr(out_props[tuple(qargs)], "_calibration") - param_names.add(tuple(cal.get_signature().parameters.keys())) - if len(qlen) > 1 or len(param_names) > 1: - raise QiskitError( - f"Schedules for {inst_name} are defined non-uniformly for " - f"multiple qubit lengths {qlen}, " - f"or different parameter names {param_names}. " - "Provide these schedules with inst_name_map or define them with " - "different names for different gate parameters." - ) - inst_obj = Gate( - name=inst_name, - num_qubits=next(iter(qlen)), - params=list(map(Parameter, next(iter(param_names)))), - ) - self.add_instruction(inst_obj, out_props, name=inst_name) - else: - # Entry found: Update "existing" instructions. - for qargs, prop in out_props.items(): - if qargs not in self._gate_map[inst_name]: - continue - self.update_instruction_properties(inst_name, qargs, prop) - def qargs_for_operation_name(self, operation): """Get the qargs for a given operation name @@ -621,104 +419,6 @@ def timing_constraints(self): self.granularity, self.min_length, self.pulse_alignment, self.acquire_alignment ) - @deprecate_pulse_dependency - def instruction_schedule_map(self): - """Return an :class:`~qiskit.pulse.InstructionScheduleMap` for the - instructions in the target with a pulse schedule defined. - - Returns: - InstructionScheduleMap: The instruction schedule map for the - instructions in this target with a pulse schedule defined. - """ - return self._get_instruction_schedule_map() - - def _get_instruction_schedule_map(self): - if self._instruction_schedule_map is not None: - return self._instruction_schedule_map - with warnings.catch_warnings(): - warnings.simplefilter(action="ignore", category=DeprecationWarning) - # `InstructionScheduleMap` is deprecated in Qiskit 1.3 but we want this alternative - # path to be clean of deprecation warnings - out_inst_schedule_map = InstructionScheduleMap() - - for instruction, qargs in self._gate_map.items(): - for qarg, properties in qargs.items(): - # Directly getting CalibrationEntry not to invoke .get_schedule(). - # This keeps PulseQobjDef un-parsed. - cal_entry = getattr(properties, "_calibration", None) - if cal_entry is not None: - # Use fast-path to add entries to the inst map. - out_inst_schedule_map._add(instruction, qarg, cal_entry) - self._instruction_schedule_map = out_inst_schedule_map - return out_inst_schedule_map - - @deprecate_pulse_dependency - def has_calibration( - self, - operation_name: str, - qargs: tuple[int, ...], - ) -> bool: - """Return whether the instruction (operation + qubits) defines a calibration. - - Args: - operation_name: The name of the operation for the instruction. - qargs: The tuple of qubit indices for the instruction. - - Returns: - Returns ``True`` if the calibration is supported and ``False`` if it isn't. - """ - return self._has_calibration(operation_name, qargs) - - def _has_calibration( - self, - operation_name: str, - qargs: tuple[int, ...], - ) -> bool: - qargs = tuple(qargs) - if operation_name not in self._gate_map: - return False - if qargs not in self._gate_map[operation_name]: - return False - return getattr(self._gate_map[operation_name][qargs], "_calibration", None) is not None - - @deprecate_pulse_dependency - def get_calibration( - self, - operation_name: str, - qargs: tuple[int, ...], - *args: ParameterValueType, - **kwargs: ParameterValueType, - ) -> Schedule | ScheduleBlock: - """Get calibrated pulse schedule for the instruction. - - If calibration is templated with parameters, one can also provide those values - to build a schedule with assigned parameters. - - Args: - operation_name: The name of the operation for the instruction. - qargs: The tuple of qubit indices for the instruction. - args: Parameter values to build schedule if any. - kwargs: Parameter values with name to build schedule if any. - - Returns: - Calibrated pulse schedule of corresponding instruction. - """ - return self._get_calibration(operation_name, qargs, *args, *kwargs) - - def _get_calibration( - self, - operation_name: str, - qargs: tuple[int, ...], - *args: ParameterValueType, - **kwargs: ParameterValueType, - ) -> Schedule | ScheduleBlock: - if not self._has_calibration(operation_name, qargs): - raise KeyError( - f"Calibration of instruction {operation_name} for qubit {qargs} is not defined." - ) - cal_entry = getattr(self._gate_map[operation_name][qargs], "_calibration") - return cal_entry.get_schedule(*args, **kwargs) - @property def operation_names(self): """Get the operation names in the target.""" @@ -941,9 +641,6 @@ def __str__(self): error = getattr(props, "error", None) if error is not None: prop_str_pieces.append(f"\t\t\tError Rate: {error:g}\n") - schedule = getattr(props, "_calibration", None) - if schedule is not None: - prop_str_pieces.append("\t\t\tWith pulse schedule calibration\n") extra_props = getattr(props, "properties", None) if extra_props is not None: extra_props_pieces = [ @@ -983,13 +680,11 @@ def seconds_to_dt(self, duration: float) -> int: return duration_in_dt(duration, self.dt) @classmethod - @deprecate_pulse_arg("inst_map") def from_configuration( cls, basis_gates: list[str], num_qubits: int | None = None, coupling_map: CouplingMap | None = None, - inst_map: InstructionScheduleMap | None = None, backend_properties: BackendProperties | None = None, instruction_durations: InstructionDurations | None = None, concurrent_measurements: Optional[List[List[int]]] = None, @@ -1022,14 +717,6 @@ def from_configuration( coupling_map: The coupling map representing connectivity constraints on the backend. If specified all gates from ``basis_gates`` will be supported on all qubits (or pairs of qubits). - inst_map: DEPRECATED. The instruction schedule map representing the pulse - :class:`~.Schedule` definitions for each instruction. If this - is specified ``coupling_map`` must be specified. The - ``coupling_map`` is used as the source of truth for connectivity - and if ``inst_map`` is used the schedule is looked up based - on the instructions from the pair of ``basis_gates`` and - ``coupling_map``. If you want to define a custom gate for - a particular qubit or qubit pair, you can manually build :class:`.Target`. backend_properties: The :class:`~.BackendProperties` object which is used for instruction properties and qubit properties. If specified and instruction properties are intended to be used @@ -1137,7 +824,6 @@ def from_configuration( for qubit in range(num_qubits): error = None duration = None - calibration = None if backend_properties is not None: if duration is None: try: @@ -1148,17 +834,6 @@ def from_configuration( error = backend_properties.gate_error(gate, qubit) except BackendPropertyError: error = None - if inst_map is not None: - try: - calibration = inst_map._get_calibration_entry(gate, qubit) - # If we have dt defined and there is a custom calibration which is user - # generate use that custom pulse schedule for the duration. If it is - # not user generated than we assume it's the same duration as what is - # defined in the backend properties - if dt and calibration.user_provided: - duration = calibration.get_schedule().duration * dt - except PulseError: - calibration = None # Durations if specified manually should override model objects if instruction_durations is not None: try: @@ -1166,19 +841,12 @@ def from_configuration( except TranspilerError: duration = None - if error is None and duration is None and calibration is None: + if error is None and duration is None: gate_properties[(qubit,)] = None else: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message=".*``calibration`` is deprecated as of Qiskit 1.3.*", - module="qiskit", - ) - gate_properties[(qubit,)] = InstructionProperties( - duration=duration, error=error, calibration=calibration - ) + gate_properties[(qubit,)] = InstructionProperties( + duration=duration, error=error + ) target.add_instruction(name_mapping[gate], properties=gate_properties, name=gate) edges = list(coupling_map.get_edges()) for gate in two_qubit_gates: @@ -1186,7 +854,6 @@ def from_configuration( for edge in edges: error = None duration = None - calibration = None if backend_properties is not None: if duration is None: try: @@ -1197,17 +864,6 @@ def from_configuration( error = backend_properties.gate_error(gate, edge) except BackendPropertyError: error = None - if inst_map is not None: - try: - calibration = inst_map._get_calibration_entry(gate, edge) - # If we have dt defined and there is a custom calibration which is user - # generate use that custom pulse schedule for the duration. If it is - # not user generated than we assume it's the same duration as what is - # defined in the backend properties - if dt and calibration.user_provided: - duration = calibration.get_schedule().duration * dt - except PulseError: - calibration = None # Durations if specified manually should override model objects if instruction_durations is not None: try: @@ -1215,19 +871,12 @@ def from_configuration( except TranspilerError: duration = None - if error is None and duration is None and calibration is None: + if error is None and duration is None: gate_properties[edge] = None else: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message=".*``calibration`` is deprecated as of Qiskit 1.3.*", - module="qiskit", - ) - gate_properties[edge] = InstructionProperties( - duration=duration, error=error, calibration=calibration - ) + gate_properties[edge] = InstructionProperties( + duration=duration, error=error + ) target.add_instruction(name_mapping[gate], properties=gate_properties, name=gate) for gate in global_ideal_variable_width_gates: target.add_instruction(name_mapping[gate], name=gate) diff --git a/qiskit/visualization/circuit/_utils.py b/qiskit/visualization/circuit/_utils.py index 8ae38a9ab949..343fb4e4eca1 100644 --- a/qiskit/visualization/circuit/_utils.py +++ b/qiskit/visualization/circuit/_utils.py @@ -44,7 +44,7 @@ def _is_boolean_expression(gate_text, op): return isinstance(op, (PhaseOracleGate, BitFlipOracleGate)) and gate_text == op.label -def get_gate_ctrl_text(op, drawer, style=None, calibrations=None): +def get_gate_ctrl_text(op, drawer, style=None): """Load the gate_text and ctrl_text strings based on names and labels""" anno_list = [] anno_text = "" @@ -119,13 +119,6 @@ def get_gate_ctrl_text(op, drawer, style=None, calibrations=None): ) and (op_type is not PauliEvolutionGate): gate_text = gate_text.capitalize() - if drawer == "mpl" and op.name in calibrations: - if isinstance(op, ControlledGate): - ctrl_text = "" if ctrl_text is None else ctrl_text - ctrl_text = "(cal)\n" + ctrl_text - else: - gate_text = gate_text + "\n(cal)" - if anno_text: gate_text += " - " + anno_text diff --git a/qiskit/visualization/circuit/matplotlib.py b/qiskit/visualization/circuit/matplotlib.py index 6f7359021839..73160f0a1b51 100644 --- a/qiskit/visualization/circuit/matplotlib.py +++ b/qiskit/visualization/circuit/matplotlib.py @@ -135,7 +135,6 @@ def __init__( self._initial_state = initial_state self._global_phase = self._circuit.global_phase - self._calibrations = self._circuit._calibrations_prop self._expr_len = expr_len self._cregbundle = cregbundle @@ -420,7 +419,7 @@ def _get_layer_widths(self, node_data, wire_map, outer_circuit, glob_data): base_type = getattr(op, "base_gate", None) gate_text, ctrl_text, raw_gate_text = get_gate_ctrl_text( - op, "mpl", style=self._style, calibrations=self._calibrations + op, "mpl", style=self._style ) node_data[node].gate_text = gate_text node_data[node].ctrl_text = ctrl_text @@ -1455,7 +1454,7 @@ def _multiqubit_gate(self, node, node_data, glob_data, xy=None): # Swap gate if isinstance(op, SwapGate): - self._swap(xy, node, node_data, node_data[node].lc) + self._swap(xy, node_data[node].lc) return # RZZ Gate @@ -1747,7 +1746,7 @@ def _control_gate(self, node, node_data, glob_data, mod_control): self._gate(node, node_data, glob_data, xy[num_ctrl_qubits:][0]) elif isinstance(base_type, SwapGate): - self._swap(xy[num_ctrl_qubits:], node, node_data, node_data[node].lc) + self._swap(xy[num_ctrl_qubits:], node_data[node].lc) else: self._multiqubit_gate(node, node_data, glob_data, xy[num_ctrl_qubits:]) @@ -1882,28 +1881,12 @@ def _symmetric_gate(self, node, node_data, base_type, glob_data): ) self._line(qubit_b, qubit_t, lc=lc) - def _swap(self, xy, node, node_data, color=None): + def _swap(self, xy, color=None): """Draw a Swap gate""" self._swap_cross(xy[0], color=color) self._swap_cross(xy[1], color=color) self._line(xy[0], xy[1], lc=color) - # add calibration text - gate_text = node_data[node].gate_text.split("\n")[-1] - if node_data[node].raw_gate_text in self._calibrations: - xpos, ypos = xy[0] - self._ax.text( - xpos, - ypos + 0.7 * HIG, - gate_text, - ha="center", - va="top", - fontsize=self._style["sfs"], - color=self._style["tc"], - clip_on=True, - zorder=PORDER_TEXT, - ) - def _swap_cross(self, xy, color=None): """Draw the Swap cross symbol""" xpos, ypos = xy diff --git a/releasenotes/notes/remove-pulse-calibrations-4486dc101b76ec51.yaml b/releasenotes/notes/remove-pulse-calibrations-4486dc101b76ec51.yaml new file mode 100644 index 000000000000..314e2e8893c6 --- /dev/null +++ b/releasenotes/notes/remove-pulse-calibrations-4486dc101b76ec51.yaml @@ -0,0 +1,37 @@ +--- +upgrade_circuits: + - | + As part of Pulse removal in Qiskit 2.0, the ``calibrations`` property has been removed + from the :class:`.QuantumCircuit`, :class:`.DAGCircuit` and :class:`.DAGDependency` classes. + In addition, the method ``has_calibration_for`` has been removed from the :class:`.QuantumCircuit` and + :class:`.DAGCircuit` classes and ``add_calibration`` has been removed from :class:`.QuantumCircuit`. +upgrade_transpiler: + - | + As part of Pulse removal in Qiskit 2.0, all pulse and calibration related functionality + in the transpiler has been removed. This includes the following: + + Passes that have been removed: + + * ``qiskit.transpiler.passes.PulseGates`` + * ``qiskit.transpiler.passes.ValidatePulseGates`` + * ``qiskit.transpiler.passes.RXCalibrationBuilder`` + * ``qiskit.transpiler.passes.RZXCalibrationBuilder`` + * ``qiskit.transpiler.passes.RZXCalibrationBuilderNoEcho`` + * ``qiskit.transpiler.passes.EchoRZXWeylDecomposition`` + + The ``inst_map`` argument has been removed from the following elements: + + * The :func:`.generate_preset_pass_manager` and :func:`.transpile` functions + * The :meth:`.Target.from_configuration` method + * The constructor of the :class:`.PassManagerConfig` class + + Calibration support has been removed: + + * ``calibration`` has been removed from the :class:`.InstructionProperties` 's constructor and is no longer a property of that class. + * The ``has_calibration``, ``get_calibration``, ``instruction_schedule_map`` and ``update_from_instruction_schedule_map`` methods have been removed from the :class:`.Target` class. + + +upgrade_misc: + - | + As part of Pulse removal in Qiskit 2.0, the ``sequence`` and ``schedule_circuit`` functions from :mod:`.qiskit.scheduler` + together with the ``ScheduleConfig`` class have been removed. diff --git a/releasenotes/notes/remove-pulse-passes-3128f27ed7e42bf6.yaml b/releasenotes/notes/remove-pulse-passes-3128f27ed7e42bf6.yaml deleted file mode 100644 index 49e176ce93b1..000000000000 --- a/releasenotes/notes/remove-pulse-passes-3128f27ed7e42bf6.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -upgrade_transpiler: - - | - The ``PulseGates``, ``ValidatePulseGates``, ``RXCalibrationBuilder``, ``RZXCalibrationBuilder``, - ``RZXCalibrationBuilderNoEcho`` and ``EchoRZXWeylDecomposition`` passes have been removed, - following their deprecation in Qiskit 1.3. These passes depend on and relate to the Pulse - package which is also being removed in Qiskit 2.0. diff --git a/test/python/circuit/test_calibrations.py b/test/python/circuit/test_calibrations.py deleted file mode 100644 index 6df7302ee50e..000000000000 --- a/test/python/circuit/test_calibrations.py +++ /dev/null @@ -1,61 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Test calibrations in quantum circuits.""" - -import unittest - -from qiskit.pulse import Schedule -from qiskit.circuit import QuantumCircuit -from qiskit.circuit.library import RZXGate -from test import QiskitTestCase # pylint: disable=wrong-import-order - - -class TestCalibrations(QiskitTestCase): - """Test composition of two circuits.""" - - def test_iadd(self): - """Test that __iadd__ keeps the calibrations.""" - qc_cal = QuantumCircuit(2) - qc_cal.rzx(0.5, 0, 1) - with self.assertWarns(DeprecationWarning): - qc_cal.add_calibration(RZXGate, (0, 1), params=[0.5], schedule=Schedule()) - - qc = QuantumCircuit(2) - qc &= qc_cal - - with self.assertWarns(DeprecationWarning): - self.assertEqual(qc.calibrations[RZXGate], {((0, 1), (0.5,)): Schedule(name="test")}) - self.assertEqual(qc_cal.calibrations, qc.calibrations) - - def test_add(self): - """Test that __add__ keeps the calibrations.""" - qc_cal = QuantumCircuit(2) - qc_cal.rzx(0.5, 0, 1) - with self.assertWarns(DeprecationWarning): - qc_cal.add_calibration(RZXGate, (0, 1), params=[0.5], schedule=Schedule()) - - qc = QuantumCircuit(2) & qc_cal - - with self.assertWarns(DeprecationWarning): - self.assertEqual(qc.calibrations[RZXGate], {((0, 1), (0.5,)): Schedule(name="test")}) - self.assertEqual(qc_cal.calibrations, qc.calibrations) - - qc = qc_cal & QuantumCircuit(2) - - with self.assertWarns(DeprecationWarning): - self.assertEqual(qc.calibrations[RZXGate], {((0, 1), (0.5,)): Schedule(name="test")}) - self.assertEqual(qc_cal.calibrations, qc.calibrations) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index ba2225f3b534..4b73805d75f9 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -31,7 +31,6 @@ from qiskit.circuit.quantumcircuitdata import CircuitInstruction from qiskit.circuit.quantumregister import AncillaQubit, AncillaRegister, Qubit from qiskit.providers.basic_provider import BasicSimulator -from qiskit.pulse import DriveChannel, Gaussian, Play, Schedule from qiskit.quantum_info import Operator from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -401,9 +400,6 @@ def test_copy_empty_like_circuit(self): qc.measure(qr[0], cr[0]) qc.measure(qr[1], cr[1]) - with self.assertWarns(DeprecationWarning): - sched = Schedule(Play(Gaussian(160, 0.1, 40), DriveChannel(0))) - qc.add_calibration("h", [0, 1], sched) copied = qc.copy_empty_like() qc.clear() @@ -411,8 +407,6 @@ def test_copy_empty_like_circuit(self): self.assertEqual(qc.global_phase, copied.global_phase) self.assertEqual(qc.name, copied.name) self.assertEqual(qc.metadata, copied.metadata) - with self.assertWarns(DeprecationWarning): - self.assertEqual(qc.calibrations, copied.calibrations) copied = qc.copy_empty_like("copy") self.assertEqual(copied.name, "copy") diff --git a/test/python/circuit/test_circuit_properties.py b/test/python/circuit/test_circuit_properties.py index 7296f09ae73d..f2cabba37056 100644 --- a/test/python/circuit/test_circuit_properties.py +++ b/test/python/circuit/test_circuit_properties.py @@ -15,10 +15,10 @@ import unittest import numpy as np -from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, pulse +from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.circuit import Clbit from qiskit.circuit.classical import expr, types -from qiskit.circuit.library import RXGate, RYGate, GlobalPhaseGate +from qiskit.circuit.library import GlobalPhaseGate from qiskit.circuit.exceptions import CircuitError from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -771,103 +771,6 @@ def test_num_qubits_multiple_register_circuit(self): circ = QuantumCircuit(q_reg1, q_reg2, q_reg3) self.assertEqual(circ.num_qubits, 18) - def test_calibrations_basis_gates(self): - """Check if the calibrations for basis gates provided are added correctly.""" - circ = QuantumCircuit(2) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - with pulse.build() as q1_y90: - pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), pulse.DriveChannel(1)) - - # Add calibration - circ.add_calibration(RXGate(3.14), [0], q0_x180) - circ.add_calibration(RYGate(1.57), [1], q1_y90) - - self.assertEqual(set(circ.calibrations.keys()), {"rx", "ry"}) - self.assertEqual(set(circ.calibrations["rx"].keys()), {((0,), (3.14,))}) - self.assertEqual(set(circ.calibrations["ry"].keys()), {((1,), (1.57,))}) - self.assertEqual( - circ.calibrations["rx"][((0,), (3.14,))].instructions, q0_x180.instructions - ) - self.assertEqual( - circ.calibrations["ry"][((1,), (1.57,))].instructions, q1_y90.instructions - ) - - def test_calibrations_custom_gates(self): - """Check if the calibrations for custom gates with params provided are added correctly.""" - circ = QuantumCircuit(3) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - - # Add calibrations with a custom gate 'rxt' - circ.add_calibration("rxt", [0], q0_x180, params=[1.57, 3.14, 4.71]) - - self.assertEqual(set(circ.calibrations.keys()), {"rxt"}) - self.assertEqual(set(circ.calibrations["rxt"].keys()), {((0,), (1.57, 3.14, 4.71))}) - self.assertEqual( - circ.calibrations["rxt"][((0,), (1.57, 3.14, 4.71))].instructions, - q0_x180.instructions, - ) - - def test_calibrations_no_params(self): - """Check calibrations if the no params is provided with just gate name.""" - circ = QuantumCircuit(3) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - - circ.add_calibration("h", [0], q0_x180) - - self.assertEqual(set(circ.calibrations.keys()), {"h"}) - self.assertEqual(set(circ.calibrations["h"].keys()), {((0,), ())}) - self.assertEqual(circ.calibrations["h"][((0,), ())].instructions, q0_x180.instructions) - - def test_has_calibration_for(self): - """Test that `has_calibration_for` returns a correct answer.""" - qc = QuantumCircuit(3) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - qc.add_calibration("h", [0], q0_x180) - - qc.h(0) - qc.h(1) - - with self.assertWarns(DeprecationWarning): - self.assertTrue(qc.has_calibration_for(qc.data[0])) - self.assertFalse(qc.has_calibration_for(qc.data[1])) - - def test_has_calibration_for_legacy(self): - """Test that `has_calibration_for` returns a correct answer when presented with a legacy 3 - tuple.""" - qc = QuantumCircuit(3) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - qc.add_calibration("h", [0], q0_x180) - - qc.h(0) - qc.h(1) - - with self.assertWarns(DeprecationWarning): - self.assertTrue( - qc.has_calibration_for( - (qc.data[0].operation, list(qc.data[0].qubits), list(qc.data[0].clbits)) - ) - ) - self.assertFalse( - qc.has_calibration_for( - (qc.data[1].operation, list(qc.data[1].qubits), list(qc.data[1].clbits)) - ) - ) - def test_metadata_copy_does_not_share_state(self): """Verify mutating the metadata of a circuit copy does not impact original.""" # ref: https://github.com/Qiskit/qiskit-terra/issues/6057 diff --git a/test/python/circuit/test_compose.py b/test/python/circuit/test_compose.py index 708bba974e02..a0e3e5ee4eff 100644 --- a/test/python/circuit/test_compose.py +++ b/test/python/circuit/test_compose.py @@ -18,8 +18,6 @@ import numpy as np -from qiskit import transpile -from qiskit.pulse import Schedule from qiskit.circuit import ( QuantumRegister, ClassicalRegister, @@ -488,38 +486,6 @@ def test_compose_gate(self): self.assertEqual(circuit_composed, circuit_expected) - def test_compose_calibrations(self): - """Test that composing two circuits updates calibrations.""" - circ_left = QuantumCircuit(1) - circ_right = QuantumCircuit(1) - with self.assertWarns(DeprecationWarning): - circ_left.add_calibration("h", [0], None) - circ_right.add_calibration("rx", [0], None) - circ = circ_left.compose(circ_right) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(circ.calibrations), 2) - self.assertEqual(len(circ_left.calibrations), 1) - - circ_left = QuantumCircuit(1) - circ_right = QuantumCircuit(1) - with self.assertWarns(DeprecationWarning): - circ_left.add_calibration("h", [0], None) - circ_right.add_calibration("h", [1], None) - circ = circ_left.compose(circ_right) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(circ.calibrations), 1) - self.assertEqual(len(circ.calibrations["h"]), 2) - self.assertEqual(len(circ_left.calibrations), 1) - - # Ensure that transpiled _calibration is defaultdict - qc = QuantumCircuit(2, 2) - qc.h(0) - qc.cx(0, 1) - qc.measure(0, 0) - qc = transpile(qc, None, basis_gates=["h", "cx"], coupling_map=[[0, 1], [1, 0]]) - with self.assertWarns(DeprecationWarning): - qc.add_calibration("cx", [0, 1], Schedule()) - def test_compose_one_liner(self): """Test building a circuit in one line, for fun.""" circ = QuantumCircuit(3) diff --git a/test/python/circuit/test_parameters.py b/test/python/circuit/test_parameters.py index 7d433be8f114..6459e4e41a07 100644 --- a/test/python/circuit/test_parameters.py +++ b/test/python/circuit/test_parameters.py @@ -15,7 +15,6 @@ import unittest import cmath import math -import copy import pickle from operator import add, mul, sub, truediv import numpy @@ -29,7 +28,6 @@ from qiskit.circuit.parametertable import ParameterView from qiskit.circuit.exceptions import CircuitError from qiskit.compiler import transpile -from qiskit import pulse from qiskit.quantum_info import Operator from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.providers.basic_provider import BasicSimulator @@ -723,165 +721,6 @@ def test_gate_multiplicity_binding(self): for instruction in qc2.data: self.assertEqual(float(instruction.operation.params[0]), 1.0) - def test_calibration_assignment(self): - """That that calibration mapping and the schedules they map are assigned together.""" - theta = Parameter("theta") - circ = QuantumCircuit(3, 3) - circ.append(Gate("rxt", 1, [theta]), [0]) - circ.measure(0, 0) - - with self.assertWarns(DeprecationWarning): - rxt_q0 = pulse.Schedule( - pulse.Play( - pulse.library.Gaussian(duration=128, sigma=16, amp=0.2 * theta / 3.14), - pulse.DriveChannel(0), - ) - ) - - circ.add_calibration("rxt", [0], rxt_q0, [theta]) - circ = circ.assign_parameters({theta: 3.14}) - - instruction = circ.data[0] - cal_key = ( - tuple(circ.find_bit(q).index for q in instruction.qubits), - tuple(instruction.operation.params), - ) - self.assertEqual(cal_key, ((0,), (3.14,))) - - with self.assertWarns(DeprecationWarning): - # Make sure that key from instruction data matches the calibrations dictionary - self.assertIn(cal_key, circ.calibrations["rxt"]) - sched = circ.calibrations["rxt"][cal_key] - self.assertEqual(sched.instructions[0][1].pulse.amp, 0.2) - - def test_calibration_assignment_doesnt_mutate(self): - """That that assignment doesn't mutate the original circuit.""" - theta = Parameter("theta") - circ = QuantumCircuit(3, 3) - circ.append(Gate("rxt", 1, [theta]), [0]) - circ.measure(0, 0) - - with self.assertWarns(DeprecationWarning): - rxt_q0 = pulse.Schedule( - pulse.Play( - pulse.library.Gaussian(duration=128, sigma=16, amp=0.2 * theta / 3.14), - pulse.DriveChannel(0), - ) - ) - - circ.add_calibration("rxt", [0], rxt_q0, [theta]) - circ_copy = copy.deepcopy(circ) - assigned_circ = circ.assign_parameters({theta: 3.14}) - - with self.assertWarns(DeprecationWarning): - self.assertEqual(circ.calibrations, circ_copy.calibrations) - self.assertNotEqual(assigned_circ.calibrations, circ.calibrations) - - def test_calibration_assignment_w_expressions(self): - """That calibrations with multiple parameters are assigned correctly""" - theta = Parameter("theta") - sigma = Parameter("sigma") - circ = QuantumCircuit(3, 3) - circ.append(Gate("rxt", 1, [theta / 2, sigma]), [0]) - circ.measure(0, 0) - - with self.assertWarns(DeprecationWarning): - rxt_q0 = pulse.Schedule( - pulse.Play( - pulse.library.Gaussian(duration=128, sigma=4 * sigma, amp=0.2 * theta / 3.14), - pulse.DriveChannel(0), - ) - ) - - circ.add_calibration("rxt", [0], rxt_q0, [theta / 2, sigma]) - circ = circ.assign_parameters({theta: 3.14, sigma: 4}) - - instruction = circ.data[0] - cal_key = ( - tuple(circ.find_bit(q).index for q in instruction.qubits), - tuple(instruction.operation.params), - ) - self.assertEqual(cal_key, ((0,), (3.14 / 2, 4))) - with self.assertWarns(DeprecationWarning): - # Make sure that key from instruction data matches the calibrations dictionary - self.assertIn(cal_key, circ.calibrations["rxt"]) - sched = circ.calibrations["rxt"][cal_key] - self.assertEqual(sched.instructions[0][1].pulse.amp, 0.2) - self.assertEqual(sched.instructions[0][1].pulse.sigma, 16) - - def test_substitution(self): - """Test Parameter substitution (vs bind).""" - alpha = Parameter("⍺") - beta = Parameter("beta") - with self.assertWarns(DeprecationWarning): - schedule = pulse.Schedule(pulse.ShiftPhase(alpha, pulse.DriveChannel(0))) - - circ = QuantumCircuit(3, 3) - circ.append(Gate("my_rz", 1, [alpha]), [0]) - with self.assertWarns(DeprecationWarning): - circ.add_calibration("my_rz", [0], schedule, [alpha]) - - circ = circ.assign_parameters({alpha: 2 * beta}) - - circ = circ.assign_parameters({beta: 1.57}) - with self.assertWarns(DeprecationWarning): - cal_sched = circ.calibrations["my_rz"][((0,), (3.14,))] - self.assertEqual(float(cal_sched.instructions[0][1].phase), 3.14) - - def test_partial_assignment(self): - """Expressions of parameters with partial assignment.""" - alpha = Parameter("⍺") - beta = Parameter("beta") - gamma = Parameter("γ") - phi = Parameter("ϕ") - - with self.assertWarns(DeprecationWarning): - with pulse.build() as my_cal: - pulse.set_frequency(alpha + beta, pulse.DriveChannel(0)) - pulse.shift_frequency(gamma + beta, pulse.DriveChannel(0)) - pulse.set_phase(phi, pulse.DriveChannel(1)) - - circ = QuantumCircuit(2, 2) - circ.append(Gate("custom", 2, [alpha, beta, gamma, phi]), [0, 1]) - with self.assertWarns(DeprecationWarning): - circ.add_calibration("custom", [0, 1], my_cal, [alpha, beta, gamma, phi]) - - # Partial bind - delta = 1e9 - freq = 4.5e9 - shift = 0.5e9 - phase = 3.14 / 4 - - circ = circ.assign_parameters({alpha: freq - delta}) - with self.assertWarns(DeprecationWarning): - cal_sched = list(circ.calibrations["custom"].values())[0] - with self.assertWarns(DeprecationWarning): - # instructions triggers conversion to Schedule - self.assertEqual(cal_sched.instructions[0][1].frequency, freq - delta + beta) - - circ = circ.assign_parameters({beta: delta}) - with self.assertWarns(DeprecationWarning): - cal_sched = list(circ.calibrations["custom"].values())[0] - with self.assertWarns(DeprecationWarning): - # instructions triggers conversion to Schedule - self.assertEqual(float(cal_sched.instructions[0][1].frequency), freq) - self.assertEqual(cal_sched.instructions[1][1].frequency, gamma + delta) - - circ = circ.assign_parameters({gamma: shift - delta}) - with self.assertWarns(DeprecationWarning): - cal_sched = list(circ.calibrations["custom"].values())[0] - with self.assertWarns(DeprecationWarning): - # instructions triggers conversion to Schedule - self.assertEqual(float(cal_sched.instructions[1][1].frequency), shift) - self.assertEqual(cal_sched.instructions[2][1].phase, phi) - - circ = circ.assign_parameters({phi: phase}) - with self.assertWarns(DeprecationWarning): - cal_sched = list(circ.calibrations["custom"].values())[0] - with self.assertWarns(DeprecationWarning): - # instructions triggers conversion to Schedule - self.assertEqual(float(cal_sched.instructions[2][1].phase), phase) - def test_circuit_generation(self): """Test creating a series of circuits parametrically""" theta = Parameter("θ") diff --git a/test/python/circuit/test_scheduled_circuit.py b/test/python/circuit/test_scheduled_circuit.py index 30adf3cdb48b..d4cbcbc69247 100644 --- a/test/python/circuit/test_scheduled_circuit.py +++ b/test/python/circuit/test_scheduled_circuit.py @@ -21,7 +21,6 @@ from qiskit.circuit.duration import convert_durations_to_dt from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.providers.basic_provider import BasicSimulator -from qiskit.scheduler import ScheduleConfig from qiskit.transpiler import InstructionProperties from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.instruction_durations import InstructionDurations @@ -390,12 +389,6 @@ def test_convert_duration_to_dt(self): Tests fix for bug reported in PR #11782.""" backend = GenericBackendV2(num_qubits=3, seed=42) - with self.assertWarns(DeprecationWarning): - 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) @@ -416,9 +409,7 @@ def test_convert_duration_to_dt(self): 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 - ) + converted_circ = convert_durations_to_dt(circuit, dt_in_sec=2.22e-10, inplace=False) self.assertEqual( converted_circ.duration, ref_duration, diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index f4c3fca15537..1b949d1239e9 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -27,7 +27,6 @@ ClassicalRegister, QuantumCircuit, QuantumRegister, - pulse, qasm3, qpy, ) @@ -79,7 +78,6 @@ from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.providers.basic_provider import BasicSimulator from qiskit.providers.options import Options -from qiskit.pulse import InstructionScheduleMap from qiskit.quantum_info import Operator, random_unitary from qiskit.utils import should_run_in_parallel from qiskit.transpiler import CouplingMap, Layout, PassManager @@ -1291,171 +1289,6 @@ def test_translation_method_synthesis(self, optimization_level, basis_gates): self.assertTrue(Operator(out).equiv(qc)) self.assertTrue(set(out.count_ops()).issubset(basis_gates)) - def test_transpiled_custom_gates_calibration(self): - """Test if transpiled calibrations is equal to custom gates circuit calibrations.""" - custom_180 = Gate("mycustom", 1, [3.14]) - custom_90 = Gate("mycustom", 1, [1.57]) - - circ = QuantumCircuit(2) - circ.append(custom_180, [0]) - circ.append(custom_90, [1]) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - with pulse.build() as q1_y90: - pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), pulse.DriveChannel(1)) - - # Add calibration - circ.add_calibration(custom_180, [0], q0_x180) - circ.add_calibration(custom_90, [1], q1_y90) - - transpiled_circuit = transpile( - circ, - backend=GenericBackendV2(num_qubits=4, seed=42), - layout_method="trivial", - seed_transpiler=42, - ) - with self.assertWarns(DeprecationWarning): - self.assertEqual(transpiled_circuit.calibrations, circ.calibrations) - self.assertEqual(list(transpiled_circuit.count_ops().keys()), ["mycustom"]) - self.assertEqual(list(transpiled_circuit.count_ops().values()), [2]) - - def test_transpiled_basis_gates_calibrations(self): - """Test if the transpiled calibrations is equal to basis gates circuit calibrations.""" - circ = QuantumCircuit(2) - circ.h(0) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - - # Add calibration - circ.add_calibration("h", [0], q0_x180) - - transpiled_circuit = transpile( - circ, backend=GenericBackendV2(num_qubits=4, seed=42), seed_transpiler=42 - ) - with self.assertWarns(DeprecationWarning): - self.assertEqual(transpiled_circuit.calibrations, circ.calibrations) - - def test_transpile_calibrated_custom_gate_on_diff_qubit(self): - """Test if the custom, non calibrated gate raises QiskitError.""" - custom_180 = Gate("mycustom", 1, [3.14]) - - circ = QuantumCircuit(2) - circ.append(custom_180, [0]) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - - # Add calibration - circ.add_calibration(custom_180, [1], q0_x180) - - with self.assertRaises(QiskitError): - transpile( - circ, - backend=GenericBackendV2(num_qubits=4, seed=42), - layout_method="trivial", - seed_transpiler=42, - optimization_level=1, - ) - - def test_transpile_calibrated_nonbasis_gate_on_diff_qubit(self): - """Test if the non-basis gates are transpiled if they are on different qubit that - is not calibrated.""" - circ = QuantumCircuit(2) - circ.h(0) - circ.h(1) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - - # Add calibration - circ.add_calibration("h", [1], q0_x180) - - transpiled_circuit = transpile( - circ, backend=GenericBackendV2(num_qubits=4), seed_transpiler=42, optimization_level=1 - ) - with self.assertWarns(DeprecationWarning): - self.assertEqual(transpiled_circuit.calibrations, circ.calibrations) - self.assertEqual(set(transpiled_circuit.count_ops().keys()), {"rz", "sx", "h"}) - - def test_transpile_subset_of_calibrated_gates(self): - """Test transpiling a circuit with both basis gate (not-calibrated) and - a calibrated gate on different qubits.""" - x_180 = Gate("mycustom", 1, [3.14]) - - circ = QuantumCircuit(2) - circ.h(0) - circ.append(x_180, [0]) - circ.h(1) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_x180: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - - circ.add_calibration(x_180, [0], q0_x180) - circ.add_calibration("h", [1], q0_x180) # 'h' is calibrated on qubit 1 - - transpiled_circ = transpile( - circ, - backend=GenericBackendV2(num_qubits=4, seed=42), - layout_method="trivial", - seed_transpiler=42, - ) - self.assertEqual(set(transpiled_circ.count_ops().keys()), {"rz", "sx", "mycustom", "h"}) - - def test_parameterized_calibrations_transpile(self): - """Check that gates can be matched to their calibrations before and after parameter - assignment.""" - tau = Parameter("tau") - circ = QuantumCircuit(3, 3) - circ.append(Gate("rxt", 1, [2 * 3.14 * tau]), [0]) - - def q0_rxt(tau): - with self.assertWarns(DeprecationWarning): - with pulse.build() as q0_rxt: - pulse.play(pulse.library.Gaussian(20, 0.4 * tau, 3.0), pulse.DriveChannel(0)) - return q0_rxt - - with self.assertWarns(DeprecationWarning): - circ.add_calibration("rxt", [0], q0_rxt(tau), [2 * 3.14 * tau]) - - transpiled_circ = transpile( - circ, - backend=GenericBackendV2(num_qubits=4, seed=42), - layout_method="trivial", - seed_transpiler=42, - ) - self.assertEqual(set(transpiled_circ.count_ops().keys()), {"rxt"}) - circ = circ.assign_parameters({tau: 1}) - transpiled_circ = transpile( - circ, - backend=GenericBackendV2(num_qubits=4), - layout_method="trivial", - seed_transpiler=42, - ) - self.assertEqual(set(transpiled_circ.count_ops().keys()), {"rxt"}) - - def test_inst_durations_from_calibrations(self): - """Test that circuit calibrations can be used instead of explicitly - supplying inst_durations. - """ - qc = QuantumCircuit(2) - qc.append(Gate("custom", 1, []), [0]) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as cal: - pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) - qc.add_calibration("custom", [0], cal) - - out = transpile(qc, scheduling_method="alap", seed_transpiler=42) - with self.assertWarns(DeprecationWarning): - self.assertEqual(out.duration, cal.duration) - @data(0, 1, 2, 3) def test_circuit_with_delay(self, optimization_level): """Verify a circuit with delay can transpile to a scheduled circuit.""" @@ -2729,35 +2562,6 @@ def test_transpile_with_multiple_coupling_maps(self): seed_transpiler=42, ) - @data(0, 1, 2, 3) - def test_backend_and_custom_gate(self, opt_level): - """Test transpile() with BackendV2, custom basis pulse gate.""" - backend = GenericBackendV2( - num_qubits=5, - coupling_map=[[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]], - seed=42, - ) - with self.assertWarns(DeprecationWarning): - inst_map = InstructionScheduleMap() - inst_map.add("newgate", [0, 1], pulse.ScheduleBlock()) - newgate = Gate("newgate", 2, []) - circ = QuantumCircuit(2) - circ.append(newgate, [0, 1]) - - with self.assertWarns(DeprecationWarning): - tqc = transpile( - circ, - backend, - inst_map=inst_map, - basis_gates=["newgate"], - optimization_level=opt_level, - seed_transpiler=42, - ) - self.assertEqual(len(tqc.data), 1) - self.assertEqual(tqc.data[0].operation, newgate) - for x in tqc.data[0].qubits: - self.assertIn((tqc.find_bit(x).index,), backend.target.qargs) - @ddt class TestTranspileMultiChipTarget(QiskitTestCase): diff --git a/test/python/converters/test_circuit_to_dag.py b/test/python/converters/test_circuit_to_dag.py index 4f0836a893d5..2c6cb5c9adae 100644 --- a/test/python/converters/test_circuit_to_dag.py +++ b/test/python/converters/test_circuit_to_dag.py @@ -41,21 +41,6 @@ def test_circuit_and_dag(self): circuit_out = dag_to_circuit(dag) self.assertEqual(circuit_out, circuit_in) - def test_calibrations(self): - """Test that calibrations are properly copied over.""" - circuit_in = QuantumCircuit(1) - with self.assertWarns(DeprecationWarning): - circuit_in.add_calibration("h", [0], None) - self.assertEqual(len(circuit_in.calibrations), 1) - - dag = circuit_to_dag(circuit_in) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(dag.calibrations), 1) - - circuit_out = dag_to_circuit(dag) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(circuit_out.calibrations), 1) - def test_wires_from_expr_nodes_condition(self): """Test that the classical wires implied by an `Expr` node in a control-flow op's `condition` are correctly transferred.""" diff --git a/test/python/converters/test_circuit_to_dagdependency.py b/test/python/converters/test_circuit_to_dagdependency.py index 9aafa0624511..f6a3b56a39f3 100644 --- a/test/python/converters/test_circuit_to_dagdependency.py +++ b/test/python/converters/test_circuit_to_dagdependency.py @@ -57,21 +57,6 @@ def test_circuit_and_dag_canonical2(self): circuit_out = dagdependency_to_circuit(dag_dependency) self.assertEqual(circuit_out, circuit_in) - def test_calibrations(self): - """Test that calibrations are properly copied over.""" - circuit_in = QuantumCircuit(1) - with self.assertWarns(DeprecationWarning): - circuit_in.add_calibration("h", [0], None) - self.assertEqual(len(circuit_in.calibrations), 1) - - dag_dependency = circuit_to_dagdependency(circuit_in) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(dag_dependency.calibrations), 1) - - circuit_out = dagdependency_to_circuit(dag_dependency) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(circuit_out.calibrations), 1) - def test_metadata(self): """Test circuit metadata is preservered through conversion.""" meta_dict = {"experiment_id": "1234", "execution_number": 4} diff --git a/test/python/converters/test_circuit_to_dagdependency_v2.py b/test/python/converters/test_circuit_to_dagdependency_v2.py index e0321c620c85..13f7e16002ef 100644 --- a/test/python/converters/test_circuit_to_dagdependency_v2.py +++ b/test/python/converters/test_circuit_to_dagdependency_v2.py @@ -40,20 +40,6 @@ def test_circuit_and_dag_canonical(self): circuit_out = dagdependency_to_circuit(dag_dependency) self.assertEqual(circuit_out, circuit_in) - def test_calibrations(self): - """Test that calibrations are properly copied over.""" - circuit_in = QuantumCircuit(1) - with self.assertWarns(DeprecationWarning): - circuit_in.add_calibration("h", [0], None) - self.assertEqual(len(circuit_in.calibrations), 1) - - dag_dependency = _circuit_to_dagdependency_v2(circuit_in) - self.assertEqual(len(dag_dependency.calibrations), 1) - - circuit_out = dagdependency_to_circuit(dag_dependency) - with self.assertWarns(DeprecationWarning): - self.assertEqual(len(circuit_out.calibrations), 1) - def test_metadata(self): """Test circuit metadata is preservered through conversion.""" meta_dict = {"experiment_id": "1234", "execution_number": 4} diff --git a/test/python/dagcircuit/test_compose.py b/test/python/dagcircuit/test_compose.py index beb7514646de..e0db69eb6831 100644 --- a/test/python/dagcircuit/test_compose.py +++ b/test/python/dagcircuit/test_compose.py @@ -27,8 +27,6 @@ from qiskit.circuit.classical import expr, types from qiskit.dagcircuit import DAGCircuit, DAGCircuitError from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.pulse import Schedule -from qiskit.circuit.gate import Gate from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -533,23 +531,6 @@ def test_reject_inline_to_nonexistent_var(self): ): dest.compose(source, inline_captures=True) - def test_compose_calibrations(self): - """Test that compose carries over the calibrations.""" - dag_cal = QuantumCircuit(1) - dag_cal.append(Gate("", 1, []), qargs=[0]) - with self.assertWarns(DeprecationWarning): - dag_cal.add_calibration(Gate("", 1, []), [0], Schedule()) - - empty_dag = circuit_to_dag(QuantumCircuit(1)) - calibrated_dag = circuit_to_dag(dag_cal) - composed_dag = empty_dag.compose(calibrated_dag, inplace=False) - - with self.assertWarns(DeprecationWarning): - cal = {"": {((0,), ()): Schedule(name="sched0")}} - with self.assertWarns(DeprecationWarning): - self.assertEqual(composed_dag.calibrations, cal) - self.assertEqual(calibrated_dag.calibrations, cal) - if __name__ == "__main__": unittest.main() diff --git a/test/python/primitives/test_primitive.py b/test/python/primitives/test_primitive.py index 14f0af578355..a418cdebda70 100644 --- a/test/python/primitives/test_primitive.py +++ b/test/python/primitives/test_primitive.py @@ -17,11 +17,10 @@ from ddt import data, ddt, unpack from numpy import array, float32, float64, int32, int64 -from qiskit import QuantumCircuit, pulse, transpile +from qiskit import QuantumCircuit from qiskit.circuit.random import random_circuit from qiskit.primitives.base import validation from qiskit.primitives.utils import _circuit_key -from qiskit.providers.fake_provider import GenericBackendV2 from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -122,38 +121,13 @@ class TestCircuitKey(QiskitTestCase): def test_different_circuits(self): """Test collision of quantum circuits.""" - with self.subTest("Ry circuit"): - - def test_func(n): - qc = QuantumCircuit(1, 1, name="foo") - qc.ry(n, 0) - return qc - - keys = [_circuit_key(test_func(i)) for i in range(5)] - self.assertEqual(len(keys), len(set(keys))) - - with self.subTest("pulse circuit"): - - def test_with_scheduling(n): - with self.assertWarns(DeprecationWarning): - custom_gate = pulse.Schedule(name="custom_x_gate") - custom_gate.insert( - 0, - pulse.Play(pulse.Constant(160 * n, 0.1), pulse.DriveChannel(0)), - inplace=True, - ) - qc = QuantumCircuit(1) - qc.x(0) - with self.assertWarns(DeprecationWarning): - qc.add_calibration("x", qubits=(0,), schedule=custom_gate) - - backend = GenericBackendV2( - num_qubits=2, basis_gates=["id", "u1", "u2", "u3", "cx"], seed=42 - ) - return transpile(qc, backend, scheduling_method="alap", optimization_level=1) - - keys = [_circuit_key(test_with_scheduling(i)) for i in range(1, 5)] - self.assertEqual(len(keys), len(set(keys))) + def test_func(n): + qc = QuantumCircuit(1, 1, name="foo") + qc.ry(n, 0) + return qc + + keys = [_circuit_key(test_func(i)) for i in range(5)] + self.assertEqual(len(keys), len(set(keys))) def test_circuit_key_controlflow(self): """Test for a circuit with control flow.""" diff --git a/test/python/transpiler/test_dynamical_decoupling.py b/test/python/transpiler/test_dynamical_decoupling.py index f28bca711c68..1068b39d5999 100644 --- a/test/python/transpiler/test_dynamical_decoupling.py +++ b/test/python/transpiler/test_dynamical_decoupling.py @@ -15,10 +15,9 @@ import unittest import numpy as np from numpy import pi -from ddt import ddt, data +from ddt import ddt -from qiskit import pulse -from qiskit.circuit import Gate, QuantumCircuit, Delay, Measure, Reset, Parameter +from qiskit.circuit import QuantumCircuit, Delay, Measure, Reset, Parameter from qiskit.circuit.library import XGate, YGate, RXGate, UGate, CXGate, HGate from qiskit.quantum_info import Operator from qiskit.transpiler.instruction_durations import InstructionDurations @@ -339,162 +338,6 @@ def test_insert_dd_ghz_everywhere(self): self.assertEqual(ghz4_dd, expected) - def test_insert_dd_with_pulse_gate_calibrations(self): - """Test DD gates are inserted without error when circuit calibrations are used - - ┌───┐ ┌───────────────┐ ┌───┐ » - q_0: ──────┤ H ├─────────■──┤ Delay(75[dt]) ├──────┤ X ├───────» - ┌─────┴───┴─────┐ ┌─┴─┐└───────────────┘┌─────┴───┴──────┐» - q_1: ┤ Delay(50[dt]) ├─┤ X ├────────■────────┤ Delay(300[dt]) ├» - ├───────────────┴┐└───┘ ┌─┴─┐ └────────────────┘» - q_2: ┤ Delay(750[dt]) ├───────────┤ X ├──────────────■─────────» - ├────────────────┤ └───┘ ┌─┴─┐ » - q_3: ┤ Delay(950[dt]) ├────────────────────────────┤ X ├───────» - └────────────────┘ └───┘ » - meas: 4/══════════════════════════════════════════════════════════» - » - « ┌────────────────┐┌───┐┌───────────────┐ ░ ┌─┐ - « q_0: ┤ Delay(150[dt]) ├┤ X ├┤ Delay(75[dt]) ├─░─┤M├───────── - « └────────────────┘└───┘└───────────────┘ ░ └╥┘┌─┐ - « q_1: ─────────────────────────────────────────░──╫─┤M├────── - « ░ ║ └╥┘┌─┐ - « q_2: ─────────────────────────────────────────░──╫──╫─┤M├─── - « ░ ║ ║ └╥┘┌─┐ - « q_3: ─────────────────────────────────────────░──╫──╫──╫─┤M├ - « ░ ║ ║ ║ └╥┘ - «meas: 4/════════════════════════════════════════════╩══╩══╩══╩═ - « 0 1 2 3 - """ - dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ALAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0]), - ] - ) - - # Change duration to 100 from the 50 in self.durations to make sure - # gate duration is used correctly. - with self.assertWarns(DeprecationWarning): - with pulse.builder.build() as x_sched: - pulse.builder.delay(100, pulse.DriveChannel(0)) - - circ_in = self.ghz4.measure_all(inplace=False) - with self.assertWarns(DeprecationWarning): - circ_in.add_calibration(XGate(), (0,), x_sched) - - ghz4_dd = pm.run(circ_in) - - expected = self.ghz4.copy() - expected = expected.compose(Delay(50), [1], front=True) - expected = expected.compose(Delay(750), [2], front=True) - expected = expected.compose(Delay(950), [3], front=True) - - # Delays different from those of the default case using self.durations - expected = expected.compose(Delay(75), [0]) - expected = expected.compose(XGate(), [0]) - expected = expected.compose(Delay(150), [0]) - expected = expected.compose(XGate(), [0]) - expected = expected.compose(Delay(75), [0]) - - expected = expected.compose(Delay(300), [1]) - - expected.measure_all() - with self.assertWarns(DeprecationWarning): - expected.add_calibration(XGate(), (0,), x_sched) - - self.assertEqual(ghz4_dd, expected) - - def test_insert_dd_with_pulse_gate_calibrations_with_parmas(self): - """Test DD gates are inserted without error when parameterized circuit calibrations are used - - ┌───┐ ┌───────────────┐ ┌───┐ » - q_0: ──────┤ H ├─────────■──┤ Delay(75[dt]) ├──────┤ X ├───────» - ┌─────┴───┴─────┐ ┌─┴─┐└───────────────┘┌─────┴───┴──────┐» - q_1: ┤ Delay(50[dt]) ├─┤ X ├────────■────────┤ Delay(300[dt]) ├» - ├───────────────┴┐└───┘ ┌─┴─┐ └────────────────┘» - q_2: ┤ Delay(750[dt]) ├───────────┤ X ├──────────────■─────────» - ├────────────────┤ └───┘ ┌─┴─┐ » - q_3: ┤ Delay(950[dt]) ├────────────────────────────┤ X ├───────» - └────────────────┘ └───┘ » - meas: 4/══════════════════════════════════════════════════════════» - » - « ┌────────────────┐┌───┐┌───────────────┐ ░ ┌─┐ - « q_0: ┤ Delay(150[dt]) ├┤ X ├┤ Delay(75[dt]) ├─░─┤M├───────── - « └────────────────┘└───┘└───────────────┘ ░ └╥┘┌─┐ - « q_1: ─────────────────────────────────────────░──╫─┤M├────── - « ░ ║ └╥┘┌─┐ - « q_2: ─────────────────────────────────────────░──╫──╫─┤M├─── - « ░ ║ ║ └╥┘┌─┐ - « q_3: ─────────────────────────────────────────░──╫──╫──╫─┤M├ - « ░ ║ ║ ║ └╥┘ - «meas: 4/════════════════════════════════════════════╩══╩══╩══╩═ - « 0 1 2 3 - """ - # Change duration to 100 from the 50 in self.durations to make sure - # gate duration is used correctly. - amp = Parameter("amp") - with self.assertWarns(DeprecationWarning): - with pulse.builder.build() as sched: - pulse.builder.play( - pulse.Gaussian(100, amp=amp, sigma=10.0), - pulse.DriveChannel(0), - ) - - class Echo(Gate): - """Dummy Gate subclass for testing - - In this test, we use a non-standard gate so we can add parameters - to it, in order to test the handling of parameters by - PadDynamicalDecoupling. PadDynamicalDecoupling checks that the DD - sequence is equivalent to the identity, so we can not use Gate - directly. Here we subclass Gate and add the identity as its matrix - representation to satisfy PadDynamicalDecoupling's check. - """ - - def __array__(self, dtype=None, copy=None): - if copy is False: - raise ValueError("cannot produce matrix without calculation") - return np.eye(2, dtype=dtype) - - # A gate with one unbound and one bound parameter to leave in the final - # circuit. - echo = Echo("echo", 1, [amp, 10.0]) - - circ_in = self.ghz4.measure_all(inplace=False) - with self.assertWarns(DeprecationWarning): - circ_in.add_calibration(echo, (0,), sched) - - dd_sequence = [echo, echo] - pm = PassManager( - [ - ALAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0]), - ] - ) - - ghz4_dd = pm.run(circ_in) - - expected = self.ghz4.copy() - expected = expected.compose(Delay(50), [1], front=True) - expected = expected.compose(Delay(750), [2], front=True) - expected = expected.compose(Delay(950), [3], front=True) - - # Delays different from those of the default case using self.durations - expected = expected.compose(Delay(75), [0]) - expected = expected.compose(echo, [0]) - expected = expected.compose(Delay(150), [0]) - expected = expected.compose(echo, [0]) - expected = expected.compose(Delay(75), [0]) - - expected = expected.compose(Delay(300), [1]) - - expected.measure_all() - with self.assertWarns(DeprecationWarning): - expected.add_calibration(echo, (0,), sched) - - self.assertEqual(ghz4_dd, expected) - def test_insert_dd_ghz_xy4(self): """Test XY4 sequence of DD gates. @@ -853,35 +696,6 @@ def test_insert_dd_bad_sequence(self): with self.assertRaises(TranspilerError): pm.run(self.ghz4) - @data(0.5, 1.5) - def test_dd_with_calibrations_with_parameters(self, param_value): - """Check that calibrations in a circuit with parameters work fine.""" - - circ = QuantumCircuit(2) - circ.x(0) - circ.cx(0, 1) - circ.rx(param_value, 1) - - rx_duration = int(param_value * 1000) - - with self.assertWarns(DeprecationWarning): - with pulse.build() as rx: - pulse.play( - pulse.Gaussian(rx_duration, 0.1, rx_duration // 4), pulse.DriveChannel(1) - ) - - with self.assertWarns(DeprecationWarning): - circ.add_calibration("rx", (1,), rx, params=[param_value]) - - durations = InstructionDurations([("x", None, 100), ("cx", None, 300)], dt=1e-8) - - dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ALAPScheduleAnalysis(durations), PadDynamicalDecoupling(durations, dd_sequence)] - ) - - self.assertEqual(pm.run(circ).duration, rx_duration + 100 + 300) - def test_insert_dd_ghz_xy4_with_alignment(self): """Test DD with pulse alignment constraints. diff --git a/test/python/transpiler/test_gate_direction.py b/test/python/transpiler/test_gate_direction.py index 31f197814d34..c10a33707b28 100644 --- a/test/python/transpiler/test_gate_direction.py +++ b/test/python/transpiler/test_gate_direction.py @@ -17,7 +17,7 @@ import ddt -from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit, pulse +from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit from qiskit.circuit import Parameter, Gate from qiskit.circuit.library import ( CXGate, @@ -429,22 +429,6 @@ def test_target_cannot_flip_message(self): with self.assertRaisesRegex(TranspilerError, "my_2q_gate would be supported.*"): pass_(circuit) - def test_target_cannot_flip_message_calibrated(self): - """A suitable error message should be emitted if the gate would be supported if it were - flipped.""" - target = Target(num_qubits=2) - target.add_instruction(CXGate(), properties={(0, 1): None}) - - gate = Gate("my_2q_gate", 2, []) - circuit = QuantumCircuit(2) - circuit.append(gate, (1, 0)) - with self.assertWarns(DeprecationWarning): - circuit.add_calibration(gate, (0, 1), pulse.ScheduleBlock()) - - pass_ = GateDirection(None, target) - with self.assertRaisesRegex(TranspilerError, "my_2q_gate would be supported.*"): - pass_(circuit) - def test_target_unknown_gate_message(self): """A suitable error message should be emitted if the gate isn't valid in either direction on the target.""" @@ -459,35 +443,6 @@ def test_target_unknown_gate_message(self): with self.assertRaisesRegex(TranspilerError, "my_2q_gate.*not supported on qubits .*"): pass_(circuit) - def test_allows_calibrated_gates_coupling_map(self): - """Test that the gate direction pass allows a gate that's got a calibration to pass through - without error.""" - cm = CouplingMap([(1, 0)]) - - gate = Gate("my_2q_gate", 2, []) - circuit = QuantumCircuit(2) - circuit.append(gate, (0, 1)) - with self.assertWarns(DeprecationWarning): - circuit.add_calibration(gate, (0, 1), pulse.ScheduleBlock()) - - pass_ = GateDirection(cm) - self.assertEqual(pass_(circuit), circuit) - - def test_allows_calibrated_gates_target(self): - """Test that the gate direction pass allows a gate that's got a calibration to pass through - without error.""" - target = Target(num_qubits=2) - target.add_instruction(CXGate(), properties={(0, 1): None}) - - gate = Gate("my_2q_gate", 2, []) - circuit = QuantumCircuit(2) - circuit.append(gate, (0, 1)) - with self.assertWarns(DeprecationWarning): - circuit.add_calibration(gate, (0, 1), pulse.ScheduleBlock()) - - pass_ = GateDirection(None, target) - self.assertEqual(pass_(circuit), circuit) - if __name__ == "__main__": unittest.main() diff --git a/test/python/transpiler/test_passmanager_config.py b/test/python/transpiler/test_passmanager_config.py index 7360935a5fa7..509bc6a4dc10 100644 --- a/test/python/transpiler/test_passmanager_config.py +++ b/test/python/transpiler/test_passmanager_config.py @@ -30,8 +30,6 @@ def test_config_from_backend_v2(self): backend = GenericBackendV2(num_qubits=27, seed=42) config = PassManagerConfig.from_backend(backend) self.assertEqual(config.basis_gates, backend.operation_names) - with self.assertWarns(DeprecationWarning): - self.assertEqual(config.inst_map, backend.instruction_schedule_map) self.assertEqual(config.coupling_map.get_edges(), backend.coupling_map.get_edges()) def test_invalid_backend(self): @@ -59,7 +57,6 @@ def test_from_backend_and_user(self): ) self.assertEqual(config.basis_gates, ["user_gate"]) self.assertNotEqual(config.basis_gates, backend.operation_names) - self.assertEqual(config.inst_map.instructions, []) self.assertEqual(str(config.coupling_map), str(CouplingMap(backend.coupling_map))) self.assertEqual(config.initial_layout, initial_layout) @@ -74,12 +71,10 @@ def test_str(self): pm_config = PassManagerConfig.from_backend(BasicSimulator()) # For testing remove instruction schedule map, its str output is non-deterministic # based on hash seed - pm_config.inst_map = None str_out = str(pm_config) expected = """Pass Manager Config: \tinitial_layout: None \tbasis_gates: ['ccx', 'ccz', 'ch', 'cp', 'crx', 'cry', 'crz', 'cs', 'csdg', 'cswap', 'csx', 'cu', 'cu1', 'cu3', 'cx', 'cy', 'cz', 'dcx', 'delay', 'ecr', 'global_phase', 'h', 'id', 'iswap', 'measure', 'p', 'r', 'rccx', 'reset', 'rx', 'rxx', 'ry', 'ryy', 'rz', 'rzx', 'rzz', 's', 'sdg', 'swap', 'sx', 'sxdg', 't', 'tdg', 'u', 'u1', 'u2', 'u3', 'unitary', 'x', 'xx_minus_yy', 'xx_plus_yy', 'y', 'z'] -\tinst_map: None \tcoupling_map: None \tlayout_method: None \trouting_method: None diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 87f21abfd9e6..18e10c2ba3a2 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -1248,7 +1248,6 @@ def test_with_no_backend(self, optimization_level): optimization_level, coupling_map=target.coupling_map, basis_gates=target.operation_names, - inst_map=target.instruction_schedule_map, instruction_durations=target.instruction_durations, timing_constraints=target.target.timing_constraints(), target=target.target, diff --git a/test/python/transpiler/test_scheduling_padding_pass.py b/test/python/transpiler/test_scheduling_padding_pass.py index 9f02d765f8a2..b5c248bc02e9 100644 --- a/test/python/transpiler/test_scheduling_padding_pass.py +++ b/test/python/transpiler/test_scheduling_padding_pass.py @@ -18,7 +18,6 @@ from qiskit import QuantumCircuit from qiskit.circuit import Measure from qiskit.circuit.library import CXGate, HGate -from qiskit.pulse import Schedule, Play, Constant, DriveChannel from qiskit.transpiler.instruction_durations import InstructionDurations from qiskit.transpiler.passes import ( ASAPScheduleAnalysis, @@ -295,34 +294,6 @@ def test_parallel_gate_different_length_with_barrier(self): self.assertEqual(qc_asap, asap_expected) - def test_scheduling_with_calibration(self): - """Test if calibrated instruction can update node duration.""" - qc = QuantumCircuit(2) - qc.x(0) - qc.cx(0, 1) - qc.x(1) - qc.cx(0, 1) - - with self.assertWarns(DeprecationWarning): - xsched = Schedule(Play(Constant(300, 0.1), DriveChannel(0))) - qc.add_calibration("x", (0,), xsched) - - durations = InstructionDurations([("x", None, 160), ("cx", None, 600)], dt=1e-7) - pm = PassManager([ASAPScheduleAnalysis(durations), PadDelay(durations=durations)]) - scheduled = pm.run(qc) - - expected = QuantumCircuit(2) - expected.x(0) - expected.delay(300, 1) - expected.cx(0, 1) - expected.x(1) - expected.delay(160, 0) - expected.cx(0, 1) - with self.assertWarns(DeprecationWarning): - expected.add_calibration("x", (0,), xsched) - - self.assertEqual(expected, scheduled) - def test_padding_not_working_without_scheduling(self): """Test padding fails when un-scheduled DAG is input.""" qc = QuantumCircuit(1, 1) diff --git a/test/python/transpiler/test_target.py b/test/python/transpiler/test_target.py index b68203a6c75c..4f1edc5fe24f 100644 --- a/test/python/transpiler/test_target.py +++ b/test/python/transpiler/test_target.py @@ -1015,11 +1015,10 @@ def __init__( self, duration=None, error=None, - calibration=None, tuned=None, diamond_norm_error=None, ): - super().__init__(duration=duration, error=error, calibration=calibration) + super().__init__(duration=duration, error=error) self.tuned = tuned self.diamond_norm_error = diamond_norm_error @@ -1694,7 +1693,7 @@ def test_empty_repr(self): properties = InstructionProperties() self.assertEqual( repr(properties), - "InstructionProperties(duration=None, error=None, calibration=None)", + "InstructionProperties(duration=None, error=None)", ) diff --git a/test/python/transpiler/test_vf2_post_layout.py b/test/python/transpiler/test_vf2_post_layout.py index 8b2548e38b6f..66b138b69a45 100644 --- a/test/python/transpiler/test_vf2_post_layout.py +++ b/test/python/transpiler/test_vf2_post_layout.py @@ -45,9 +45,8 @@ def assertLayoutV2(self, dag, target, property_set): def run(dag, wire_map): for gate in dag.two_qubit_ops(): - with self.assertWarns(DeprecationWarning): - if dag.has_calibration_for(gate) or isinstance(gate.op, ControlFlowOp): - continue + if isinstance(gate.op, ControlFlowOp): + continue physical_q0 = wire_map[gate.qargs[0]] physical_q1 = wire_map[gate.qargs[1]] qargs = (physical_q0, physical_q1) @@ -387,9 +386,6 @@ def assertLayout(self, dag, coupling_map, property_set): layout = property_set["post_layout"] for gate in dag.two_qubit_ops(): - with self.assertWarns(DeprecationWarning): - if dag.has_calibration_for(gate): - continue physical_q0 = layout[gate.qargs[0]] physical_q1 = layout[gate.qargs[1]] self.assertTrue(coupling_map.graph.has_edge(physical_q0, physical_q1)) @@ -403,9 +399,6 @@ def assertLayoutV2(self, dag, target, property_set): layout = property_set["post_layout"] for gate in dag.two_qubit_ops(): - with self.assertWarns(DeprecationWarning): - if dag.has_calibration_for(gate): - continue physical_q0 = layout[gate.qargs[0]] physical_q1 = layout[gate.qargs[1]] qargs = (physical_q0, physical_q1) diff --git a/test/utils/providers/__init__.py b/test/utils/providers/__init__.py deleted file mode 100644 index 46829845c9db..000000000000 --- a/test/utils/providers/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2023. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Module containing one qubit unitary synthesis methods.""" - -from .one_qubit_decompose import OneQubitEulerDecomposer diff --git a/test/visual/mpl/circuit/references/calibrations.png b/test/visual/mpl/circuit/references/calibrations.png deleted file mode 100644 index c8f4d8fb0838..000000000000 Binary files a/test/visual/mpl/circuit/references/calibrations.png and /dev/null differ diff --git a/test/visual/mpl/circuit/references/calibrations_with_control_gates.png b/test/visual/mpl/circuit/references/calibrations_with_control_gates.png deleted file mode 100644 index 49db6bbbdf25..000000000000 Binary files a/test/visual/mpl/circuit/references/calibrations_with_control_gates.png and /dev/null differ diff --git a/test/visual/mpl/circuit/references/calibrations_with_rzz_and_rxx.png b/test/visual/mpl/circuit/references/calibrations_with_rzz_and_rxx.png deleted file mode 100644 index 8c57d9d50352..000000000000 Binary files a/test/visual/mpl/circuit/references/calibrations_with_rzz_and_rxx.png and /dev/null differ diff --git a/test/visual/mpl/circuit/references/calibrations_with_swap_and_reset.png b/test/visual/mpl/circuit/references/calibrations_with_swap_and_reset.png deleted file mode 100644 index 2aa31394d728..000000000000 Binary files a/test/visual/mpl/circuit/references/calibrations_with_swap_and_reset.png and /dev/null differ diff --git a/test/visual/mpl/circuit/test_circuit_matplotlib_drawer.py b/test/visual/mpl/circuit/test_circuit_matplotlib_drawer.py index b7e3827f0d3d..77b2c5408ba0 100644 --- a/test/visual/mpl/circuit/test_circuit_matplotlib_drawer.py +++ b/test/visual/mpl/circuit/test_circuit_matplotlib_drawer.py @@ -112,149 +112,6 @@ def test_empty_circuit(self): ) self.assertGreaterEqual(ratio, self.threshold) - def test_calibrations(self): - """Test calibrations annotations - See https://github.com/Qiskit/qiskit-terra/issues/5920 - """ - - circuit = QuantumCircuit(2, 2) - circuit.h(0) - - from qiskit import pulse - - with self.assertWarns(DeprecationWarning): - with pulse.build(name="hadamard") as h_q0: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(0) - ) - - circuit.add_calibration("h", [0], h_q0) - - fname = "calibrations.png" - self.circuit_drawer(circuit, output="mpl", filename=fname) - - ratio = VisualTestUtilities._save_diff( - self._image_path(fname), - self._reference_path(fname), - fname, - FAILURE_DIFF_DIR, - FAILURE_PREFIX, - ) - self.assertGreaterEqual(ratio, self.threshold) - - def test_calibrations_with_control_gates(self): - """Test calibrations annotations - See https://github.com/Qiskit/qiskit-terra/issues/5920 - """ - - circuit = QuantumCircuit(2, 2) - circuit.cx(0, 1) - circuit.ch(0, 1) - - from qiskit import pulse - - with self.assertWarns(DeprecationWarning): - with pulse.build(name="cnot") as cx_q01: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) - ) - - circuit.add_calibration("cx", [0, 1], cx_q01) - - with pulse.build(name="ch") as ch_q01: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) - ) - - circuit.add_calibration("ch", [0, 1], ch_q01) - - fname = "calibrations_with_control_gates.png" - self.circuit_drawer(circuit, output="mpl", filename=fname) - - ratio = VisualTestUtilities._save_diff( - self._image_path(fname), - self._reference_path(fname), - fname, - FAILURE_DIFF_DIR, - FAILURE_PREFIX, - ) - self.assertGreaterEqual(ratio, self.threshold) - - def test_calibrations_with_swap_and_reset(self): - """Test calibrations annotations - See https://github.com/Qiskit/qiskit-terra/issues/5920 - """ - - circuit = QuantumCircuit(2, 2) - circuit.swap(0, 1) - circuit.reset(0) - - from qiskit import pulse - - with self.assertWarns(DeprecationWarning): - with pulse.build(name="swap") as swap_q01: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) - ) - - circuit.add_calibration("swap", [0, 1], swap_q01) - - with pulse.build(name="reset") as reset_q0: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) - ) - - circuit.add_calibration("reset", [0], reset_q0) - - fname = "calibrations_with_swap_and_reset.png" - self.circuit_drawer(circuit, output="mpl", filename=fname) - - ratio = VisualTestUtilities._save_diff( - self._image_path(fname), - self._reference_path(fname), - fname, - FAILURE_DIFF_DIR, - FAILURE_PREFIX, - ) - self.assertGreaterEqual(ratio, self.threshold) - - def test_calibrations_with_rzz_and_rxx(self): - """Test calibrations annotations - See https://github.com/Qiskit/qiskit-terra/issues/5920 - """ - circuit = QuantumCircuit(2, 2) - circuit.rzz(pi, 0, 1) - circuit.rxx(pi, 0, 1) - - from qiskit import pulse - - with self.assertWarns(DeprecationWarning): - with pulse.build(name="rzz") as rzz_q01: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) - ) - - circuit.add_calibration("rzz", [0, 1], rzz_q01) - - with pulse.build(name="rxx") as rxx_q01: - pulse.play( - pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) - ) - - circuit.add_calibration("rxx", [0, 1], rxx_q01) - - fname = "calibrations_with_rzz_and_rxx.png" - self.circuit_drawer(circuit, output="mpl", filename=fname) - - ratio = VisualTestUtilities._save_diff( - self._image_path(fname), - self._reference_path(fname), - fname, - FAILURE_DIFF_DIR, - FAILURE_PREFIX, - ) - self.assertGreaterEqual(ratio, self.threshold) - def test_no_ops(self): """Test circuit with no ops. See https://github.com/Qiskit/qiskit-terra/issues/5393"""