From 4cc652c23a6e8bfa1675f619660808c50c9a4020 Mon Sep 17 00:00:00 2001 From: Raynel Sanchez Date: Tue, 27 Aug 2024 13:43:42 -0400 Subject: [PATCH] Fix: Make use of `copy_operations` - Use `copy_operations` to copy all of the operations obtained from `CircuitData` by calling deepcopy. - Initialize `._data` manually for instances of `BlueprintCircuit` by calling `._build()`. - Other small fixes. --- crates/circuit/src/converters.rs | 15 +++++++++++---- crates/circuit/src/dag_circuit.rs | 25 +++++++++++++------------ qiskit/converters/circuit_to_dag.py | 26 +++++++++++++------------- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/crates/circuit/src/converters.rs b/crates/circuit/src/converters.rs index ff061ab9cf48..b293d77c245b 100644 --- a/crates/circuit/src/converters.rs +++ b/crates/circuit/src/converters.rs @@ -24,7 +24,7 @@ use crate::{circuit_data::CircuitData, dag_circuit::DAGCircuit}; /// it contains callbacks to Python and should not be stored anywhere. #[derive(Debug)] pub(crate) struct QuantumCircuitData<'py> { - pub data: PyRef<'py, CircuitData>, + pub data: CircuitData, pub name: Option>, pub calibrations: HashMap>, pub metadata: Option>, @@ -38,7 +38,7 @@ pub(crate) struct QuantumCircuitData<'py> { impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> { fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { let circuit_data = ob.getattr("_data")?; - let data_borrowed = circuit_data.downcast::()?.borrow(); + let data_borrowed = circuit_data.extract::()?; Ok(QuantumCircuitData { data: data_borrowed, name: ob.getattr("name").ok(), @@ -53,14 +53,21 @@ impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> { } } -#[pyfunction] +#[pyfunction(signature = (quantum_circuit, copy_operations = true, qubit_order = None, clbit_order = None))] fn circuit_to_dag( py: Python, quantum_circuit: QuantumCircuitData, + copy_operations: bool, qubit_order: Option>, clbit_order: Option>, ) -> PyResult { - DAGCircuit::from_quantum_circuit(py, quantum_circuit, qubit_order, clbit_order) + DAGCircuit::from_quantum_circuit( + py, + quantum_circuit, + copy_operations, + qubit_order, + clbit_order, + ) } pub fn converters(m: &Bound) -> PyResult<()> { diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index c9c3caa644ac..f7e0a702dbff 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -6374,11 +6374,16 @@ impl DAGCircuit { pub(crate) fn from_quantum_circuit( py: Python, qc: QuantumCircuitData, + copy_op: bool, qubit_order: Option>, clbit_order: Option>, ) -> PyResult { // Extract necessary attributes - let qc_data = qc.data; + let qc_data = if copy_op { + qc.data.copy(py, true, true)? + } else { + qc.data + }; let num_qubits = qc_data.num_qubits(); let num_clbits = qc_data.num_clbits(); let num_ops = qc_data.__len__(); @@ -6431,10 +6436,9 @@ impl DAGCircuit { qubits } else { let qubits: Vec = (0..num_qubits as u32).map(Qubit).collect(); - for qubit in &qubits { - let qubit = qc_data.qubits().get(*qubit).unwrap(); - let bound = qubit.bind(py); - qubit_data.add(py, bound, false)?; + for qubit in qc_data.qubits().bits() { + let bound = qubit.clone_ref(py).into_bound(py); + qubit_data.add(py, &bound, false)?; } qubits }; @@ -6456,11 +6460,10 @@ impl DAGCircuit { } clbits } else { - let clbits: Vec = (0..num_clbits as u32).map(Clbit).collect(); - for clbit in &clbits { - let clbit = qc_data.clbits().get(*clbit).unwrap(); - let bound = clbit.bind(py); - clbit_data.add(py, bound, false)?; + let clbits: Vec = (0..num_qubits as u32).map(Clbit).collect(); + for clbit in qc_data.clbits().bits() { + let bound = clbit.clone_ref(py).into_bound(py); + clbit_data.add(py, &bound, false)?; } clbits }; @@ -6518,8 +6521,6 @@ impl DAGCircuit { new_dag.calibrations = qc.calibrations; new_dag.metadata = qc.metadata.map(|meta| meta.unbind()); - // TODO: Use Qubit ordering to remap the interners and qubit - // Copy over all interners and registers new_dag.qargs_cache = qubit_interner; new_dag.cargs_cache = clbit_interner; diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index 39f8a1088d4f..f4433c468de5 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -12,8 +12,7 @@ """Helper function for converting a circuit to a dag""" -from qiskit.dagcircuit.dagcircuit import DAGCircuit -from qiskit.dagcircuit.dagnode import DAGOpNode +from qiskit.circuit.library.blueprintcircuit import BlueprintCircuit from qiskit._accelerate.circuit.converters import circuit_to_dag as core_circuit_to_dag @@ -57,21 +56,22 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord circ.rz(0.5, q[1]).c_if(c, 2) dag = circuit_to_dag(circ) """ - if qubit_order is None: - qubits = circuit.qubits - elif len(qubit_order) != circuit.num_qubits or set(qubit_order) != set(circuit.qubits): + # If we have an instance of BluePrintCircuit, make sure it is built by calling ._build() + if isinstance(circuit, BlueprintCircuit): + if not circuit._is_built: + circuit._build() + + if qubit_order is not None and ( + len(qubit_order) != circuit.num_qubits or set(qubit_order) != set(circuit.qubits) + ): raise ValueError("'qubit_order' does not contain exactly the same qubits as the circuit") - else: - qubits = qubit_order - if clbit_order is None: - clbits = circuit.clbits - elif len(clbit_order) != circuit.num_clbits or set(clbit_order) != set(circuit.clbits): + if clbit_order is not None and ( + len(clbit_order) != circuit.num_clbits or set(clbit_order) != set(circuit.clbits) + ): raise ValueError("'clbit_order' does not contain exactly the same clbits as the circuit") - else: - clbits = clbit_order - dagcircuit = core_circuit_to_dag(circuit, qubit_order, clbit_order) + dagcircuit = core_circuit_to_dag(circuit, copy_operations, qubit_order, clbit_order) dagcircuit.duration = circuit.duration dagcircuit.unit = circuit.unit