From c30740bb2ca6629388da6e4871225351dcec5fce Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:24:39 -0400 Subject: [PATCH] Allow `CircuitData` construction from `PackedOperation`s and `with_capacity`(backport #12943 + part of #12809) (#13038) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow `CircuitData` construction from `PackedOperation`s (#12943) * ``CircuitData::from_packed_operations`` * missing import * remove redundant `to_vec` (cherry picked from commit b1e7ffeff000d4034d70e691da92062bb5b0730d) * Add with_capacity * Add CLBIT import * Run cargo fmt --------- Co-authored-by: Julien Gacon Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Elena Peña Tapia --- crates/circuit/src/circuit_data.rs | 103 ++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index dc83c9dd2487..011c2088bbc5 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -15,10 +15,10 @@ use std::cell::RefCell; use crate::bit_data::BitData; use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; -use crate::imports::{ANNOTATED_OPERATION, QUANTUM_CIRCUIT, QUBIT}; +use crate::imports::{ANNOTATED_OPERATION, CLBIT, 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 @@ -169,6 +234,40 @@ impl CircuitData { Ok(res) } + /// Build an empty CircuitData object with an initially allocated instruction capacity + pub fn with_capacity( + py: Python, + num_qubits: u32, + num_clbits: u32, + instruction_capacity: usize, + global_phase: Param, + ) -> PyResult { + let mut res = CircuitData { + data: Vec::with_capacity(instruction_capacity), + qargs_interner: IndexedInterner::new(), + cargs_interner: IndexedInterner::new(), + qubits: BitData::new(py, "qubits".to_string()), + clbits: BitData::new(py, "clbits".to_string()), + param_table: ParameterTable::new(), + global_phase, + }; + if num_qubits > 0 { + let qubit_cls = QUBIT.get_bound(py); + for _i in 0..num_qubits { + let bit = qubit_cls.call0()?; + res.add_qubit(py, &bit, true)?; + } + } + if num_clbits > 0 { + let clbit_cls = CLBIT.get_bound(py); + for _i in 0..num_clbits { + let bit = clbit_cls.call0()?; + res.add_clbit(py, &bit, true)?; + } + } + Ok(res) + } + /// Add the entries from the `PackedInstruction` at the given index to the internal parameter /// table. fn track_instruction_parameters(