Skip to content

Commit

Permalink
Move serialization to Rust.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhartman committed Oct 2, 2023
1 parent 376c8f6 commit fe6eaf7
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 14 deletions.
34 changes: 33 additions & 1 deletion crates/accelerate/src/quantum_circuit/circuit_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::iter::zip;
use std::mem::swap;

// Private type use to store instructions with interned arg lists.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, FromPyObject)]
struct InternedInstruction(Option<PyObject>, IndexType, IndexType);

#[pyclass(sequence, module = "qiskit._accelerate.quantum_circuit")]
Expand Down Expand Up @@ -268,6 +268,38 @@ impl CircuitData {
}
self.new_callable = None;
}

fn __getstate__(&self, py: Python<'_>) -> PyObject {
(
PyList::new(py, self.data.iter().map(|i| (i.0.as_ref().unwrap(), i.1, i.2))),
self.intern_context.clone(),
self.new_callable.as_ref().unwrap().clone(),
self.qubits.clone(),
self.clbits.clone(),
self.qubit_indices.clone(),
self.clbit_indices.clone()
).into_py(py)
}

fn __setstate__(&mut self, _py:Python<'_>, state: &PyTuple) -> PyResult<()> {
self.data = state.get_item(0)?.extract()?;
self.intern_context = state.get_item(1)?.extract()?;
self.new_callable = Some(state.get_item(2)?.extract()?);
self.qubits = state.get_item(3)?.extract()?;
self.clbits = state.get_item(4)?.extract()?;
self.qubit_indices = state.get_item(5)?.extract()?;
self.clbit_indices = state.get_item(6)?.extract()?;
Ok(())
}

pub fn __getnewargs__(&self, py: Python<'_>) -> PyResult<PyObject> {
Ok((self.intern_context.clone(),
self.new_callable.as_ref().unwrap().clone(),
self.qubits.clone(),
self.clbits.clone(),
self.qubit_indices.clone(),
self.clbit_indices.clone()).into_py(py))
}
}

enum IndexFor {
Expand Down
27 changes: 27 additions & 0 deletions crates/accelerate/src/quantum_circuit/intern_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use pyo3::prelude::*;
use std::collections::VecDeque;
use std::mem::take;
use std::sync::Arc;
use pyo3::types::{PyList, PyTuple};

pub type IndexType = u32;
pub type BitType = u32;
Expand Down Expand Up @@ -112,6 +113,32 @@ impl InternContext {
str.push_str(&*format!(" {:?}", self.free_slots));
str.into_py(py)
}

fn __getstate__(&self, py: Python<'_>) -> PyObject {
(
PyList::new(py, self.slots.iter().map(|o| o.as_ref().map(|s| {
(PyList::new(py, s.operands.as_ref().iter()), s.use_count)
}))),
PyList::new(py, self.free_slots.iter())
).into_py(py)
}

fn __setstate__(&mut self, state: &PyTuple) -> PyResult<()> {
for (idx, slot) in state.get_item(0)?.iter()?.enumerate() {
let slot: Option<(Vec<BitType>, usize)> = slot?.extract()?;
self.slots.push(slot.map(|(ops, use_count)| {
let operands = Arc::new(ops);
self.slot_lookup.insert(operands.clone(), idx.try_into().unwrap());
SharedOperandList {
operands,
use_count
}
}));
}
self.free_slots = state.get_item(1)?.iter()?.map(|i| i?.extract()).collect::<PyResult<VecDeque<IndexType>>>()?;

Ok(())
}
}

impl Default for InternContext {
Expand Down
13 changes: 0 additions & 13 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,19 +522,6 @@ def __eq__(self, other) -> bool:
other, copy_operations=False
)

def __getstate__(self):
# Rust's CircuitData is not picklable, so we convert it to a list first.
state = self.__dict__.copy()
state["_data"] = list(self._data)
del state["_intern_context"]
return state

def __setstate__(self, state):
self.__dict__ = state
self._intern_context = InternContext()
data = self._new_data(self._data)
self._data = data

@classmethod
def _increment_instances(cls):
cls.instances += 1
Expand Down

0 comments on commit fe6eaf7

Please sign in to comment.