Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions quil-rs/python/quil/instructions.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -384,11 +384,9 @@ class CircuitDefinition:
@parameters.setter
def parameters(self, value: builtins.list[builtins.str]) -> None: ...
@property
def qubit_variables(self) -> builtins.list[builtins.str]: ...
@qubit_variables.setter
def qubit_variables(self, value: builtins.list[builtins.str]) -> None: ...
def qubits(self) -> builtins.list[Qubit]: ...
def __eq__(self, other: builtins.object) -> builtins.bool: ...
def __getnewargs__(self) -> tuple[builtins.str, builtins.list[builtins.str], builtins.list[builtins.str], builtins.list[Instruction]]: ...
def __getnewargs__(self) -> tuple: ...
def __new__(cls, name: builtins.str, parameters: typing.Sequence[builtins.str], qubit_variables: typing.Sequence[builtins.str], instructions: typing.Sequence[Instruction]) -> CircuitDefinition: ...
def __repr__(self) -> builtins.str:
r"""
Expand Down
61 changes: 43 additions & 18 deletions quil-rs/src/instruction/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#[cfg(feature = "stubs")]
use pyo3_stub_gen::derive::gen_stub_pyclass;
use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};

#[cfg(not(feature = "python"))]
use optipy::strip_pyo3;

use crate::{
pickleable_new,
instruction::Qubit,
quil::{Quil, INDENT},
};

Expand All @@ -12,24 +15,41 @@ use super::Instruction;
#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "quil.instructions", eq, get_all, set_all, subclass)
pyo3::pyclass(module = "quil.instructions", eq, subclass)
)]
#[cfg_attr(not(feature = "python"), strip_pyo3)]
pub struct CircuitDefinition {
#[pyo3(get, set)]
pub name: String,

#[pyo3(get, set)]
pub parameters: Vec<String>,
// These cannot be fixed qubits and thus are not typed as `Qubit`
pub qubit_variables: Vec<String>,

// These should always be Qubit::Variable
#[pyo3(get)]
pub(crate) qubits: Vec<Qubit>,

#[pyo3(get, set)]
pub instructions: Vec<Instruction>,
}

pickleable_new! {
impl CircuitDefinition {
pub fn new(
name: String,
parameters: Vec<String>,
qubit_variables: Vec<String>,
instructions: Vec<Instruction>,
);
#[cfg_attr(feature = "stubs", gen_stub_pymethods)]
#[cfg_attr(feature = "python", pyo3::pymethods)]
#[cfg_attr(not(feature = "python"), strip_pyo3)]
impl CircuitDefinition {
#[new]
pub fn new(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're not able to use pickleable_new here1, you should implement __getnewargs__ manually so that CircuitDefinitions (and its subclasses) remain pickleable.

Since doing so is purely for Python users, our convention is to put it in a quilpy module. In this case, the appropriate place is src/instructions/quilpy.rs, likely around line 460.

Here's one possible implementation (the important thing is that its arguments are compatible with the method marked #[new]):

#[cfg_attr(feature = "stubs", gen_stub_pymethods)]
#[pymethods]
impl CircuitDefinition {
    fn __getnewargs__<'py>(&self, py: pyo3::Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
        (
            self.name.clone(),
            self.parameters.clone(),
            self.qubits.clone(),
            self.instructions.clone(),
        ).into_pyobject(py)
    }
}

Footnotes

  1. I'd still like to look into improving this macro to make it useful across a wider range of cases, and likely move it to rigetti-pyo3. ↩

name: String,
parameters: Vec<String>,
qubit_variables: Vec<String>,
instructions: Vec<Instruction>,
) -> Self {
Self {
name,
parameters,
qubits: qubit_variables.into_iter().map(Qubit::Variable).collect(),
instructions,
}
}
}

Expand All @@ -51,8 +71,13 @@ impl Quil for CircuitDefinition {
}
write!(writer, ")")?;
}
for qubit_variable in &self.qubit_variables {
write!(writer, " {qubit_variable}")?;
for qubit in &self.qubits {
let q = if fall_back_to_debug {
qubit.to_quil_or_debug()
} else {
qubit.to_quil()?
};
write!(writer, " {q}")?;
}
writeln!(writer, ":")?;
for instruction in &self.instructions {
Expand Down Expand Up @@ -86,7 +111,7 @@ mod test_circuit_definition {
CircuitDefinition {
name: "BELL".to_owned(),
parameters: vec![],
qubit_variables: vec!["a".to_owned(), "b".to_owned()],
qubits: vec![Qubit::Variable("a".to_owned()), Qubit::Variable("b".to_owned())],
instructions: vec![
Instruction::Gate(Gate {
name: "H".to_owned(),
Expand All @@ -111,7 +136,7 @@ mod test_circuit_definition {
CircuitDefinition {
name: "BELL".to_owned(),
parameters: vec!["a".to_owned(), "b".to_owned()],
qubit_variables: vec!["a".to_owned(), "b".to_owned()],
qubits: vec![Qubit::Variable("a".to_owned()), Qubit::Variable("b".to_owned())],
instructions: vec![
Instruction::Gate(Gate {
name: "RZ".to_owned(),
Expand Down Expand Up @@ -154,7 +179,7 @@ mod test_circuit_definition {
CircuitDefinition {
name: "BELL".to_owned(),
parameters: vec!["a".to_owned()],
qubit_variables: vec!["a".to_owned(), "b".to_owned()],
qubits: vec![Qubit::Variable("a".to_owned()), Qubit::Variable("b".to_owned())],
instructions: vec![
Instruction::Gate(Gate {
name: "RZ".to_owned(),
Expand Down
27 changes: 15 additions & 12 deletions quil-rs/src/instruction/gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,21 @@ impl<'a, T: AsRef<str>> GateSignature<'a, T> {
}

#[cfg(feature = "python")]
impl<'a, T: AsRef<str>> GateSignature<'a, T> {
pub(crate) fn gate_parameters(&self) -> &[T] {
self.gate_parameters
}

pub(crate) fn qubit_parameters(&self) -> &[T] {
self.qubit_parameters
}

pub(crate) fn gate_type(&self) -> GateType {
self.gate_type
}
}

#[cfg(any(feature = "python", test))]
impl<'a, T: AsRef<str>> GateSignature<'a, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think you should just pull the try_new method into a separate impl block instead of repeating the #[cfg(feature = "python")]s.

pub(crate) fn try_new(
name: &'a T,
Expand All @@ -1072,18 +1087,6 @@ impl<'a, T: AsRef<str>> GateSignature<'a, T> {
gate_type,
})
}

pub(crate) fn gate_parameters(&self) -> &[T] {
self.gate_parameters
}

pub(crate) fn qubit_parameters(&self) -> &[T] {
self.qubit_parameters
}

pub(crate) fn gate_type(&self) -> GateType {
self.gate_type
}
}

impl Quil for GateSignature<'_> {
Expand Down
Loading
Loading