diff --git a/crates/accelerate/src/commutation_analysis.rs b/crates/accelerate/src/commutation_analysis.rs index 08fa1dda5ec9..2da8cfce931e 100644 --- a/crates/accelerate/src/commutation_analysis.rs +++ b/crates/accelerate/src/commutation_analysis.rs @@ -50,7 +50,7 @@ const MAX_NUM_QUBITS: u32 = 3; /// commutation_set = {0: [[0], [2, 3], [4], [1]]} /// node_indices = {(0, 0): 0, (1, 0): 3, (2, 0): 1, (3, 0): 1, (4, 0): 2} /// -fn analyze_commutations_inner( +pub(crate) fn analyze_commutations_inner( py: Python, dag: &mut DAGCircuit, commutation_checker: &mut CommutationChecker, diff --git a/crates/accelerate/src/commutation_cancellation.rs b/crates/accelerate/src/commutation_cancellation.rs new file mode 100644 index 000000000000..dc2d4436d83a --- /dev/null +++ b/crates/accelerate/src/commutation_cancellation.rs @@ -0,0 +1,280 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// 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. + +use std::f64::consts::PI; + +use hashbrown::{HashMap, HashSet}; +use pyo3::exceptions::PyRuntimeError; +use pyo3::prelude::*; +use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyResult, Python}; +use rustworkx_core::petgraph::stable_graph::NodeIndex; +use smallvec::{smallvec, SmallVec}; + +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType, Wire}; +use qiskit_circuit::operations::StandardGate::{ + CXGate, CYGate, CZGate, HGate, PhaseGate, RXGate, RZGate, SGate, TGate, U1Gate, XGate, YGate, + ZGate, +}; +use qiskit_circuit::operations::{Operation, Param, StandardGate}; +use qiskit_circuit::Qubit; + +use crate::commutation_analysis::analyze_commutations_inner; +use crate::commutation_checker::CommutationChecker; +use crate::{euler_one_qubit_decomposer, QiskitError}; + +const _CUTOFF_PRECISION: f64 = 1e-5; +static ROTATION_GATES: [&str; 4] = ["p", "u1", "rz", "rx"]; +static HALF_TURNS: [&str; 2] = ["z", "x"]; +static QUARTER_TURNS: [&str; 1] = ["s"]; +static EIGHTH_TURNS: [&str; 1] = ["t"]; + +static VAR_Z_MAP: [(&str, StandardGate); 3] = [("rz", RZGate), ("p", PhaseGate), ("u1", U1Gate)]; +static Z_ROTATIONS: [StandardGate; 6] = [PhaseGate, ZGate, U1Gate, RZGate, TGate, SGate]; +static X_ROTATIONS: [StandardGate; 2] = [XGate, RXGate]; +static SUPPORTED_GATES: [StandardGate; 5] = [CXGate, CYGate, CZGate, HGate, YGate]; + +#[derive(Hash, Eq, PartialEq, Debug)] +enum GateOrRotation { + Gate(StandardGate), + ZRotation, + XRotation, +} +#[derive(Hash, Eq, PartialEq, Debug)] +struct CancellationSetKey { + gate: GateOrRotation, + qubits: SmallVec<[Qubit; 2]>, + com_set_index: usize, + second_index: Option, +} + +#[pyfunction] +#[pyo3(signature = (dag, commutation_checker, basis_gates=None))] +pub(crate) fn cancel_commutations( + py: Python, + dag: &mut DAGCircuit, + commutation_checker: &mut CommutationChecker, + basis_gates: Option>, +) -> PyResult<()> { + let basis: HashSet = if let Some(basis) = basis_gates { + basis + } else { + HashSet::new() + }; + let z_var_gate = dag + .get_op_counts() + .keys() + .find_map(|g| { + VAR_Z_MAP + .iter() + .find(|(key, _)| *key == g.as_str()) + .map(|(_, gate)| gate) + }) + .or_else(|| { + basis.iter().find_map(|g| { + VAR_Z_MAP + .iter() + .find(|(key, _)| *key == g.as_str()) + .map(|(_, gate)| gate) + }) + }); + // Fallback to the first matching key from basis if there is no match in dag.op_names + + // Gate sets to be cancelled + /* Traverse each qubit to generate the cancel dictionaries + Cancel dictionaries: + - For 1-qubit gates the key is (gate_type, qubit_id, commutation_set_id), + the value is the list of gates that share the same gate type, qubit, commutation set. + - For 2qbit gates the key: (gate_type, first_qbit, sec_qbit, first commutation_set_id, + sec_commutation_set_id), the value is the list gates that share the same gate type, + qubits and commutation sets. + */ + let (commutation_set, node_indices) = analyze_commutations_inner(py, dag, commutation_checker)?; + let mut cancellation_sets: HashMap> = HashMap::new(); + + (0..dag.num_qubits() as u32).for_each(|qubit| { + let wire = Qubit(qubit); + if let Some(wire_commutation_set) = commutation_set.get(&Wire::Qubit(wire)) { + for (com_set_idx, com_set) in wire_commutation_set.iter().enumerate() { + if let Some(&nd) = com_set.first() { + if !matches!(dag.dag[nd], NodeType::Operation(_)) { + continue; + } + } else { + continue; + } + for node in com_set.iter() { + let instr = match &dag.dag[*node] { + NodeType::Operation(instr) => instr, + _ => panic!("Unexpected type in commutation set."), + }; + let num_qargs = dag.get_qargs(instr.qubits).len(); + // no support for cancellation of parameterized gates + if instr.is_parameterized() { + continue; + } + if let Some(op_gate) = instr.op.try_standard_gate() { + if num_qargs == 1 && SUPPORTED_GATES.contains(&op_gate) { + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::Gate(op_gate), + qubits: smallvec![wire], + com_set_index: com_set_idx, + second_index: None, + }) + .or_insert_with(Vec::new) + .push(*node); + } + + if num_qargs == 1 && Z_ROTATIONS.contains(&op_gate) { + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::ZRotation, + qubits: smallvec![wire], + com_set_index: com_set_idx, + second_index: None, + }) + .or_insert_with(Vec::new) + .push(*node); + } + if num_qargs == 1 && X_ROTATIONS.contains(&op_gate) { + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::XRotation, + qubits: smallvec![wire], + com_set_index: com_set_idx, + second_index: None, + }) + .or_insert_with(Vec::new) + .push(*node); + } + // Don't deal with Y rotation, because Y rotation doesn't commute with + // CNOT, so it should be dealt with by optimized1qgate pass + if num_qargs == 2 && dag.get_qargs(instr.qubits)[0] == wire { + let second_qarg = dag.get_qargs(instr.qubits)[1]; + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::Gate(op_gate), + qubits: smallvec![wire, second_qarg], + com_set_index: com_set_idx, + second_index: node_indices + .get(&(*node, Wire::Qubit(second_qarg))) + .copied(), + }) + .or_insert_with(Vec::new) + .push(*node); + } + } + } + } + } + }); + + for (cancel_key, cancel_set) in &cancellation_sets { + if cancel_set.len() > 1 { + if let GateOrRotation::Gate(g) = cancel_key.gate { + if SUPPORTED_GATES.contains(&g) { + for &c_node in &cancel_set[0..(cancel_set.len() / 2) * 2] { + dag.remove_op_node(c_node); + } + } + continue; + } + if matches!(cancel_key.gate, GateOrRotation::ZRotation) && z_var_gate.is_none() { + continue; + } + if matches!( + cancel_key.gate, + GateOrRotation::ZRotation | GateOrRotation::XRotation + ) { + let mut total_angle: f64 = 0.0; + let mut total_phase: f64 = 0.0; + for current_node in cancel_set { + let node_op = match &dag.dag[*current_node] { + NodeType::Operation(instr) => instr, + _ => panic!("Unexpected type in commutation set run."), + }; + let node_op_name = node_op.op.name(); + + let node_angle = if ROTATION_GATES.contains(&node_op_name) { + match node_op.params_view().first() { + Some(Param::Float(f)) => Ok(*f), + _ => return Err(QiskitError::new_err(format!( + "Rotational gate with parameter expression encountered in cancellation {:?}", + node_op.op + ))) + } + } else if HALF_TURNS.contains(&node_op_name) { + Ok(PI) + } else if QUARTER_TURNS.contains(&node_op_name) { + Ok(PI / 2.0) + } else if EIGHTH_TURNS.contains(&node_op_name) { + Ok(PI / 4.0) + } else { + Err(PyRuntimeError::new_err(format!( + "Angle for operation {} is not defined", + node_op_name + ))) + }; + total_angle += node_angle?; + + let Param::Float(new_phase) = node_op + .op + .definition(node_op.params_view()) + .unwrap() + .global_phase() + .clone() + else { + unreachable!() + }; + total_phase += new_phase + } + + let new_op = match cancel_key.gate { + GateOrRotation::ZRotation => z_var_gate.unwrap(), + GateOrRotation::XRotation => &RXGate, + _ => unreachable!(), + }; + + let gate_angle = euler_one_qubit_decomposer::mod_2pi(total_angle, 0.); + + let new_op_phase: f64 = if gate_angle.abs() > _CUTOFF_PRECISION { + dag.insert_1q_on_incoming_qubit((*new_op, &[total_angle]), cancel_set[0]); + let Param::Float(new_phase) = new_op + .definition(&[Param::Float(total_angle)]) + .unwrap() + .global_phase() + .clone() + else { + unreachable!(); + }; + new_phase + } else { + 0.0 + }; + + dag.add_global_phase(py, &Param::Float(total_phase - new_op_phase))?; + + for node in cancel_set { + dag.remove_op_node(*node); + } + } + } + } + + Ok(()) +} + +#[pymodule] +pub fn commutation_cancellation(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(cancel_commutations))?; + Ok(()) +} diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index a3cb11ea45a2..4c0a8539cf34 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -924,7 +924,7 @@ pub fn det_one_qubit(mat: ArrayView2) -> Complex64 { /// Wrap angle into interval [-π,π). If within atol of the endpoint, clamp to -π #[inline] -fn mod_2pi(angle: f64, atol: f64) -> f64 { +pub(crate) fn mod_2pi(angle: f64, atol: f64) -> f64 { // f64::rem_euclid() isn't exactly the same as Python's % operator, but because // the RHS here is a constant and positive it is effectively equivalent for // this case diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 9e391e0a9030..9111f932e270 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -17,6 +17,7 @@ use pyo3::import_exception; pub mod check_map; pub mod circuit_library; pub mod commutation_analysis; +pub mod commutation_cancellation; pub mod commutation_checker; pub mod convert_2q_block_matrix; pub mod dense_layout; diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 0b5a43c1eb4b..81dd8ffd3322 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -6454,6 +6454,16 @@ impl DAGCircuit { } } + /// Get an immutable reference to the op counts for this DAGCircuit + /// + /// This differs from count_ops() in that it doesn't handle control flow recursion at all + /// and it returns a reference instead of an owned copy. If you don't need to work with + /// control flow or ownership of the counts this is a more efficient alternative to + /// `DAGCircuit::count_ops(py, false)` + pub fn get_op_counts(&self) -> &IndexMap { + &self.op_names + } + /// Extends the DAG with valid instances of [PackedInstruction] pub fn extend(&mut self, py: Python, iter: I) -> PyResult> where diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 03bd0202dae4..43b693a4d6c1 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -14,12 +14,13 @@ use pyo3::prelude::*; use qiskit_accelerate::{ check_map::check_map_mod, circuit_library::circuit_library, - commutation_analysis::commutation_analysis, commutation_checker::commutation_checker, - convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, - error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, - filter_op_nodes::filter_op_nodes_mod, gate_direction::gate_direction, - inverse_cancellation::inverse_cancellation_mod, isometry::isometry, nlayout::nlayout, - optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, + commutation_analysis::commutation_analysis, commutation_cancellation::commutation_cancellation, + commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, + dense_layout::dense_layout, error_map::error_map, + euler_one_qubit_decomposer::euler_one_qubit_decomposer, filter_op_nodes::filter_op_nodes_mod, + gate_direction::gate_direction, inverse_cancellation::inverse_cancellation_mod, + isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, + pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, split_2q_unitaries::split_2q_unitaries_mod, star_prerouting::star_prerouting, @@ -77,5 +78,6 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, gate_direction, "gate_direction")?; add_submodule(m, commutation_checker, "commutation_checker")?; add_submodule(m, commutation_analysis, "commutation_analysis")?; + add_submodule(m, commutation_cancellation, "commutation_cancellation")?; Ok(()) } diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 29e2b8ba5c11..d0811c172d69 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -91,6 +91,7 @@ sys.modules["qiskit._accelerate.synthesis.clifford"] = _accelerate.synthesis.clifford sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis +sys.modules["qiskit._accelerate.commutation_cancellation"] = _accelerate.commutation_cancellation sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase sys.modules["qiskit._accelerate.split_2q_unitaries"] = _accelerate.split_2q_unitaries sys.modules["qiskit._accelerate.gate_direction"] = _accelerate.gate_direction diff --git a/qiskit/transpiler/passes/optimization/commutative_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_cancellation.py index 836fa112fd84..130ff0609354 100644 --- a/qiskit/transpiler/passes/optimization/commutative_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_cancellation.py @@ -11,23 +11,16 @@ # that they have been altered from the originals. """Cancel the redundant (self-adjoint) gates through commutation relations.""" - -from collections import defaultdict -import numpy as np - -from qiskit.circuit.quantumregister import QuantumRegister -from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.transpiler.basepasses import TransformationPass -from qiskit.transpiler.passmanager import PassManager -from qiskit.transpiler.passes.optimization.commutation_analysis import CommutationAnalysis -from qiskit.dagcircuit import DAGCircuit, DAGInNode, DAGOutNode -from qiskit.circuit.commutation_library import CommutationChecker, StandardGateCommutations +from qiskit.circuit.commutation_library import StandardGateCommutations + from qiskit.circuit.library.standard_gates.u1 import U1Gate -from qiskit.circuit.library.standard_gates.rx import RXGate from qiskit.circuit.library.standard_gates.p import PhaseGate from qiskit.circuit.library.standard_gates.rz import RZGate -from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES +from qiskit._accelerate import commutation_cancellation +from qiskit._accelerate.commutation_checker import CommutationChecker +from qiskit.transpiler.passes.utils.control_flow import trivial_recurse _CUTOFF_PRECISION = 1e-5 @@ -59,6 +52,7 @@ def __init__(self, basis_gates=None, target=None): self.basis = set(basis_gates) else: self.basis = set() + self.target = target if target is not None: self.basis = set(target.operation_names) @@ -70,12 +64,11 @@ def __init__(self, basis_gates=None, target=None): # build a commutation checker restricted to the gates we cancel -- the others we # do not have to investigate, which allows to save time - commutation_checker = CommutationChecker( + self._commutation_checker = CommutationChecker( StandardGateCommutations, gates=self._gates | self._z_rotations | self._x_rotations ) - self.requires.append(CommutationAnalysis(_commutation_checker=commutation_checker)) - + @trivial_recurse def run(self, dag): """Run the CommutativeCancellation pass on `dag`. @@ -85,141 +78,5 @@ def run(self, dag): Returns: DAGCircuit: the optimized DAG. """ - var_z_gate = None - z_var_gates = [gate for gate in dag.count_ops().keys() if gate in self._var_z_map] - if z_var_gates: - # prioritize z gates in circuit - var_z_gate = self._var_z_map[next(iter(z_var_gates))] - else: - z_var_gates = [gate for gate in self.basis if gate in self._var_z_map] - if z_var_gates: - var_z_gate = self._var_z_map[next(iter(z_var_gates))] - - # Gate sets to be cancelled - cancellation_sets = defaultdict(lambda: []) - - # Traverse each qubit to generate the cancel dictionaries - # Cancel dictionaries: - # - For 1-qubit gates the key is (gate_type, qubit_id, commutation_set_id), - # the value is the list of gates that share the same gate type, qubit, commutation set. - # - For 2qbit gates the key: (gate_type, first_qbit, sec_qbit, first commutation_set_id, - # sec_commutation_set_id), the value is the list gates that share the same gate type, - # qubits and commutation sets. - for wire in dag.qubits: - wire_commutation_set = self.property_set["commutation_set"][wire] - - for com_set_idx, com_set in enumerate(wire_commutation_set): - if isinstance(com_set[0], (DAGInNode, DAGOutNode)): - continue - for node in com_set: - num_qargs = len(node.qargs) - if any(isinstance(p, ParameterExpression) for p in node.params): - continue # no support for cancellation of parameterized gates - if num_qargs == 1 and node.name in self._gates: - cancellation_sets[(node.name, wire, com_set_idx)].append(node) - if num_qargs == 1 and node.name in self._z_rotations: - cancellation_sets[("z_rotation", wire, com_set_idx)].append(node) - if num_qargs == 1 and node.name in ["rx", "x"]: - cancellation_sets[("x_rotation", wire, com_set_idx)].append(node) - # Don't deal with Y rotation, because Y rotation doesn't commute with CNOT, so - # it should be dealt with by optimized1qgate pass - elif num_qargs == 2 and node.qargs[0] == wire: - second_qarg = node.qargs[1] - q2_key = ( - node.name, - wire, - second_qarg, - com_set_idx, - self.property_set["commutation_set"][(node, second_qarg)], - ) - cancellation_sets[q2_key].append(node) - - for cancel_set_key in cancellation_sets: - if cancel_set_key[0] == "z_rotation" and var_z_gate is None: - continue - set_len = len(cancellation_sets[cancel_set_key]) - if set_len > 1 and cancel_set_key[0] in self._gates: - gates_to_cancel = cancellation_sets[cancel_set_key] - for c_node in gates_to_cancel[: (set_len // 2) * 2]: - dag.remove_op_node(c_node) - - elif set_len > 1 and cancel_set_key[0] in ["z_rotation", "x_rotation"]: - run = cancellation_sets[cancel_set_key] - run_qarg = run[0].qargs[0] - total_angle = 0.0 # lambda - total_phase = 0.0 - for current_node in run: - if ( - current_node.condition is not None - or len(current_node.qargs) != 1 - or current_node.qargs[0] != run_qarg - ): - raise RuntimeError("internal error") - - if current_node.name in ["p", "u1", "rz", "rx"]: - current_angle = float(current_node.params[0]) - elif current_node.name in ["z", "x"]: - current_angle = np.pi - elif current_node.name == "t": - current_angle = np.pi / 4 - elif current_node.name == "s": - current_angle = np.pi / 2 - else: - raise RuntimeError( - f"Angle for operation {current_node.name } is not defined" - ) - - # Compose gates - total_angle = current_angle + total_angle - if current_node.definition: - total_phase += current_node.definition.global_phase - - # Replace the data of the first node in the run - if cancel_set_key[0] == "z_rotation": - new_op = var_z_gate(total_angle) - elif cancel_set_key[0] == "x_rotation": - new_op = RXGate(total_angle) - else: - raise RuntimeError("impossible case") - - new_op_phase = 0 - if np.mod(total_angle, (2 * np.pi)) > _CUTOFF_PRECISION: - new_qarg = QuantumRegister(1, "q") - new_dag = DAGCircuit() - new_dag.add_qreg(new_qarg) - new_dag.apply_operation_back(new_op, [new_qarg[0]]) - dag.substitute_node_with_dag(run[0], new_dag) - if new_op.definition: - new_op_phase = new_op.definition.global_phase - - dag.global_phase = total_phase - new_op_phase - - # Delete the other nodes in the run - for current_node in run[1:]: - dag.remove_op_node(current_node) - - if np.mod(total_angle, (2 * np.pi)) < _CUTOFF_PRECISION: - dag.remove_op_node(run[0]) - - dag = self._handle_control_flow_ops(dag) - - return dag - - def _handle_control_flow_ops(self, dag): - """ - This is similar to transpiler/passes/utils/control_flow.py except that the - commutation analysis is redone for the control flow blocks. - """ - - pass_manager = PassManager([CommutationAnalysis(), self]) - for node in dag.op_nodes(): - if node.name not in CONTROL_FLOW_OP_NAMES: - continue - mapped_blocks = [] - for block in node.op.blocks: - new_circ = pass_manager.run(block) - mapped_blocks.append(new_circ) - dag.substitute_node( - node, node.op.replace_blocks(mapped_blocks), propagate_condition=False - ) + commutation_cancellation.cancel_commutations(dag, self._commutation_checker, self.basis) return dag diff --git a/test/python/transpiler/test_commutative_cancellation.py b/test/python/transpiler/test_commutative_cancellation.py index 71bab61708cd..88f1d99bef31 100644 --- a/test/python/transpiler/test_commutative_cancellation.py +++ b/test/python/transpiler/test_commutative_cancellation.py @@ -13,6 +13,7 @@ """Gate cancellation pass testing""" import unittest + import numpy as np from qiskit import QuantumRegister, QuantumCircuit @@ -76,7 +77,7 @@ def test_all_gates(self): expected = QuantumCircuit(qr) expected.append(RZGate(2.0), [qr[0]]) expected.rx(1.0, qr[0]) - + expected.global_phase = 0.5 self.assertEqual(expected, new_circuit) def test_commutative_circuit1(self): @@ -433,7 +434,7 @@ def test_commutative_circuit3(self): expected.append(RZGate(np.pi * 17 / 12), [qr[2]]) expected.append(RZGate(np.pi * 2 / 3), [qr[3]]) expected.cx(qr[2], qr[1]) - + expected.global_phase = 3 * np.pi / 8 self.assertEqual( expected, new_circuit, msg=f"expected:\n{expected}\nnew_circuit:\n{new_circuit}" ) diff --git a/test/python/transpiler/test_passmanager.py b/test/python/transpiler/test_passmanager.py index ce4d28bf314e..60375a820655 100644 --- a/test/python/transpiler/test_passmanager.py +++ b/test/python/transpiler/test_passmanager.py @@ -27,7 +27,7 @@ DoWhileController, ) from qiskit.transpiler import PassManager, PropertySet, TransformationPass -from qiskit.transpiler.passes import CommutativeCancellation +from qiskit.transpiler.passes import RXCalibrationBuilder from qiskit.transpiler.passes import Optimize1qGates, BasisTranslator from qiskit.circuit.library.standard_gates.equivalence_library import ( StandardEquivalenceLibrary as std_eqlib, @@ -97,7 +97,6 @@ def test_callback_with_pass_requires(self): expected_end = QuantumCircuit(qr) expected_end.cx(qr[0], qr[2]) - expected_end_dag = circuit_to_dag(expected_end) calls = [] @@ -107,20 +106,19 @@ def callback(**kwargs): calls.append(out_dict) passmanager = PassManager() - passmanager.append(CommutativeCancellation(basis_gates=["u1", "u2", "u3", "cx"])) + passmanager.append(RXCalibrationBuilder()) passmanager.run(circuit, callback=callback) self.assertEqual(len(calls), 2) self.assertEqual(len(calls[0]), 5) self.assertEqual(calls[0]["count"], 0) - self.assertEqual(calls[0]["pass_"].name(), "CommutationAnalysis") + self.assertEqual(calls[0]["pass_"].name(), "NormalizeRXAngle") self.assertEqual(expected_start_dag, calls[0]["dag"]) self.assertIsInstance(calls[0]["time"], float) self.assertIsInstance(calls[0]["property_set"], PropertySet) self.assertEqual("MyCircuit", calls[0]["dag"].name) self.assertEqual(len(calls[1]), 5) self.assertEqual(calls[1]["count"], 1) - self.assertEqual(calls[1]["pass_"].name(), "CommutativeCancellation") - self.assertEqual(expected_end_dag, calls[1]["dag"]) + self.assertEqual(calls[1]["pass_"].name(), "RXCalibrationBuilder") self.assertIsInstance(calls[0]["time"], float) self.assertIsInstance(calls[0]["property_set"], PropertySet) self.assertEqual("MyCircuit", calls[1]["dag"].name)