Skip to content

Commit

Permalink
Add: DAGCircuit from CircuitData
Browse files Browse the repository at this point in the history
- Make `QuantumCircuitData` extraction struct private.
- Rename `DAGCircuit::from_quantum_circuit` into `DAGCircuit::from_circuit` to make more generalized.
- Pass all attributes of `QuantumCircuit` that are passed from python as arguments to the `DAGCircuit::from_circuit` function.
- Add `DAGCircuit::from_circuit_data` as a wrapper to `from_circuit` to create an instance solely from the properties available in `CircuitData`.
    - Use `DAGCircuit::from_circuit` as base for `DAGCircuit::from_circuit_data`.
  • Loading branch information
raynelfss committed Sep 3, 2024
1 parent 5b0ce5e commit 8a46a04
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 45 deletions.
51 changes: 35 additions & 16 deletions crates/circuit/src/converters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ use crate::{circuit_data::CircuitData, dag_circuit::DAGCircuit};
/// This structure does not implement `Clone`, this is the intended behavior as
/// it contains callbacks to Python and should not be stored anywhere.
#[derive(Debug)]
pub(crate) struct QuantumCircuitData<'py> {
pub data: CircuitData,
pub name: Option<Bound<'py, PyAny>>,
pub calibrations: HashMap<String, Py<PyDict>>,
pub metadata: Option<Bound<'py, PyAny>>,
pub qregs: Option<Bound<'py, PyList>>,
pub cregs: Option<Bound<'py, PyList>>,
pub input_vars: Option<Bound<'py, PyAny>>,
pub captured_vars: Option<Bound<'py, PyAny>>,
pub declared_vars: Option<Bound<'py, PyAny>>,
struct QuantumCircuitData<'py> {
data: CircuitData,
name: Option<Bound<'py, PyAny>>,
calibrations: Option<HashMap<String, Py<PyDict>>>,
metadata: Option<Bound<'py, PyAny>>,
qregs: Option<Bound<'py, PyList>>,
cregs: Option<Bound<'py, PyList>>,
input_vars: Vec<Bound<'py, PyAny>>,
captured_vars: Vec<Bound<'py, PyAny>>,
declared_vars: Vec<Bound<'py, PyAny>>,
}

impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> {
Expand All @@ -42,13 +42,22 @@ impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> {
Ok(QuantumCircuitData {
data: data_borrowed,
name: ob.getattr("name").ok(),
calibrations: ob.getattr("calibrations")?.extract()?,
calibrations: ob.getattr("calibrations")?.extract().ok(),
metadata: ob.getattr("metadata").ok(),
qregs: ob.getattr("qregs").map(|ob| ob.downcast_into())?.ok(),
cregs: ob.getattr("cregs").map(|ob| ob.downcast_into())?.ok(),
input_vars: ob.call_method0("iter_input_vars").ok(),
captured_vars: ob.call_method0("iter_captured_vars").ok(),
declared_vars: ob.call_method0("iter_declared_vars").ok(),
input_vars: ob
.call_method0("iter_input_vars")?
.iter()?
.collect::<PyResult<Vec<_>>>()?,
captured_vars: ob
.call_method0("iter_captured_vars")?
.iter()?
.collect::<PyResult<Vec<_>>>()?,
declared_vars: ob
.call_method0("iter_declared_vars")?
.iter()?
.collect::<PyResult<Vec<_>>>()?,
})
}
}
Expand All @@ -61,10 +70,20 @@ fn circuit_to_dag(
qubit_order: Option<Vec<Bound<PyAny>>>,
clbit_order: Option<Vec<Bound<PyAny>>>,
) -> PyResult<DAGCircuit> {
DAGCircuit::from_quantum_circuit(
DAGCircuit::from_circuit(
py,
quantum_circuit,
&quantum_circuit.data,
copy_operations,
Some([
quantum_circuit.declared_vars,
quantum_circuit.input_vars,
quantum_circuit.captured_vars,
]),
quantum_circuit.qregs,
quantum_circuit.cregs,
quantum_circuit.metadata,
quantum_circuit.name,
quantum_circuit.calibrations,
qubit_order,
clbit_order,
)
Expand Down
81 changes: 52 additions & 29 deletions crates/circuit/src/dag_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ use std::hash::{Hash, Hasher};
use ahash::RandomState;

use crate::bit_data::BitData;
use crate::circuit_data::CircuitData;
use crate::circuit_instruction::{
CircuitInstruction, ExtraInstructionAttributes, OperationFromPython,
};
use crate::converters::QuantumCircuitData;
use crate::dag_node::{DAGInNode, DAGNode, DAGOpNode, DAGOutNode};
use crate::dot_utils::build_dot;
use crate::error::DAGCircuitError;
Expand Down Expand Up @@ -6480,32 +6480,35 @@ impl DAGCircuit {
Ok(new_nodes)
}

#[allow(clippy::too_many_arguments)]
/// Alternative constructor to build an instance of [DAGCircuit] from a `QuantumCircuit`.
pub(crate) fn from_quantum_circuit(
pub(crate) fn from_circuit(
py: Python,
qc: QuantumCircuitData,
qc: &CircuitData,
copy_op: bool,
vars: Option<[Vec<Bound<PyAny>>; 3]>,
qregs: Option<Bound<PyList>>,
cregs: Option<Bound<PyList>>,
metadata: Option<Bound<PyAny>>,
name: Option<Bound<PyAny>>,
calibrations: Option<HashMap<String, Py<PyDict>>>,
qubit_order: Option<Vec<Bound<PyAny>>>,
clbit_order: Option<Vec<Bound<PyAny>>>,
) -> PyResult<DAGCircuit> {
let copied: CircuitData;
// Extract necessary attributes
let qc_data = if copy_op {
qc.data.copy(py, true, true)?
copied = qc.copy(py, true, true)?;
&copied
} else {
qc.data
qc
};
let num_qubits = qc_data.num_qubits();
let num_clbits = qc_data.num_clbits();
let num_ops = qc_data.__len__();
let mut num_vars = 0;
if let Some(vars) = &qc.input_vars {
num_vars += vars.len()?;
}
if let Some(vars) = &qc.captured_vars {
num_vars += vars.len()?;
}
if let Some(vars) = &qc.declared_vars {
num_vars += vars.len()?;
if let Some(vars) = &vars {
num_vars += vars[0].len() + vars[1].len() + vars[2].len();
}

// Build DAGCircuit with capacity
Expand All @@ -6519,7 +6522,7 @@ impl DAGCircuit {
)?;

// Assign other necessary data
new_dag.name = qc.name.map(|ob| ob.unbind());
new_dag.name = name.map(|ob| ob.unbind());

// Avoid manually acquiring the GIL.
new_dag.global_phase = match qc_data.global_phase() {
Expand All @@ -6528,8 +6531,11 @@ impl DAGCircuit {
_ => unreachable!("Incorrect parameter assigned for global phase"),
};

new_dag.calibrations = qc.calibrations;
new_dag.metadata = qc.metadata.map(|meta| meta.unbind());
if let Some(calibrations) = calibrations {
new_dag.calibrations = calibrations;
}

new_dag.metadata = metadata.map(|meta| meta.unbind());

// Add the qubits depending on order.
let mut qubit_map: HashMap<Qubit, Bound<PyAny>> = HashMap::new();
Expand Down Expand Up @@ -6570,32 +6576,28 @@ impl DAGCircuit {
}

// Add all of the new vars.
if let Some(vars) = qc.declared_vars {
for var in vars.iter()? {
new_dag.add_var(py, &var?, DAGVarType::Declare)?;
if let Some(vars) = vars {
for var in &vars[0] {
new_dag.add_var(py, var, DAGVarType::Declare)?;
}
}

if let Some(vars) = qc.input_vars {
for var in vars.iter()? {
new_dag.add_var(py, &var?, DAGVarType::Input)?;
for var in &vars[1] {
new_dag.add_var(py, var, DAGVarType::Input)?;
}
}

if let Some(vars) = qc.captured_vars {
for var in vars.iter()? {
new_dag.add_var(py, &var?, DAGVarType::Capture)?;
for var in &vars[2] {
new_dag.add_var(py, var, DAGVarType::Capture)?;
}
}

// Add all the registers
if let Some(qregs) = qc.qregs {
if let Some(qregs) = qregs {
for qreg in qregs.iter() {
new_dag.add_qreg(py, &qreg)?;
}
}

if let Some(cregs) = qc.cregs {
if let Some(cregs) = cregs {
for creg in cregs.iter() {
new_dag.add_creg(py, &creg)?;
}
Expand Down Expand Up @@ -6640,6 +6642,27 @@ impl DAGCircuit {

Ok(new_dag)
}

/// Builds a [DAGCircuit] based on an instance of [CircuitData].
pub fn from_circuit_data(
py: Python,
circuit_data: &CircuitData,
copy_op: bool,
) -> PyResult<Self> {
Self::from_circuit(
py,
circuit_data,
copy_op,
None,
None,
None,
None,
None,
None,
None,
None,
)
}
}

/// Add to global phase. Global phase can only be Float or ParameterExpression so this
Expand Down

0 comments on commit 8a46a04

Please sign in to comment.