Skip to content

Commit

Permalink
feat: Initialize Instructions from a Quil string. Python `Instructi…
Browse files Browse the repository at this point in the history
…on`s support the `pickle` module. (#382)

* feat: Instruction types are compatible with the `pickle` module.

* refactor, removing public parser method, and raising errors when there is leftover input, or if the parsed instruction count is not exactly 1

* apply macro to remainder of instructions

* add missing type hint

* fix arg name

* clean up docstring
  • Loading branch information
MarquessV authored Jul 26, 2024
1 parent 66393c5 commit e500db8
Show file tree
Hide file tree
Showing 18 changed files with 163 additions and 20 deletions.
6 changes: 6 additions & 0 deletions quil-py/quil/instructions/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ class Instruction:
def is_quil_t(self) -> bool:
"""Returns ``True`` if the instruction is a Quil-T instruction, ``False`` otherwise."""
...
@staticmethod
def parse(string: str) -> Instruction:
"""Parses a Quil ``Instruction`` from a string.
Raises an error if there is leftover input after parsing, or if there wasn't exactly 1 instruction.
"""
def inner(
self,
) -> Union[
Expand Down
4 changes: 3 additions & 1 deletion quil-py/src/instruction/calibration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rigetti_pyo3::{

use crate::{
expression::PyExpression,
impl_copy_for_instruction, impl_eq, impl_to_quil,
impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil,
instruction::{PyGateModifier, PyInstruction, PyQubit},
validation::identifier::RustIdentifierValidationError,
};
Expand All @@ -31,6 +31,7 @@ impl_repr!(PyCalibration);
impl_to_quil!(PyCalibration);
impl_copy_for_instruction!(PyCalibration);
impl_eq!(PyCalibration);
impl_pickle_for_instruction!(PyCalibration);

#[pymethods]
impl PyCalibration {
Expand Down Expand Up @@ -70,6 +71,7 @@ impl_repr!(PyMeasureCalibrationDefinition);
impl_to_quil!(PyMeasureCalibrationDefinition);
impl_copy_for_instruction!(PyMeasureCalibrationDefinition);
impl_eq!(PyMeasureCalibrationDefinition);
impl_pickle_for_instruction!(PyMeasureCalibrationDefinition);

#[pymethods]
impl PyMeasureCalibrationDefinition {
Expand Down
3 changes: 2 additions & 1 deletion quil-py/src/instruction/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rigetti_pyo3::{
};

use super::PyInstruction;
use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
use crate::{impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil};

py_wrap_data_struct! {
#[derive(Debug, PartialEq)]
Expand All @@ -23,6 +23,7 @@ impl_repr!(PyCircuitDefinition);
impl_to_quil!(PyCircuitDefinition);
impl_copy_for_instruction!(PyCircuitDefinition);
impl_eq!(PyCircuitDefinition);
impl_pickle_for_instruction!(PyCircuitDefinition);

#[pymethods]
impl PyCircuitDefinition {
Expand Down
9 changes: 8 additions & 1 deletion quil-py/src/instruction/classical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rigetti_pyo3::{
};

use super::PyMemoryReference;
use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
use crate::{impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil};

py_wrap_data_struct! {
#[derive(Debug, PartialEq)]
Expand All @@ -31,6 +31,7 @@ impl_to_quil!(PyArithmetic);
impl_copy_for_instruction!(PyArithmetic);
impl_hash!(PyArithmetic);
impl_eq!(PyArithmetic);
impl_pickle_for_instruction!(PyArithmetic);

#[pymethods]
impl PyArithmetic {
Expand Down Expand Up @@ -115,6 +116,7 @@ impl_repr!(PyBinaryLogic);
impl_to_quil!(PyBinaryLogic);
impl_copy_for_instruction!(PyBinaryLogic);
impl_eq!(PyBinaryLogic);
impl_pickle_for_instruction!(PyBinaryLogic);

#[pymethods]
impl PyBinaryLogic {
Expand Down Expand Up @@ -146,6 +148,7 @@ impl_to_quil!(PyConvert);
impl_copy_for_instruction!(PyConvert);
impl_hash!(PyConvert);
impl_eq!(PyConvert);
impl_pickle_for_instruction!(PyConvert);

#[pymethods]
impl PyConvert {
Expand Down Expand Up @@ -175,6 +178,7 @@ impl_to_quil!(PyMove);
impl_copy_for_instruction!(PyMove);
impl_hash!(PyMove);
impl_eq!(PyMove);
impl_pickle_for_instruction!(PyMove);

#[pymethods]
impl PyMove {
Expand Down Expand Up @@ -204,6 +208,7 @@ impl_to_quil!(PyExchange);
impl_copy_for_instruction!(PyExchange);
impl_hash!(PyExchange);
impl_eq!(PyExchange);
impl_pickle_for_instruction!(PyExchange);

#[pymethods]
impl PyExchange {
Expand Down Expand Up @@ -259,6 +264,7 @@ impl_to_quil!(PyComparison);
impl_copy_for_instruction!(PyComparison);
impl_hash!(PyComparison);
impl_eq!(PyComparison);
impl_pickle_for_instruction!(PyComparison);

#[pymethods]
impl PyComparison {
Expand Down Expand Up @@ -303,6 +309,7 @@ impl_to_quil!(PyUnaryLogic);
impl_copy_for_instruction!(PyUnaryLogic);
impl_hash!(PyUnaryLogic);
impl_eq!(PyUnaryLogic);
impl_pickle_for_instruction!(PyUnaryLogic);

#[pymethods]
impl PyUnaryLogic {
Expand Down
6 changes: 5 additions & 1 deletion quil-py/src/instruction/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rigetti_pyo3::{
PyWrapper,
};

use crate::{impl_eq, impl_to_quil, instruction::PyMemoryReference};
use crate::{impl_eq, impl_pickle_for_instruction, impl_to_quil, instruction::PyMemoryReference};

/// Implements __copy__ and __deepcopy__ for instructions containing a [`Target`].
///
Expand Down Expand Up @@ -51,6 +51,7 @@ impl_hash!(PyLabel);
impl_to_quil!(PyLabel);
impl_copy_for_target_containing_instructions!(PyLabel);
impl_eq!(PyLabel);
impl_pickle_for_instruction!(PyLabel);

#[pymethods]
impl PyLabel {
Expand Down Expand Up @@ -105,6 +106,7 @@ impl_repr!(PyJump);
impl_to_quil!(PyJump);
impl_copy_for_target_containing_instructions!(PyJump);
impl_eq!(PyJump);
impl_pickle_for_instruction!(PyJump);

#[pymethods]
impl PyJump {
Expand All @@ -126,6 +128,7 @@ impl_repr!(PyJumpWhen);
impl_to_quil!(PyJumpWhen);
impl_copy_for_target_containing_instructions!(PyJumpWhen);
impl_eq!(PyJumpWhen);
impl_pickle_for_instruction!(PyJumpWhen);

#[pymethods]
impl PyJumpWhen {
Expand All @@ -147,6 +150,7 @@ impl_repr!(PyJumpUnless);
impl_to_quil!(PyJumpUnless);
impl_copy_for_target_containing_instructions!(PyJumpUnless);
impl_eq!(PyJumpUnless);
impl_pickle_for_instruction!(PyJumpUnless);

#[pymethods]
impl PyJumpUnless {
Expand Down
5 changes: 4 additions & 1 deletion quil-py/src/instruction/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use quil_rs::instruction::{
};

use super::PyArithmeticOperand;
use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
use crate::{impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil};

use rigetti_pyo3::{
impl_from_str, impl_hash, impl_parse, impl_repr, py_wrap_data_struct, py_wrap_error,
Expand Down Expand Up @@ -123,6 +123,7 @@ impl_to_quil!(PyDeclaration);
impl_copy_for_instruction!(PyDeclaration);
impl_hash!(PyDeclaration);
impl_eq!(PyDeclaration);
impl_pickle_for_instruction!(PyDeclaration);

#[pymethods]
impl PyDeclaration {
Expand Down Expand Up @@ -178,6 +179,7 @@ impl_to_quil!(PyLoad);
impl_copy_for_instruction!(PyLoad);
impl_hash!(PyLoad);
impl_eq!(PyLoad);
impl_pickle_for_instruction!(PyLoad);

#[pymethods]
impl PyLoad {
Expand Down Expand Up @@ -210,6 +212,7 @@ impl_to_quil!(PyStore);
impl_copy_for_instruction!(PyStore);
impl_hash!(PyStore);
impl_eq!(PyStore);
impl_pickle_for_instruction!(PyStore);

#[pymethods]
impl PyStore {
Expand Down
17 changes: 14 additions & 3 deletions quil-py/src/instruction/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ use rigetti_pyo3::{
use super::PyQubit;
use crate::{
expression::PyExpression,
impl_copy_for_instruction, impl_eq, impl_to_quil,
impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil,
instruction::{PyMemoryReference, PyWaveformInvocation},
};

py_wrap_union_enum! {
#[derive(Debug, PartialEq, Eq)]
#[pyo3(module = "quil.instructions")]
PyAttributeValue(AttributeValue) as "AttributeValue" {
string: String => Py<PyString>,
expression: Expression => PyExpression
Expand All @@ -43,7 +44,7 @@ pub type PyFrameAttributes = IndexMap<String, PyAttributeValue>;

py_wrap_data_struct! {
#[derive(Debug, PartialEq, Eq)]
#[pyo3(subclass)]
#[pyo3(subclass, module = "quil.instructions")]
PyFrameDefinition(FrameDefinition) as "FrameDefinition" {
identifier: FrameIdentifier => PyFrameIdentifier,
attributes: FrameAttributes => PyFrameAttributes
Expand All @@ -53,6 +54,7 @@ impl_repr!(PyFrameDefinition);
impl_to_quil!(PyFrameDefinition);
impl_copy_for_instruction!(PyFrameDefinition);
impl_eq!(PyFrameDefinition);
impl_pickle_for_instruction!(PyFrameDefinition);

#[pymethods]
impl PyFrameDefinition {
Expand All @@ -71,7 +73,7 @@ impl PyFrameDefinition {

py_wrap_data_struct! {
#[derive(Debug, PartialEq, Eq, Hash)]
#[pyo3(subclass)]
#[pyo3(subclass, module = "quil.instructions")]
PyFrameIdentifier(FrameIdentifier) as "FrameIdentifier" {
name: String => Py<PyString>,
qubits: Vec<Qubit> => Vec<PyQubit>
Expand Down Expand Up @@ -107,6 +109,7 @@ impl_repr!(PyCapture);
impl_to_quil!(PyCapture);
impl_copy_for_instruction!(PyCapture);
impl_eq!(PyCapture);
impl_pickle_for_instruction!(PyCapture);

#[pymethods]
impl PyCapture {
Expand Down Expand Up @@ -140,6 +143,7 @@ impl_repr!(PyPulse);
impl_to_quil!(PyPulse);
impl_copy_for_instruction!(PyPulse);
impl_eq!(PyPulse);
impl_pickle_for_instruction!(PyPulse);

#[pymethods]
impl PyPulse {
Expand Down Expand Up @@ -174,6 +178,7 @@ impl_to_quil!(PyRawCapture);
impl_copy_for_instruction!(PyRawCapture);
impl_hash!(PyRawCapture);
impl_eq!(PyRawCapture);
impl_pickle_for_instruction!(PyRawCapture);

#[pymethods]
impl PyRawCapture {
Expand Down Expand Up @@ -207,6 +212,7 @@ impl_to_quil!(PySetFrequency);
impl_copy_for_instruction!(PySetFrequency);
impl_hash!(PySetFrequency);
impl_eq!(PySetFrequency);
impl_pickle_for_instruction!(PySetFrequency);

#[pymethods]
impl PySetFrequency {
Expand Down Expand Up @@ -236,6 +242,7 @@ impl_to_quil!(PySetPhase);
impl_copy_for_instruction!(PySetPhase);
impl_hash!(PySetPhase);
impl_eq!(PySetPhase);
impl_pickle_for_instruction!(PySetPhase);

#[pymethods]
impl PySetPhase {
Expand All @@ -261,6 +268,7 @@ impl_to_quil!(PySetScale);
impl_copy_for_instruction!(PySetScale);
impl_hash!(PySetScale);
impl_eq!(PySetScale);
impl_pickle_for_instruction!(PySetScale);

#[pymethods]
impl PySetScale {
Expand All @@ -286,6 +294,7 @@ impl_to_quil!(PyShiftFrequency);
impl_copy_for_instruction!(PyShiftFrequency);
impl_hash!(PyShiftFrequency);
impl_eq!(PyShiftFrequency);
impl_pickle_for_instruction!(PyShiftFrequency);

#[pymethods]
impl PyShiftFrequency {
Expand Down Expand Up @@ -315,6 +324,7 @@ impl_to_quil!(PyShiftPhase);
impl_copy_for_instruction!(PyShiftPhase);
impl_hash!(PyShiftPhase);
impl_eq!(PyShiftPhase);
impl_pickle_for_instruction!(PyShiftPhase);

#[pymethods]
impl PyShiftPhase {
Expand All @@ -340,6 +350,7 @@ impl_to_quil!(PySwapPhases);
impl_copy_for_instruction!(PySwapPhases);
impl_hash!(PySwapPhases);
impl_eq!(PySwapPhases);
impl_pickle_for_instruction!(PySwapPhases);

#[pymethods]
impl PySwapPhases {
Expand Down
6 changes: 4 additions & 2 deletions quil-py/src/instruction/gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ use rigetti_pyo3::{
use strum;

use crate::{
expression::PyExpression, impl_copy_for_instruction, impl_eq, impl_to_quil,
instruction::PyQubit,
expression::PyExpression, impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction,
impl_to_quil, instruction::PyQubit,
};

wrap_error!(RustGateError(quil_rs::instruction::GateError));
Expand All @@ -45,6 +45,7 @@ impl_copy_for_instruction!(PyGate);
impl_to_quil!(PyGate);
impl_hash!(PyGate);
impl_eq!(PyGate);
impl_pickle_for_instruction!(PyGate);

#[pymethods]
impl PyGate {
Expand Down Expand Up @@ -271,6 +272,7 @@ impl_to_quil!(PyGateDefinition);
impl_copy_for_instruction!(PyGateDefinition);
impl_hash!(PyGateDefinition);
impl_eq!(PyGateDefinition);
impl_pickle_for_instruction!(PyGateDefinition);

#[pymethods]
impl PyGateDefinition {
Expand Down
3 changes: 2 additions & 1 deletion quil-py/src/instruction/measurement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rigetti_pyo3::{
};

use crate::{
impl_copy_for_instruction, impl_eq, impl_to_quil,
impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil,
instruction::{PyMemoryReference, PyQubit},
};

Expand All @@ -23,6 +23,7 @@ impl_copy_for_instruction!(PyMeasurement);
impl_hash!(PyMeasurement);
impl_repr!(PyMeasurement);
impl_eq!(PyMeasurement);
impl_pickle_for_instruction!(PyMeasurement);

#[pymethods]
impl PyMeasurement {
Expand Down
11 changes: 11 additions & 0 deletions quil-py/src/instruction/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::str::FromStr;

use pyo3::exceptions::PyValueError;
use quil_rs::instruction::Instruction;
use rigetti_pyo3::{
create_init_submodule, impl_repr, py_wrap_union_enum,
Expand Down Expand Up @@ -105,6 +108,14 @@ impl PyInstruction {
self.as_inner().is_quil_t()
}

#[staticmethod]
pub fn parse(string: &str) -> PyResult<Self> {
match Instruction::from_str(string) {
Ok(instruction) => Ok(Self(instruction)),
Err(err) => Err(PyValueError::new_err(err.to_string())),
}
}

// Implement the __copy__ and __deepcopy__ dunder methods, which are used by Python's
// `copy` module.
//
Expand Down
4 changes: 3 additions & 1 deletion quil-py/src/instruction/pragma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rigetti_pyo3::{
PyTryFrom,
};

use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
use crate::{impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction, impl_to_quil};

py_wrap_data_struct! {
#[derive(Debug, PartialEq, Eq)]
Expand All @@ -26,6 +26,7 @@ impl_to_quil!(PyPragma);
impl_copy_for_instruction!(PyPragma);
impl_hash!(PyPragma);
impl_eq!(PyPragma);
impl_pickle_for_instruction!(PyPragma);

#[pymethods]
impl PyPragma {
Expand Down Expand Up @@ -68,6 +69,7 @@ impl_to_quil!(PyInclude);
impl_copy_for_instruction!(PyInclude);
impl_hash!(PyInclude);
impl_eq!(PyInclude);
impl_pickle_for_instruction!(PyInclude);

#[pymethods]
impl PyInclude {
Expand Down
Loading

0 comments on commit e500db8

Please sign in to comment.