Skip to content

Commit

Permalink
Merge branch 'oxidize-dag' into oxidize-dag-family-tree
Browse files Browse the repository at this point in the history
  • Loading branch information
raynelfss committed Jun 28, 2024
2 parents 8e0f5d9 + 7523def commit a4facc9
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 18 deletions.
52 changes: 46 additions & 6 deletions crates/circuit/src/dag_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -138,7 +138,9 @@ pub struct DAGCircuit {

dag: StableDiGraph<NodeType, Wire>,

#[pyo3(get)]
qregs: Py<PyDict>,
#[pyo3(get)]
cregs: Py<PyDict>,

/// The cache used to intern instruction qargs.
Expand Down Expand Up @@ -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<PyList> {
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<PyList> {
self.clbits.cached().clone_ref(py)
}

/// Return a list of the wires in order.
#[getter]
fn get_wires(&self, py: Python<'_>) -> Py<PyList> {
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion crates/circuit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -49,8 +50,18 @@ pub struct TupleLikeArg<'py> {

impl<'py> FromPyObject<'py> for TupleLikeArg<'py> {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let value = match ob.downcast::<PySequence>() {
Ok(seq) => {seq.to_tuple()?}
Err(_) => {
PyTuple::new_bound(
ob.py(),
ob.iter()?
.map(|o| Ok(o?.unbind()))
.collect::<PyResult<Vec<PyObject>>>()?)
}
};
Ok(TupleLikeArg {
value: ob.downcast::<PySequence>()?.to_tuple()?,
value,
})
}
}
Expand Down
21 changes: 10 additions & 11 deletions qiskit/transpiler/passes/calibration/rzx_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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"]

Expand Down

0 comments on commit a4facc9

Please sign in to comment.