Skip to content

Commit 69d6533

Browse files
committed
Merge branch 'main' into check-gate-direction
Also changing functions order in gate_direction.rs and adding Returns: doc
2 parents 0b9c0d2 + 7b2d50c commit 69d6533

File tree

5 files changed

+304
-233
lines changed

5 files changed

+304
-233
lines changed

crates/accelerate/src/gate_direction.rs

+60-54
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,66 @@ use qiskit_circuit::{
2424
Qubit,
2525
};
2626

27+
/// Check if the two-qubit gates follow the right direction with respect to the coupling map.
28+
///
29+
/// Args:
30+
/// dag: the DAGCircuit to analyze
31+
///
32+
/// coupling_edges: set of edge pairs representing a directed coupling map, against which gate directionality is checked
33+
///
34+
/// Returns:
35+
/// true iff all two-qubit gates comply with the coupling constraints
36+
#[pyfunction]
37+
#[pyo3(name = "check_gate_direction_coupling")]
38+
fn py_check_with_coupling_map(
39+
py: Python,
40+
dag: &DAGCircuit,
41+
coupling_edges: &Bound<PySet>,
42+
) -> PyResult<bool> {
43+
let coupling_map_check =
44+
|curr_dag: &DAGCircuit, _: &PackedInstruction, op_args: &[Qubit]| -> bool {
45+
coupling_edges
46+
.contains((
47+
map_qubit(py, dag, curr_dag, op_args[0]).0,
48+
map_qubit(py, dag, curr_dag, op_args[1]).0,
49+
))
50+
.unwrap_or(false)
51+
};
52+
53+
check_gate_direction(py, dag, &coupling_map_check)
54+
}
55+
56+
/// Check if the two-qubit gates follow the right direction with respect to instructions supported in the given target.
57+
///
58+
/// Args:
59+
/// dag: the DAGCircuit to analyze
60+
///
61+
/// target: the Target against which gate directionality compliance is checked
62+
///
63+
/// Returns:
64+
/// true iff all two-qubit gates comply with the target's coupling constraints
65+
#[pyfunction]
66+
#[pyo3(name = "check_gate_direction_target")]
67+
fn py_check_with_target(py: Python, dag: &DAGCircuit, target: &Bound<Target>) -> PyResult<bool> {
68+
let target = target.borrow();
69+
70+
let target_check =
71+
|curr_dag: &DAGCircuit, inst: &PackedInstruction, op_args: &[Qubit]| -> bool {
72+
let mut qargs = Qargs::new();
73+
74+
qargs.push(PhysicalQubit::new(
75+
map_qubit(py, dag, curr_dag, op_args[0]).0,
76+
));
77+
qargs.push(PhysicalQubit::new(
78+
map_qubit(py, dag, curr_dag, op_args[1]).0,
79+
));
80+
81+
target.instruction_supported(inst.op.name(), Some(&qargs))
82+
};
83+
84+
check_gate_direction(py, dag, &target_check)
85+
}
86+
2787
// Handle a control flow instruction, namely check recursively into its circuit blocks
2888
fn check_gate_direction_control_flow<T>(
2989
py: Python,
@@ -91,60 +151,6 @@ fn map_qubit(py: Python, orig_dag: &DAGCircuit, curr_dag: &DAGCircuit, qubit: Qu
91151
orig_dag.qubits.find(qubit).expect("Qubit in orig_dag")
92152
}
93153

94-
/// Check if the two-qubit gates follow the right direction with respect to the coupling map.
95-
///
96-
/// Args:
97-
/// dag: the DAGCircuit to analyze
98-
///
99-
/// coupling_edges: set of edge pairs representing a directed coupling map, against which gate directionality is checked
100-
#[pyfunction]
101-
#[pyo3(name = "check_gate_direction_coupling")]
102-
fn py_check_with_coupling_map(
103-
py: Python,
104-
dag: &DAGCircuit,
105-
coupling_edges: &Bound<PySet>,
106-
) -> PyResult<bool> {
107-
let coupling_map_check =
108-
|curr_dag: &DAGCircuit, _: &PackedInstruction, op_args: &[Qubit]| -> bool {
109-
coupling_edges
110-
.contains((
111-
map_qubit(py, dag, curr_dag, op_args[0]).0,
112-
map_qubit(py, dag, curr_dag, op_args[1]).0,
113-
))
114-
.unwrap_or(false)
115-
};
116-
117-
check_gate_direction(py, dag, &coupling_map_check)
118-
}
119-
120-
/// Check if the two-qubit gates follow the right direction with respect to instructions supported in the given target.
121-
///
122-
/// Args:
123-
/// dag: the DAGCircuit to analyze
124-
///
125-
/// target: the Target against which gate directionality compliance is checked
126-
#[pyfunction]
127-
#[pyo3(name = "check_gate_direction_target")]
128-
fn py_check_with_target(py: Python, dag: &DAGCircuit, target: &Bound<Target>) -> PyResult<bool> {
129-
let target = target.borrow();
130-
131-
let target_check =
132-
|curr_dag: &DAGCircuit, inst: &PackedInstruction, op_args: &[Qubit]| -> bool {
133-
let mut qargs = Qargs::new();
134-
135-
qargs.push(PhysicalQubit::new(
136-
map_qubit(py, dag, curr_dag, op_args[0]).0,
137-
));
138-
qargs.push(PhysicalQubit::new(
139-
map_qubit(py, dag, curr_dag, op_args[1]).0,
140-
));
141-
142-
target.instruction_supported(inst.op.name(), Some(&qargs))
143-
};
144-
145-
check_gate_direction(py, dag, &target_check)
146-
}
147-
148154
#[pymodule]
149155
pub fn gate_direction(m: &Bound<PyModule>) -> PyResult<()> {
150156
m.add_wrapped(wrap_pyfunction!(py_check_with_coupling_map))?;

crates/circuit/src/circuit_data.rs

+34-36
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::cell::OnceCell;
1616
use crate::bit_data::BitData;
1717
use crate::circuit_instruction::{CircuitInstruction, OperationFromPython};
1818
use crate::imports::{ANNOTATED_OPERATION, CLBIT, QUANTUM_CIRCUIT, QUBIT};
19-
use crate::interner::{Index, IndexedInterner, Interner};
19+
use crate::interner::{Interned, Interner};
2020
use crate::operations::{Operation, OperationRef, Param, StandardGate};
2121
use crate::packed_instruction::{PackedInstruction, PackedOperation};
2222
use crate::parameter_table::{ParameterTable, ParameterTableError, ParameterUse, ParameterUuid};
@@ -91,9 +91,9 @@ pub struct CircuitData {
9191
/// The packed instruction listing.
9292
data: Vec<PackedInstruction>,
9393
/// The cache used to intern instruction bits.
94-
qargs_interner: IndexedInterner<Vec<Qubit>>,
94+
qargs_interner: Interner<[Qubit]>,
9595
/// The cache used to intern instruction bits.
96-
cargs_interner: IndexedInterner<Vec<Clbit>>,
96+
cargs_interner: Interner<[Clbit]>,
9797
/// Qubits registered in the circuit.
9898
qubits: BitData<Qubit>,
9999
/// Clbits registered in the circuit.
@@ -148,8 +148,8 @@ impl CircuitData {
148148
global_phase,
149149
)?;
150150
for (operation, params, qargs, cargs) in instruction_iter {
151-
let qubits = (&mut res.qargs_interner).intern(qargs)?;
152-
let clbits = (&mut res.cargs_interner).intern(cargs)?;
151+
let qubits = res.qargs_interner.insert_owned(qargs);
152+
let clbits = res.cargs_interner.insert_owned(cargs);
153153
let params = (!params.is_empty()).then(|| Box::new(params));
154154
res.data.push(PackedInstruction {
155155
op: operation,
@@ -199,9 +199,9 @@ impl CircuitData {
199199
instruction_iter.size_hint().0,
200200
global_phase,
201201
)?;
202-
let no_clbit_index = (&mut res.cargs_interner).intern(Vec::new())?;
202+
let no_clbit_index = res.cargs_interner.insert(&[]);
203203
for (operation, params, qargs) in instruction_iter {
204-
let qubits = (&mut res.qargs_interner).intern(qargs.to_vec())?;
204+
let qubits = res.qargs_interner.insert(&qargs);
205205
let params = (!params.is_empty()).then(|| Box::new(params));
206206
res.data.push(PackedInstruction {
207207
op: operation.into(),
@@ -227,8 +227,8 @@ impl CircuitData {
227227
) -> PyResult<Self> {
228228
let mut res = CircuitData {
229229
data: Vec::with_capacity(instruction_capacity),
230-
qargs_interner: IndexedInterner::new(),
231-
cargs_interner: IndexedInterner::new(),
230+
qargs_interner: Interner::new(),
231+
cargs_interner: Interner::new(),
232232
qubits: BitData::new(py, "qubits".to_string()),
233233
clbits: BitData::new(py, "clbits".to_string()),
234234
param_table: ParameterTable::new(),
@@ -258,9 +258,9 @@ impl CircuitData {
258258
params: &[Param],
259259
qargs: &[Qubit],
260260
) -> PyResult<()> {
261-
let no_clbit_index = (&mut self.cargs_interner).intern(Vec::new())?;
261+
let no_clbit_index = self.cargs_interner.insert(&[]);
262262
let params = (!params.is_empty()).then(|| Box::new(params.iter().cloned().collect()));
263-
let qubits = (&mut self.qargs_interner).intern(qargs.to_vec())?;
263+
let qubits = self.qargs_interner.insert(qargs);
264264
self.data.push(PackedInstruction {
265265
op: operation.into(),
266266
qubits,
@@ -351,8 +351,8 @@ impl CircuitData {
351351
) -> PyResult<Self> {
352352
let mut self_ = CircuitData {
353353
data: Vec::new(),
354-
qargs_interner: IndexedInterner::new(),
355-
cargs_interner: IndexedInterner::new(),
354+
qargs_interner: Interner::new(),
355+
cargs_interner: Interner::new(),
356356
qubits: BitData::new(py, "qubits".to_string()),
357357
clbits: BitData::new(py, "clbits".to_string()),
358358
param_table: ParameterTable::new(),
@@ -572,10 +572,10 @@ impl CircuitData {
572572
let qubits = PySet::empty_bound(py)?;
573573
let clbits = PySet::empty_bound(py)?;
574574
for inst in self.data.iter() {
575-
for b in self.qargs_interner.intern(inst.qubits) {
575+
for b in self.qargs_interner.get(inst.qubits) {
576576
qubits.add(self.qubits.get(*b).unwrap().clone_ref(py))?;
577577
}
578-
for b in self.cargs_interner.intern(inst.clbits) {
578+
for b in self.cargs_interner.get(inst.clbits) {
579579
clbits.add(self.clbits.get(*b).unwrap().clone_ref(py))?;
580580
}
581581
}
@@ -737,8 +737,8 @@ impl CircuitData {
737737
// Get a single item, assuming the index is validated as in bounds.
738738
let get_single = |index: usize| {
739739
let inst = &self.data[index];
740-
let qubits = self.qargs_interner.intern(inst.qubits);
741-
let clbits = self.cargs_interner.intern(inst.clbits);
740+
let qubits = self.qargs_interner.get(inst.qubits);
741+
let clbits = self.cargs_interner.get(inst.clbits);
742742
CircuitInstruction {
743743
operation: inst.op.clone(),
744744
qubits: PyTuple::new_bound(py, self.qubits.map_indices(qubits)).unbind(),
@@ -894,7 +894,7 @@ impl CircuitData {
894894
for inst in other.data.iter() {
895895
let qubits = other
896896
.qargs_interner
897-
.intern(inst.qubits)
897+
.get(inst.qubits)
898898
.iter()
899899
.map(|b| {
900900
Ok(self
@@ -905,7 +905,7 @@ impl CircuitData {
905905
.collect::<PyResult<Vec<Qubit>>>()?;
906906
let clbits = other
907907
.cargs_interner
908-
.intern(inst.clbits)
908+
.get(inst.clbits)
909909
.iter()
910910
.map(|b| {
911911
Ok(self
@@ -915,8 +915,8 @@ impl CircuitData {
915915
})
916916
.collect::<PyResult<Vec<Clbit>>>()?;
917917
let new_index = self.data.len();
918-
let qubits_id = Interner::intern(&mut self.qargs_interner, qubits)?;
919-
let clbits_id = Interner::intern(&mut self.cargs_interner, clbits)?;
918+
let qubits_id = self.qargs_interner.insert_owned(qubits);
919+
let clbits_id = self.cargs_interner.insert_owned(clbits);
920920
self.data.push(PackedInstruction {
921921
op: inst.op.clone(),
922922
qubits: qubits_id,
@@ -1113,14 +1113,12 @@ impl CircuitData {
11131113
}
11141114

11151115
fn pack(&mut self, py: Python, inst: &CircuitInstruction) -> PyResult<PackedInstruction> {
1116-
let qubits = Interner::intern(
1117-
&mut self.qargs_interner,
1118-
self.qubits.map_bits(inst.qubits.bind(py))?.collect(),
1119-
)?;
1120-
let clbits = Interner::intern(
1121-
&mut self.cargs_interner,
1122-
self.clbits.map_bits(inst.clbits.bind(py))?.collect(),
1123-
)?;
1116+
let qubits = self
1117+
.qargs_interner
1118+
.insert_owned(self.qubits.map_bits(inst.qubits.bind(py))?.collect());
1119+
let clbits = self
1120+
.cargs_interner
1121+
.insert_owned(self.clbits.map_bits(inst.clbits.bind(py))?.collect());
11241122
Ok(PackedInstruction {
11251123
op: inst.operation.clone(),
11261124
qubits,
@@ -1138,12 +1136,12 @@ impl CircuitData {
11381136
}
11391137

11401138
/// Returns an immutable view of the Interner used for Qargs
1141-
pub fn qargs_interner(&self) -> &IndexedInterner<Vec<Qubit>> {
1139+
pub fn qargs_interner(&self) -> &Interner<[Qubit]> {
11421140
&self.qargs_interner
11431141
}
11441142

11451143
/// Returns an immutable view of the Interner used for Cargs
1146-
pub fn cargs_interner(&self) -> &IndexedInterner<Vec<Clbit>> {
1144+
pub fn cargs_interner(&self) -> &Interner<[Clbit]> {
11471145
&self.cargs_interner
11481146
}
11491147

@@ -1162,14 +1160,14 @@ impl CircuitData {
11621160
&self.clbits
11631161
}
11641162

1165-
/// Unpacks from InternerIndex to `[Qubit]`
1166-
pub fn get_qargs(&self, index: Index) -> &[Qubit] {
1167-
self.qargs_interner().intern(index)
1163+
/// Unpacks from interned value to `[Qubit]`
1164+
pub fn get_qargs(&self, index: Interned<[Qubit]>) -> &[Qubit] {
1165+
self.qargs_interner().get(index)
11681166
}
11691167

11701168
/// Unpacks from InternerIndex to `[Clbit]`
1171-
pub fn get_cargs(&self, index: Index) -> &[Clbit] {
1172-
self.cargs_interner().intern(index)
1169+
pub fn get_cargs(&self, index: Interned<[Clbit]>) -> &[Clbit] {
1170+
self.cargs_interner().get(index)
11731171
}
11741172

11751173
fn assign_parameters_inner<I>(&mut self, py: Python, iter: I) -> PyResult<()>

0 commit comments

Comments
 (0)