Skip to content

Commit 3384877

Browse files
committed
WIP: Gates in rust
This compiles but has circular import errors because we need to use the standard gate classes in Python to map from python to rust. Fixes: Qiskit#12205
1 parent 95476b7 commit 3384877

13 files changed

+1109
-51
lines changed

Cargo.lock

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ license = "Apache-2.0"
1616
[workspace.dependencies]
1717
indexmap.version = "2.2.6"
1818
hashbrown.version = "0.14.0"
19+
num-complex = "0.4"
20+
ndarray = "^0.15.6"
21+
numpy = "0.21.0"
22+
smallvec = "1.13"
23+
1924
# Most of the crates don't need the feature `extension-module`, since only `qiskit-pyext` builds an
2025
# actual C extension (the feature disables linking in `libpython`, which is forbidden in Python
2126
# distributions). We only activate that feature when building the C extension module; we still need

crates/accelerate/Cargo.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@ doctest = false
1111

1212
[dependencies]
1313
rayon = "1.10"
14-
numpy = "0.21.0"
14+
numpy.workspace = true
1515
rand = "0.8"
1616
rand_pcg = "0.3"
1717
rand_distr = "0.4.3"
1818
ahash = "0.8.11"
1919
num-traits = "0.2"
20-
num-complex = "0.4"
20+
num-complex.workspace = true
2121
num-bigint = "0.4"
2222
rustworkx-core = "0.14"
2323
faer = "0.18.2"
2424
qiskit-circuit.workspace = true
2525

2626
[dependencies.smallvec]
27-
version = "1.13"
27+
workspace = true
2828
features = ["union"]
2929

3030
[dependencies.pyo3]
3131
workspace = true
3232
features = ["hashbrown", "indexmap", "num-complex", "num-bigint", "smallvec"]
3333

3434
[dependencies.ndarray]
35-
version = "^0.15.6"
35+
workspace = true
3636
features = ["rayon", "approx-0_5"]
3737

3838
[dependencies.approx]

crates/accelerate/src/sparse_pauli_op.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ impl ZXPaulis {
141141
phases: &Bound<PyArray1<u8>>,
142142
coeffs: &Bound<PyArray1<Complex64>>,
143143
) -> PyResult<Self> {
144-
let &[num_ops, num_qubits] = x.shape() else { unreachable!("PyArray2 must be 2D") };
144+
let &[num_ops, num_qubits] = x.shape() else {
145+
unreachable!("PyArray2 must be 2D")
146+
};
145147
if z.shape() != [num_ops, num_qubits] {
146148
return Err(PyValueError::new_err(format!(
147149
"'x' and 'z' have different shapes: {:?} and {:?}",

crates/circuit/Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,11 @@ doctest = false
1111

1212
[dependencies]
1313
hashbrown.workspace = true
14-
pyo3.workspace = true
14+
num-complex.workspace = true
15+
ndarray.workspace = true
16+
numpy.workspace = true
17+
smallvec.workspace = true
18+
19+
[dependencies.pyo3]
20+
workspace = true
21+
features = ["hashbrown", "indexmap", "num-complex", "num-bigint", "smallvec"]

crates/circuit/src/circuit_data.rs

+53-9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
use crate::circuit_instruction::CircuitInstruction;
1414
use crate::intern_context::{BitType, IndexType, InternContext};
1515
use crate::SliceOrInt;
16+
use smallvec::SmallVec;
17+
18+
use crate::operations::{OperationType, Param};
1619

1720
use hashbrown::HashMap;
1821
use pyo3::exceptions::{PyIndexError, PyKeyError, PyRuntimeError, PyValueError};
@@ -25,11 +28,15 @@ use std::hash::{Hash, Hasher};
2528
#[derive(Clone, Debug)]
2629
struct PackedInstruction {
2730
/// The Python-side operation instance.
28-
op: PyObject,
31+
op: OperationType,
2932
/// The index under which the interner has stored `qubits`.
3033
qubits_id: IndexType,
3134
/// The index under which the interner has stored `clbits`.
3235
clbits_id: IndexType,
36+
params: Option<SmallVec<[Param; 3]>>,
37+
label: Option<String>,
38+
duration: Option<PyObject>,
39+
unit: Option<String>,
3340
}
3441

3542
/// Private wrapper for Python-side Bit instances that implements
@@ -324,7 +331,7 @@ impl CircuitData {
324331
0,
325332
)?;
326333
res.intern_context = self.intern_context.clone();
327-
res.data = self.data.clone();
334+
res.data.clone_from(&self.data);
328335
Ok(res)
329336
}
330337

@@ -366,7 +373,15 @@ impl CircuitData {
366373
#[pyo3(signature = (func))]
367374
pub fn foreach_op(&self, py: Python<'_>, func: &Bound<PyAny>) -> PyResult<()> {
368375
for inst in self.data.iter() {
369-
func.call1((inst.op.bind(py),))?;
376+
match &inst.op {
377+
OperationType::Standard(op) => {
378+
let op = op.into_py(py);
379+
func.call1((op,))
380+
}
381+
OperationType::Instruction(op) => func.call1((op.instruction.clone_ref(py),)),
382+
OperationType::Gate(op) => func.call1((op.gate.clone_ref(py),)),
383+
OperationType::Operation(op) => func.call1((op.operation.clone_ref(py),)),
384+
}?;
370385
}
371386
Ok(())
372387
}
@@ -380,7 +395,15 @@ impl CircuitData {
380395
#[pyo3(signature = (func))]
381396
pub fn foreach_op_indexed(&self, py: Python<'_>, func: &Bound<PyAny>) -> PyResult<()> {
382397
for (index, inst) in self.data.iter().enumerate() {
383-
func.call1((index, inst.op.bind(py)))?;
398+
match &inst.op {
399+
OperationType::Standard(op) => {
400+
let op = op.into_py(py);
401+
func.call1((index, op))
402+
}
403+
OperationType::Instruction(op) => func.call1((index, op.instruction.clone_ref(py))),
404+
OperationType::Gate(op) => func.call1((index, op.gate.clone_ref(py))),
405+
OperationType::Operation(op) => func.call1((index, op.operation.clone_ref(py))),
406+
}?;
384407
}
385408
Ok(())
386409
}
@@ -395,7 +418,16 @@ impl CircuitData {
395418
#[pyo3(signature = (func))]
396419
pub fn map_ops(&mut self, py: Python<'_>, func: &Bound<PyAny>) -> PyResult<()> {
397420
for inst in self.data.iter_mut() {
398-
inst.op = func.call1((inst.op.bind(py),))?.into_py(py);
421+
inst.op = match &inst.op {
422+
OperationType::Standard(op) => {
423+
let op = op.into_py(py);
424+
func.call1((op,))
425+
}
426+
OperationType::Instruction(op) => func.call1((op.instruction.clone_ref(py),)),
427+
OperationType::Gate(op) => func.call1((op.gate.clone_ref(py),)),
428+
OperationType::Operation(op) => func.call1((op.operation.clone_ref(py),)),
429+
}?
430+
.extract()?;
399431
}
400432
Ok(())
401433
}
@@ -666,9 +698,13 @@ impl CircuitData {
666698
.collect::<PyResult<Vec<BitType>>>()?;
667699

668700
self.data.push(PackedInstruction {
669-
op: inst.op.clone_ref(py),
701+
op: inst.op.clone(),
670702
qubits_id: self.intern_context.intern(qubits)?,
671703
clbits_id: self.intern_context.intern(clbits)?,
704+
params: inst.params.clone(),
705+
label: inst.label.clone(),
706+
duration: inst.duration.clone(),
707+
unit: inst.unit.clone(),
672708
});
673709
}
674710
return Ok(());
@@ -720,7 +756,7 @@ impl CircuitData {
720756

721757
fn __traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {
722758
for packed in self.data.iter() {
723-
visit.call(&packed.op)?;
759+
visit.call(&packed.duration)?;
724760
}
725761
for bit in self.qubits_native.iter().chain(self.clbits_native.iter()) {
726762
visit.call(bit)?;
@@ -820,17 +856,21 @@ impl CircuitData {
820856
self.intern_context.intern(args)
821857
};
822858
Ok(PackedInstruction {
823-
op: inst.operation.clone_ref(py),
859+
op: inst.operation.clone(),
824860
qubits_id: interned_bits(&self.qubit_indices_native, inst.qubits.bind(py))?,
825861
clbits_id: interned_bits(&self.clbit_indices_native, inst.clbits.bind(py))?,
862+
params: inst.params.clone(),
863+
label: inst.label.clone(),
864+
duration: inst.duration.clone(),
865+
unit: inst.unit.clone(),
826866
})
827867
}
828868

829869
fn unpack(&self, py: Python<'_>, inst: &PackedInstruction) -> PyResult<Py<CircuitInstruction>> {
830870
Py::new(
831871
py,
832872
CircuitInstruction {
833-
operation: inst.op.clone_ref(py),
873+
operation: inst.op.clone(),
834874
qubits: PyTuple::new_bound(
835875
py,
836876
self.intern_context
@@ -849,6 +889,10 @@ impl CircuitData {
849889
.collect::<Vec<_>>(),
850890
)
851891
.unbind(),
892+
params: inst.params.clone(),
893+
label: inst.label.clone(),
894+
duration: inst.duration.clone(),
895+
unit: inst.unit.clone(),
852896
},
853897
)
854898
}

0 commit comments

Comments
 (0)