1use numpy::{PyArray2, ToPyArray};
2use quil_rs::{
3 expression::Expression,
4 instruction::{
5 Gate, GateDefinition, GateModifier, GateSpecification, PauliGate, PauliSum, PauliTerm,
6 Qubit,
7 },
8};
9use rigetti_pyo3::{
10 impl_from_str, impl_hash, impl_parse, impl_repr, impl_str,
11 num_complex::Complex64,
12 py_wrap_data_struct, py_wrap_error, py_wrap_simple_enum, py_wrap_type, py_wrap_union_enum,
13 pyo3::{
14 exceptions::PyValueError,
15 pymethods,
16 types::{PyInt, PyString},
17 Py, PyErr, PyResult, Python,
18 },
19 wrap_error, PyTryFrom, PyWrapper, PyWrapperMut, ToPython, ToPythonError,
20};
21use strum;
22
23use crate::{
24 expression::PyExpression, impl_copy_for_instruction, impl_eq, impl_pickle_for_instruction,
25 impl_to_quil, instruction::PyQubit,
26};
27
28wrap_error!(RustGateError(quil_rs::instruction::GateError));
29py_wrap_error!(quil, RustGateError, GateError, PyValueError);
30wrap_error!(RustParseEnumError(strum::ParseError));
31py_wrap_error!(quil, RustParseEnumError, EnumParseError, PyValueError);
32
33py_wrap_data_struct! {
34 #[derive(Debug, PartialEq, Eq)]
35 #[pyo3(subclass, module = "quil.instructions")]
36 PyGate(Gate) as "Gate" {
37 name: String => Py<PyString>,
38 parameters: Vec<Expression> => Vec<PyExpression>,
39 qubits: Vec<Qubit> => Vec<PyQubit>,
40 modifiers: Vec<GateModifier> => Vec<PyGateModifier>
41 }
42}
43impl_repr!(PyGate);
44impl_copy_for_instruction!(PyGate);
45impl_to_quil!(PyGate);
46impl_hash!(PyGate);
47impl_eq!(PyGate);
48impl_pickle_for_instruction!(PyGate);
49
50#[pymethods]
51impl PyGate {
52 #[new]
53 fn new(
54 py: Python<'_>,
55 name: String,
56 parameters: Vec<PyExpression>,
57 qubits: Vec<PyQubit>,
58 modifiers: Vec<PyGateModifier>,
59 ) -> PyResult<Self> {
60 Ok(Self(
61 Gate::new(
62 &name,
63 Vec::<Expression>::py_try_from(py, ¶meters)?,
64 Vec::<Qubit>::py_try_from(py, &qubits)?,
65 Vec::<GateModifier>::py_try_from(py, &modifiers)?,
66 )
67 .map_err(RustGateError::from)
68 .map_err(RustGateError::to_py_err)?,
69 ))
70 }
71
72 fn dagger(&self, py: Python<'_>) -> PyResult<Self> {
73 self.as_inner().clone().dagger().to_python(py)
74 }
75
76 fn controlled(&self, py: Python<'_>, control_qubit: PyQubit) -> PyResult<Self> {
77 self.as_inner()
78 .clone()
79 .controlled(Qubit::py_try_from(py, &control_qubit)?)
80 .to_python(py)
81 }
82
83 fn forked(
84 &self,
85 py: Python<'_>,
86 fork_qubit: PyQubit,
87 alt_params: Vec<PyExpression>,
88 ) -> PyResult<Self> {
89 self.as_inner()
90 .clone()
91 .forked(
92 Qubit::py_try_from(py, &fork_qubit)?,
93 Vec::<Expression>::py_try_from(py, &alt_params)?,
94 )
95 .map_err(RustGateError::from)
96 .map_err(RustGateError::to_py_err)?
97 .to_python(py)
98 }
99
100 fn to_unitary_mut(
101 &mut self,
102 py: Python<'_>,
103 n_qubits: u64,
104 ) -> PyResult<Py<PyArray2<Complex64>>> {
105 Ok(self
106 .as_inner_mut()
107 .to_unitary(n_qubits)
108 .map_err(RustGateError::from)
109 .map_err(RustGateError::to_py_err)?
110 .to_pyarray(py)
111 .to_owned())
112 }
113}
114
115py_wrap_simple_enum! {
116 #[derive(Debug, PartialEq, Eq)]
117 PyGateModifier(GateModifier) as "GateModifier" {
118 Controlled,
119 Dagger,
120 Forked
121 }
122}
123impl_repr!(PyGateModifier);
124impl_to_quil!(PyGateModifier);
125impl_hash!(PyGateModifier);
126impl_eq!(PyGateModifier);
127
128py_wrap_simple_enum! {
129 #[derive(Debug, PartialEq, Eq)]
130 PyPauliGate(PauliGate) as "PauliGate" {
131 I,
132 X,
133 Y,
134 Z
135 }
136}
137impl_repr!(PyPauliGate);
138impl_str!(PyPauliGate);
139impl_hash!(PyPauliGate);
140impl_from_str!(PyPauliGate, RustParseEnumError);
141impl_parse!(PyPauliGate);
142
143py_wrap_type! {
146 PyPauliPair((PauliGate, String))
147}
148
149impl PyPauliPair {
150 pub(crate) fn from_py_tuple(py: Python<'_>, tuple: (PyPauliGate, String)) -> PyResult<Self> {
151 Ok(Self((PauliGate::py_try_from(py, &tuple.0)?, tuple.1)))
152 }
153}
154
155py_wrap_data_struct! {
156 #[derive(Debug, PartialEq, Eq)]
157 #[pyo3(subclass)]
158 PyPauliTerm(PauliTerm) as "PauliTerm" {
159 arguments: Vec<(PauliGate, String)> => Vec<PyPauliPair>,
160 expression: Expression => PyExpression
161 }
162}
163
164#[pymethods]
165impl PyPauliTerm {
166 #[new]
167 pub fn new(
168 py: Python<'_>,
169 arguments: Vec<(PyPauliGate, String)>,
170 expression: PyExpression,
171 ) -> PyResult<Self> {
172 Ok(Self(PauliTerm::new(
173 Vec::<(PauliGate, String)>::py_try_from(
174 py,
175 &PyPauliTerm::py_pairs_from_tuples(py, arguments)?,
176 )?,
177 Expression::py_try_from(py, &expression)?,
178 )))
179 }
180
181 #[getter(arguments)]
184 fn get_arguments_as_tuple(&self, py: Python<'_>) -> PyResult<Vec<(PyPauliGate, String)>> {
185 let mut pairs: Vec<(PyPauliGate, String)> =
186 Vec::with_capacity(self.as_inner().arguments.len());
187 self.as_inner()
188 .arguments
189 .iter()
190 .try_for_each(|(gate, arg)| {
191 pairs.push((gate.to_python(py)?, arg.clone()));
192 Ok::<(), PyErr>(())
193 })?;
194 Ok(pairs)
195 }
196
197 #[setter(arguments)]
198 fn set_arguments_from_tuple(
199 &mut self,
200 py: Python<'_>,
201 arguments: Vec<(PyPauliGate, String)>,
202 ) -> PyResult<()> {
203 self.as_inner_mut().arguments = Vec::<(PauliGate, String)>::py_try_from(
204 py,
205 &PyPauliTerm::py_pairs_from_tuples(py, arguments)?,
206 )?;
207 Ok(())
208 }
209}
210
211impl PyPauliTerm {
212 pub(crate) fn py_pairs_from_tuples(
213 py: Python<'_>,
214 tuples: Vec<(PyPauliGate, String)>,
215 ) -> PyResult<Vec<PyPauliPair>> {
216 let mut pairs: Vec<PyPauliPair> = Vec::with_capacity(tuples.len());
217 tuples.into_iter().try_for_each(|tuple| {
218 pairs.push(PyPauliPair::from_py_tuple(py, tuple)?);
219 Ok::<(), PyErr>(())
220 })?;
221 Ok(pairs)
222 }
223}
224
225py_wrap_data_struct! {
226 #[derive(Debug, PartialEq, Eq)]
227 #[pyo3(subclass)]
228 PyPauliSum(PauliSum) as "PauliSum" {
229 arguments: Vec<String> => Vec<Py<PyString>>,
230 terms: Vec<PauliTerm> => Vec<PyPauliTerm>
231 }
232}
233impl_repr!(PyPauliSum);
234impl_eq!(PyPauliSum);
235
236#[pymethods]
237impl PyPauliSum {
238 #[new]
239 pub fn new(py: Python<'_>, arguments: Vec<String>, terms: Vec<PyPauliTerm>) -> PyResult<Self> {
240 Ok(Self(
241 PauliSum::new(arguments, Vec::<PauliTerm>::py_try_from(py, &terms)?)
242 .map_err(RustGateError::from)
243 .map_err(RustGateError::to_py_err)?,
244 ))
245 }
246}
247
248py_wrap_union_enum! {
249 #[derive(Debug, PartialEq, Eq)]
250 PyGateSpecification(GateSpecification) as "GateSpecification" {
251 matrix: Matrix => Vec<Vec<PyExpression>>,
252 permutation: Permutation => Vec<Py<PyInt>>,
253 pauli_sum: PauliSum => PyPauliSum
254 }
255}
256impl_repr!(PyGateSpecification);
257impl_to_quil!(PyGateSpecification);
258impl_hash!(PyGateSpecification);
259impl_eq!(PyGateSpecification);
260
261py_wrap_data_struct! {
262 #[derive(Debug, PartialEq, Eq)]
263 #[pyo3(subclass, module = "quil.instructions")]
264 PyGateDefinition(GateDefinition) as "GateDefinition" {
265 name: String => Py<PyString>,
266 parameters: Vec<String> => Vec<Py<PyString>>,
267 specification: GateSpecification => PyGateSpecification
268 }
269}
270impl_repr!(PyGateDefinition);
271impl_to_quil!(PyGateDefinition);
272impl_copy_for_instruction!(PyGateDefinition);
273impl_hash!(PyGateDefinition);
274impl_eq!(PyGateDefinition);
275impl_pickle_for_instruction!(PyGateDefinition);
276
277#[pymethods]
278impl PyGateDefinition {
279 #[new]
280 pub fn new(
281 py: Python<'_>,
282 name: String,
283 parameters: Vec<String>,
284 specification: PyGateSpecification,
285 ) -> PyResult<Self> {
286 Ok(Self(
287 GateDefinition::new(
288 name,
289 parameters,
290 GateSpecification::py_try_from(py, &specification)?,
291 )
292 .map_err(RustGateError::from)
293 .map_err(RustGateError::to_py_err)?,
294 ))
295 }
296}