-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fully port CheckMap to Rust #13030
Fully port CheckMap to Rust #13030
Changes from 2 commits
88b4265
341a65b
298c4b2
64c47b8
ccb9ddf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// 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 hashbrown::HashSet; | ||
use pyo3::intern; | ||
use pyo3::prelude::*; | ||
use pyo3::wrap_pyfunction; | ||
|
||
use qiskit_circuit::circuit_data::CircuitData; | ||
use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType}; | ||
use qiskit_circuit::imports::CIRCUIT_TO_DAG; | ||
use qiskit_circuit::operations::{Operation, OperationRef}; | ||
use qiskit_circuit::Qubit; | ||
|
||
fn recurse<'py>( | ||
py: Python<'py>, | ||
dag: &'py DAGCircuit, | ||
edge_set: &'py HashSet<[u32; 2]>, | ||
wire_map: Option<&'py [Qubit]>, | ||
) -> PyResult<Option<(String, [u32; 2])>> { | ||
let check_qubits = |qubits: &[Qubit]| -> bool { | ||
match wire_map { | ||
Some(wire_map) => { | ||
let mapped_bits = [ | ||
wire_map[qubits[0].0 as usize], | ||
wire_map[qubits[1].0 as usize], | ||
]; | ||
edge_set.contains(&[mapped_bits[0].into(), mapped_bits[1].into()]) | ||
} | ||
None => edge_set.contains(&[qubits[0].into(), qubits[1].into()]), | ||
} | ||
}; | ||
for node in dag.op_nodes(false) { | ||
if let NodeType::Operation(inst) = &dag.dag[node] { | ||
let qubits = dag.get_qargs(inst.qubits); | ||
if inst.op.control_flow() { | ||
if let OperationRef::Instruction(py_inst) = inst.op.view() { | ||
let raw_blocks = py_inst.instruction.getattr(py, "blocks")?; | ||
let circuit_to_dag = CIRCUIT_TO_DAG.get_bound(py); | ||
raynelfss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for raw_block in raw_blocks.bind(py).iter().unwrap() { | ||
let block_obj = raw_block?; | ||
let block = block_obj | ||
.getattr(intern!(py, "_data"))? | ||
.extract::<CircuitData>()?; | ||
mtreinish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let new_dag: DAGCircuit = | ||
circuit_to_dag.call1((block_obj.clone(),))?.extract()?; | ||
let wire_map = (0..block.num_qubits()) | ||
.map(|inner| { | ||
let outer = qubits[inner]; | ||
match wire_map { | ||
Some(wire_map) => wire_map[outer.0 as usize], | ||
None => outer, | ||
} | ||
}) | ||
.collect::<Vec<_>>(); | ||
let res = recurse(py, &new_dag, edge_set, Some(&wire_map))?; | ||
if res.is_some() { | ||
return Ok(res); | ||
} | ||
} | ||
} | ||
} else if qubits.len() == 2 | ||
&& (dag.calibrations_empty() || !dag.has_calibration_for_index(py, node)?) | ||
&& !check_qubits(qubits) | ||
{ | ||
return Ok(Some(( | ||
inst.op.name().to_string(), | ||
[qubits[0].0, qubits[1].0], | ||
))); | ||
} | ||
} | ||
} | ||
Ok(None) | ||
} | ||
|
||
#[pyfunction] | ||
pub fn check_map( | ||
py: Python, | ||
dag: &DAGCircuit, | ||
edge_set: HashSet<[u32; 2]>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Besides dropping |
||
) -> PyResult<Option<(String, [u32; 2])>> { | ||
recurse(py, dag, &edge_set, None) | ||
} | ||
|
||
pub fn check_map_mod(m: &Bound<PyModule>) -> PyResult<()> { | ||
m.add_wrapped(wrap_pyfunction!(check_map))?; | ||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR, but I wonder if eventually we should add methods like
DAGCircuit::op_node_references
and have that return an iterator of some node reference type which holds theNodeId
and a&PackedInstruction
so that users don't need to unwrap. Sort of like whatpetgraph
has for theirIntoNodeReferences
trait.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the sound of that. Currently a lot of the rust
DAGCircuit
API is limited, and everyone seems to be adding stuff in their transpiler passes PRs to save time. We could discuss this further in its own issue if you're interested in working on it :)