Add rust-native `apply_operation` methods (#13143)

* Initial: Add rust-native `apply_operation_front` and `apply_operation_back methods.
- These methods allow rust users to add an operation to either the front or the back of the circuit without needing to have valid interned indices for the Qargs/Qargs of said operations.
- Leverage the new methods in the existing python variants of them.

* Fix: Remove extra blank space

* Fix: Revert changes to python `apply_op` methods.
- To avoid an ownership issue, usage of the new methods from the Python variants has been removed.
- As requested, the insertion check in the rust `apply_op` has been removed.

* Fix: Adapt to new `ExtraInstructionProperties` infrastructure.

* Format: Change redundant iteration statement for params
This commit is contained in:
Raynel Sanchez 2024-09-17 17:55:21 -04:00 committed by GitHub
parent 87836411a8
commit c68e80329c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 110 additions and 1 deletions

View File

@ -13,6 +13,7 @@
use std::hash::{Hash, Hasher};
use ahash::RandomState;
use smallvec::SmallVec;
use crate::bit_data::BitData;
use crate::circuit_data::CircuitData;
@ -26,7 +27,7 @@ use crate::error::DAGCircuitError;
use crate::imports;
use crate::interner::{Interned, Interner};
use crate::operations::{Operation, OperationRef, Param, PyInstruction, StandardGate};
use crate::packed_instruction::PackedInstruction;
use crate::packed_instruction::{PackedInstruction, PackedOperation};
use crate::rustworkx_core_vnext::isomorphism;
use crate::{BitType, Clbit, Qubit, TupleLikeArg};
@ -5192,6 +5193,114 @@ impl DAGCircuit {
Ok(new_node)
}
/// Apply a [PackedOperation] to the back of the circuit.
pub fn apply_operation_back(
&mut self,
py: Python,
op: PackedOperation,
qargs: &[Qubit],
cargs: &[Clbit],
params: Option<SmallVec<[Param; 3]>>,
extra_attrs: ExtraInstructionAttributes,
#[cfg(feature = "cache_pygates")] py_op: Option<PyObject>,
) -> PyResult<NodeIndex> {
self.inner_apply_op(
py,
op,
qargs,
cargs,
params,
extra_attrs,
#[cfg(feature = "cache_pygates")]
py_op,
false,
)
}
/// Apply a [PackedOperation] to the front of the circuit.
pub fn apply_operation_front(
&mut self,
py: Python,
op: PackedOperation,
qargs: &[Qubit],
cargs: &[Clbit],
params: Option<SmallVec<[Param; 3]>>,
extra_attrs: ExtraInstructionAttributes,
#[cfg(feature = "cache_pygates")] py_op: Option<PyObject>,
) -> PyResult<NodeIndex> {
self.inner_apply_op(
py,
op,
qargs,
cargs,
params,
extra_attrs,
#[cfg(feature = "cache_pygates")]
py_op,
true,
)
}
#[inline]
#[allow(clippy::too_many_arguments)]
fn inner_apply_op(
&mut self,
py: Python,
op: PackedOperation,
qargs: &[Qubit],
cargs: &[Clbit],
params: Option<SmallVec<[Param; 3]>>,
extra_attrs: ExtraInstructionAttributes,
#[cfg(feature = "cache_pygates")] py_op: Option<PyObject>,
front: bool,
) -> PyResult<NodeIndex> {
// Check that all qargs are within an acceptable range
qargs.iter().try_for_each(|qarg| {
if qarg.0 as usize >= self.num_qubits() {
return Err(PyValueError::new_err(format!(
"Qubit index {} is out of range. This DAGCircuit currently has only {} qubits.",
qarg.0,
self.num_qubits()
)));
}
Ok(())
})?;
// Check that all cargs are within an acceptable range
cargs.iter().try_for_each(|carg| {
if carg.0 as usize >= self.num_clbits() {
return Err(PyValueError::new_err(format!(
"Clbit index {} is out of range. This DAGCircuit currently has only {} clbits.",
carg.0,
self.num_clbits()
)));
}
Ok(())
})?;
#[cfg(feature = "cache_pygates")]
let py_op = if let Some(py_op) = py_op {
py_op.into()
} else {
OnceCell::new()
};
let packed_instruction = PackedInstruction {
op,
qubits: self.qargs_interner.insert(qargs),
clbits: self.cargs_interner.insert(cargs),
params: params.map(Box::new),
extra_attrs,
#[cfg(feature = "cache_pygates")]
py_op,
};
if front {
self.push_front(py, packed_instruction)
} else {
self.push_back(py, packed_instruction)
}
}
fn sort_key(&self, node: NodeIndex) -> SortKeyType {
match &self.dag[node] {
NodeType::Operation(packed) => (