diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 91b13cf9e849..e8429a22957a 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -17,7 +17,7 @@ use crate::circuit_instruction::{ }; use crate::dag_node::{DAGInNode, DAGNode, DAGOpNode, DAGOutNode}; use crate::error::DAGCircuitError; -use crate::imports::VARIABLE_MAPPER; +use crate::imports::{DAG_NODE, VARIABLE_MAPPER}; use crate::interner::{Index, IndexedInterner, Interner}; use crate::operations::{Operation, OperationType, Param}; use crate::{interner, BitType, Clbit, Qubit, SliceOrInt, TupleLikeArg}; @@ -138,7 +138,9 @@ pub struct DAGCircuit { dag: StableDiGraph, + #[pyo3(get)] qregs: Py, + #[pyo3(get)] cregs: Py, /// The cache used to intern instruction qargs. @@ -384,6 +386,35 @@ impl DAGCircuit { }) } + /// Returns the current sequence of registered :class:`.Qubit` instances as a list. + /// + /// .. warning:: + /// + /// Do not modify this list yourself. It will invalidate the :class:`DAGCircuit` data + /// structures. + /// + /// Returns: + /// list(:class:`.Qubit`): The current sequence of registered qubits. + #[getter] + pub fn qubits(&self, py: Python<'_>) -> Py { + self.qubits.cached().clone_ref(py) + } + + /// Returns the current sequence of registered :class:`.Clbit` + /// instances as a list. + /// + /// .. warning:: + /// + /// Do not modify this list yourself. It will invalidate the :class:`DAGCircuit` data + /// structures. + /// + /// Returns: + /// list(:class:`.Clbit`): The current sequence of registered clbits. + #[getter] + pub fn clbits(&self, py: Python<'_>) -> Py { + self.clbits.cached().clone_ref(py) + } + /// Return a list of the wires in order. #[getter] fn get_wires(&self, py: Python<'_>) -> Py { @@ -1878,14 +1909,23 @@ def _format(operand): } } - // - // def node_eq(node_self, node_other): - // return DAGNode.semantic_eq(node_self, node_other, self_bit_indices, other_bit_indices) - // - // return rx.is_isomorphic_node_match(self._multi_graph, other._multi_graph, node_eq) todo!() + // Check for VF2 isomorphic match. + // self.topological_nodes() + // let semantic_eq = DAG_NODE.get_bound(py).getattr(intern!(py, "semantic_eq"))?; + // let node_match = |n1, n2| -> bool { + // semantic_eq + // .call1((n1, n2, self_bit_indices, other_bit_indices)).map_or(false, |r| r.extract().unwrap_or(false)) + // }; + // Ok(petgraph::algo::is_isomorphic_matching( + // &self.dag, + // &other.dag, + // node_match, + // |_, _| true, + // )) } + /// Yield nodes in topological order. /// /// Args: diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index 0df3707cc025..b0c0d63ac869 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -74,6 +74,8 @@ pub static SINGLETON_CONTROLLED_GATE: ImportOnceCell = pub static VARIABLE_MAPPER: ImportOnceCell = ImportOnceCell::new("qiskit.circuit._classical_resource_map", "VariableMapper"); +pub static DAG_NODE: ImportOnceCell = ImportOnceCell::new("qiskit.dagcircuit", "DAGNode"); + /// A mapping from the enum variant in crate::operations::StandardGate to the python /// module path and class name to import it. This is used to populate the conversion table /// when a gate is added directly via the StandardGate path and there isn't a Python object diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index 3d5b1c702c47..56cc3871e730 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -26,6 +26,7 @@ mod interner; use pyo3::prelude::*; use pyo3::types::{PySequence, PySlice, PyTuple}; use std::ops::Deref; +use pyo3::DowncastError; /// A private enumeration type used to extract arguments to pymethod /// that may be either an index or a slice @@ -49,8 +50,18 @@ pub struct TupleLikeArg<'py> { impl<'py> FromPyObject<'py> for TupleLikeArg<'py> { fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { + let value = match ob.downcast::() { + Ok(seq) => {seq.to_tuple()?} + Err(_) => { + PyTuple::new_bound( + ob.py(), + ob.iter()? + .map(|o| Ok(o?.unbind())) + .collect::>>()?) + } + }; Ok(TupleLikeArg { - value: ob.downcast::()?.to_tuple()?, + value, }) } } diff --git a/qiskit/transpiler/passes/calibration/rzx_templates.py b/qiskit/transpiler/passes/calibration/rzx_templates.py index 406e5e75de04..12211f18b2bc 100644 --- a/qiskit/transpiler/passes/calibration/rzx_templates.py +++ b/qiskit/transpiler/passes/calibration/rzx_templates.py @@ -20,17 +20,6 @@ from qiskit.circuit.library.templates import rzx -class RZXTemplateMap(Enum): - """Mapping of instruction name to decomposition template.""" - - ZZ1 = rzx.rzx_zz1() - ZZ2 = rzx.rzx_zz2() - ZZ3 = rzx.rzx_zz3() - YZ = rzx.rzx_yz() - XZ = rzx.rzx_xz() - CY = rzx.rzx_cy() - - def rzx_templates(template_list: List[str] = None) -> Dict: """Convenience function to get the cost_dict and templates for template matching. @@ -40,6 +29,16 @@ def rzx_templates(template_list: List[str] = None) -> Dict: Returns: Decomposition templates and cost values. """ + class RZXTempateMap(Enum): + """Mapping of instruction name to decomposition template.""" + + ZZ1 = rzx.rzx_zz1() + ZZ2 = rzx.rzx_zz2() + ZZ3 = rzx.rzx_zz3() + YZ = rzx.rzx_yz() + XZ = rzx.rzx_xz() + CY = rzx.rzx_cy() + if template_list is None: template_list = ["zz1", "zz2", "zz3", "yz", "xz", "cy"]