Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new API for inserting multiple operations into the DAGCircuit in Rust. #13335

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
55 changes: 29 additions & 26 deletions crates/accelerate/src/basis/basis_translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use pyo3::types::{IntoPyDict, PyComplex, PyDict, PyTuple};
use pyo3::PyTypeInfo;
use qiskit_circuit::circuit_instruction::OperationFromPython;
use qiskit_circuit::converters::circuit_to_dag;
use qiskit_circuit::dag_circuit::DAGCircuitConcat;
use qiskit_circuit::imports::DAG_TO_CIRCUIT;
use qiskit_circuit::imports::PARAMETER_EXPRESSION;
use qiskit_circuit::operations::Param;
Expand Down Expand Up @@ -429,6 +430,7 @@ fn apply_translation(
) -> PyResult<(DAGCircuit, bool)> {
let mut is_updated = false;
let mut out_dag = dag.copy_empty_like(py, "alike")?;
let mut out_dag_concat = out_dag.as_concat();
for node in dag.topological_op_nodes()? {
let node_obj = dag.dag()[node].unwrap_operation();
let node_qarg = dag.get_qargs(node_obj.qubits);
Expand Down Expand Up @@ -471,11 +473,11 @@ fn apply_translation(
new_op = Some(replaced_blocks.extract()?);
}
if let Some(new_op) = new_op {
out_dag.apply_operation_back(
out_dag_concat.apply_operation_back(
py,
new_op.operation,
node_qarg,
node_carg,
Some(node_qarg.into()),
Some(node_carg.into()),
if new_op.params.is_empty() {
None
} else {
Expand All @@ -484,13 +486,13 @@ fn apply_translation(
new_op.extra_attrs,
#[cfg(feature = "cache_pygates")]
None,
)?;
);
} else {
out_dag.apply_operation_back(
out_dag_concat.apply_operation_back(
py,
node_obj.op.clone(),
node_qarg,
node_carg,
Some(node_qarg.into()),
Some(node_carg.into()),
if node_obj.params_view().is_empty() {
None
} else {
Expand All @@ -505,7 +507,7 @@ fn apply_translation(
node_obj.extra_attrs.clone(),
#[cfg(feature = "cache_pygates")]
None,
)?;
);
}
continue;
}
Expand All @@ -514,11 +516,11 @@ fn apply_translation(
if qargs_with_non_global_operation.contains_key(&node_qarg_as_physical)
&& qargs_with_non_global_operation[&node_qarg_as_physical].contains(node_obj.op.name())
{
out_dag.apply_operation_back(
out_dag_concat.apply_operation_back(
py,
node_obj.op.clone(),
node_qarg,
node_carg,
Some(node_qarg.into()),
Some(node_carg.into()),
if node_obj.params_view().is_empty() {
None
} else {
Expand All @@ -533,16 +535,16 @@ fn apply_translation(
node_obj.extra_attrs.clone(),
#[cfg(feature = "cache_pygates")]
None,
)?;
);
continue;
}

if dag.has_calibration_for_index(py, node)? {
out_dag.apply_operation_back(
out_dag_concat.apply_operation_back(
py,
node_obj.op.clone(),
node_qarg,
node_carg,
Some(node_qarg.into()),
Some(node_carg.into()),
if node_obj.params_view().is_empty() {
None
} else {
Expand All @@ -557,7 +559,7 @@ fn apply_translation(
node_obj.extra_attrs.clone(),
#[cfg(feature = "cache_pygates")]
None,
)?;
);
continue;
}
let unique_qargs: Option<Qargs> = if qubit_set.is_empty() {
Expand All @@ -568,14 +570,14 @@ fn apply_translation(
if extra_inst_map.contains_key(&unique_qargs) {
replace_node(
py,
&mut out_dag,
&mut out_dag_concat,
node_obj.clone(),
&extra_inst_map[&unique_qargs],
)?;
} else if instr_map
.contains_key(&(node_obj.op.name().to_string(), node_obj.op.num_qubits()))
{
replace_node(py, &mut out_dag, node_obj.clone(), instr_map)?;
replace_node(py, &mut out_dag_concat, node_obj.clone(), instr_map)?;
} else {
return Err(TranspilerError::new_err(format!(
"BasisTranslator did not map {}",
Expand All @@ -584,13 +586,14 @@ fn apply_translation(
}
is_updated = true;
}

// Kill the concatenator
out_dag_concat.end();
Ok((out_dag, is_updated))
}

fn replace_node(
py: Python,
dag: &mut DAGCircuit,
dag: &mut DAGCircuitConcat,
node: PackedInstruction,
instr_map: &HashMap<GateIdentifier, (SmallVec<[Param; 3]>, DAGCircuit)>,
) -> PyResult<()> {
Expand Down Expand Up @@ -650,8 +653,8 @@ fn replace_node(
dag.apply_operation_back(
py,
new_op,
&new_qubits,
&new_clbits,
Some(new_qubits.into()),
Some(new_clbits.into()),
if new_params.is_empty() {
None
} else {
Expand All @@ -660,7 +663,7 @@ fn replace_node(
new_extra_props,
#[cfg(feature = "cache_pygates")]
None,
)?;
);
}
dag.add_global_phase(py, target_dag.global_phase())?;
} else {
Expand Down Expand Up @@ -754,8 +757,8 @@ fn replace_node(
dag.apply_operation_back(
py,
new_op,
&new_qubits,
&new_clbits,
Some(new_qubits.into()),
Some(new_clbits.into()),
if new_params.is_empty() {
None
} else {
Expand All @@ -764,7 +767,7 @@ fn replace_node(
inner_node.extra_attrs.clone(),
#[cfg(feature = "cache_pygates")]
None,
)?;
);
}

if let Param::ParameterExpression(old_phase) = target_dag.global_phase() {
Expand Down
65 changes: 45 additions & 20 deletions crates/accelerate/src/unitary_synthesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,31 @@ fn apply_synth_dag(
out_qargs: &[Qubit],
synth_dag: &DAGCircuit,
) -> PyResult<()> {
let mut out_dag_concat = out_dag.as_concat();
for out_node in synth_dag.topological_op_nodes()? {
let mut out_packed_instr = synth_dag.dag()[out_node].unwrap_operation().clone();
let out_packed_instr = synth_dag.dag()[out_node].unwrap_operation();
let synth_qargs = synth_dag.get_qargs(out_packed_instr.qubits);
let mapped_qargs: Vec<Qubit> = synth_qargs
.iter()
.map(|qarg| out_qargs[qarg.0 as usize])
.collect();
out_packed_instr.qubits = out_dag.qargs_interner.insert(&mapped_qargs);
out_dag.push_back(py, out_packed_instr)?;
out_dag_concat.apply_operation_back(
py,
out_packed_instr.op.clone(),
Some(mapped_qargs.into()),
Some(
synth_dag
.cargs_interner()
.get(out_packed_instr.clbits)
.into(),
),
out_packed_instr.params.clone().map(|param| *param),
out_packed_instr.extra_attrs.clone(),
#[cfg(feature = "cache_pygates")]
None,
);
}
out_dag_concat.end();
out_dag.add_global_phase(py, &synth_dag.get_global_phase())?;
Ok(())
}
Expand All @@ -131,29 +146,29 @@ fn apply_synth_sequence(
out_qargs: &[Qubit],
sequence: &TwoQubitUnitarySequence,
) -> PyResult<()> {
let mut instructions = Vec::with_capacity(sequence.gate_sequence.gates().len());
let mut concat_dag = out_dag.as_concat();
for (gate, params, qubit_ids) in sequence.gate_sequence.gates() {
let gate_node = match gate {
None => sequence.decomp_gate.operation.standard_gate(),
Some(gate) => *gate,
};
let mapped_qargs: Vec<Qubit> = qubit_ids.iter().map(|id| out_qargs[*id as usize]).collect();
let new_params: Option<Box<SmallVec<[Param; 3]>>> = match gate {
Some(_) => Some(Box::new(params.iter().map(|p| Param::Float(*p)).collect())),
None => Some(Box::new(sequence.decomp_gate.params.clone())),
let new_params: Option<SmallVec<[Param; 3]>> = match gate {
Some(_) => Some(params.iter().map(|p| Param::Float(*p)).collect()),
None => Some(sequence.decomp_gate.params.clone()),
};
let instruction = PackedInstruction {
op: PackedOperation::from_standard(gate_node),
qubits: out_dag.qargs_interner.insert(&mapped_qargs),
clbits: out_dag.cargs_interner.get_default(),
params: new_params,
extra_attrs: ExtraInstructionAttributes::default(),
concat_dag.apply_operation_back(
py,
PackedOperation::from_standard(gate_node),
Some(mapped_qargs.into()),
None,
new_params,
ExtraInstructionAttributes::default(),
#[cfg(feature = "cache_pygates")]
py_op: OnceLock::new(),
};
instructions.push(instruction);
None,
);
}
out_dag.extend(py, instructions.into_iter())?;
concat_dag.end();
out_dag.add_global_phase(py, &Param::Float(sequence.gate_sequence.global_phase()))?;
Ok(())
}
Expand Down Expand Up @@ -1060,17 +1075,27 @@ fn reversed_synth_su4_dag(

let mut target_dag = synth_dag.copy_empty_like(py, "alike")?;
let flip_bits: [Qubit; 2] = [Qubit(1), Qubit(0)];
let mut target_dag_concat = target_dag.as_concat();
for node in synth_dag.topological_op_nodes()? {
let mut inst = synth_dag.dag()[node].unwrap_operation().clone();
let inst = synth_dag.dag()[node].unwrap_operation();
let qubits: Vec<Qubit> = synth_dag
.qargs_interner()
.get(inst.qubits)
.iter()
.map(|x| flip_bits[x.0 as usize])
.collect();
inst.qubits = target_dag.qargs_interner.insert_owned(qubits);
target_dag.push_back(py, inst)?;
target_dag_concat.apply_operation_back(
py,
inst.op.clone(),
Some(qubits.into()),
Some(synth_dag.cargs_interner().get(inst.clbits).into()),
inst.params.clone().map(|param| *param),
inst.extra_attrs.clone(),
#[cfg(feature = "cache_pygates")]
None,
);
}
target_dag_concat.end();
Ok(target_dag)
}

Expand Down
Loading
Loading