From 297137ba279e725ee21a8c04c1d35ea3fb21e15d Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Mon, 12 Aug 2024 15:42:30 +0200 Subject: [PATCH] Allow `CircuitData` construction from `PackedOperation`s (#12943) * ``CircuitData::from_packed_operations`` * missing import * remove redundant `to_vec` (cherry picked from commit b1e7ffeff000d4034d70e691da92062bb5b0730d) --- crates/circuit/src/circuit_data.rs | 67 +++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index dc83c9dd2487..502f4c26f1b4 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -18,7 +18,7 @@ use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; use crate::imports::{ANNOTATED_OPERATION, QUANTUM_CIRCUIT, QUBIT}; use crate::interner::{IndexedInterner, Interner, InternerKey}; use crate::operations::{Operation, OperationRef, Param, StandardGate}; -use crate::packed_instruction::PackedInstruction; +use crate::packed_instruction::{PackedInstruction, PackedOperation}; use crate::parameter_table::{ParameterTable, ParameterTableError, ParameterUse, ParameterUuid}; use crate::slice::{PySequenceIndex, SequenceIndex}; use crate::{Clbit, Qubit}; @@ -104,6 +104,71 @@ pub struct CircuitData { } impl CircuitData { + /// An alternate constructor to build a new `CircuitData` from an iterator + /// of packed operations. This can be used to build a circuit from a sequence + /// of `PackedOperation` without needing to involve Python. + /// + /// This can be connected with the Python space + /// QuantumCircuit.from_circuit_data() constructor to build a full + /// QuantumCircuit from Rust. + /// + /// # Arguments + /// + /// * py: A GIL handle this is needed to instantiate Qubits in Python space + /// * num_qubits: The number of qubits in the circuit. These will be created + /// in Python as loose bits without a register. + /// * num_clbits: The number of classical bits in the circuit. These will be created + /// in Python as loose bits without a register. + /// * instructions: An iterator of the (packed operation, params, qubits, clbits) to + /// add to the circuit + /// * global_phase: The global phase to use for the circuit + pub fn from_packed_operations( + py: Python, + num_qubits: u32, + num_clbits: u32, + instructions: I, + global_phase: Param, + ) -> PyResult + where + I: IntoIterator< + Item = ( + PackedOperation, + SmallVec<[Param; 3]>, + Vec, + Vec, + ), + >, + { + let instruction_iter = instructions.into_iter(); + let mut res = Self::with_capacity( + py, + num_qubits, + num_clbits, + instruction_iter.size_hint().0, + global_phase, + )?; + for (operation, params, qargs, cargs) in instruction_iter { + let qubits = (&mut res.qargs_interner) + .intern(InternerKey::Value(qargs))? + .index; + let clbits = (&mut res.cargs_interner) + .intern(InternerKey::Value(cargs))? + .index; + let params = (!params.is_empty()).then(|| Box::new(params)); + res.data.push(PackedInstruction { + op: operation, + qubits, + clbits, + params, + extra_attrs: None, + #[cfg(feature = "cache_pygates")] + py_op: RefCell::new(None), + }); + res.track_instruction_parameters(py, res.data.len() - 1)?; + } + Ok(res) + } + /// An alternate constructor to build a new `CircuitData` from an iterator /// of standard gates. This can be used to build a circuit from a sequence /// of standard gates, such as for a `StandardGate` definition or circuit