qudit_expr/expressions/
brasys.rs1use std::ops::{Deref, DerefMut};
2
3use crate::{
4 GenerationShape, TensorExpression,
5 expressions::JittableExpression,
6 index::{IndexDirection, TensorIndex},
7};
8
9use super::NamedExpression;
10use qudit_core::QuditSystem;
11use qudit_core::Radices;
12
13#[derive(PartialEq, Eq, Debug, Clone)]
14pub struct BraSystemExpression {
15 inner: NamedExpression,
16 radices: Radices,
17 num_states: usize,
18}
19
20impl BraSystemExpression {
21 pub fn new<T: AsRef<str>>(input: T) -> Self {
22 TensorExpression::new(input).try_into().unwrap()
23 }
24
25 pub fn num_qudits(&self) -> usize {
26 self.radices.num_qudits()
27 }
28}
29
30impl JittableExpression for BraSystemExpression {
31 fn generation_shape(&self) -> GenerationShape {
32 GenerationShape::Tensor3D(self.num_states, 1, self.radices.dimension())
33 }
34}
35
36impl AsRef<NamedExpression> for BraSystemExpression {
37 fn as_ref(&self) -> &NamedExpression {
38 &self.inner
39 }
40}
41
42impl From<BraSystemExpression> for NamedExpression {
43 fn from(value: BraSystemExpression) -> Self {
44 value.inner
45 }
46}
47
48impl Deref for BraSystemExpression {
49 type Target = NamedExpression;
50
51 fn deref(&self) -> &Self::Target {
52 &self.inner
53 }
54}
55
56impl DerefMut for BraSystemExpression {
57 fn deref_mut(&mut self) -> &mut Self::Target {
58 &mut self.inner
59 }
60}
61
62impl From<BraSystemExpression> for TensorExpression {
76 fn from(value: BraSystemExpression) -> Self {
77 let BraSystemExpression {
78 inner,
79 radices,
80 num_states,
81 } = value;
82 let indices = [num_states]
84 .into_iter()
85 .map(|r| (IndexDirection::Batch, r))
86 .chain(
87 radices
88 .iter()
89 .map(|r| (IndexDirection::Input, usize::from(*r))),
90 )
91 .enumerate()
92 .map(|(i, (d, r))| TensorIndex::new(d, i, r))
93 .collect();
94 TensorExpression::from_raw(indices, inner)
95 }
96}
97
98impl TryFrom<TensorExpression> for BraSystemExpression {
99 type Error = String;
101
102 fn try_from(value: TensorExpression) -> Result<Self, Self::Error> {
103 let mut num_states = None;
104 let mut radices = vec![];
105 for idx in value.indices() {
106 match idx.direction() {
107 IndexDirection::Batch => match num_states {
108 Some(n) => num_states = Some(n * idx.index_size()),
109 None => num_states = Some(idx.index_size()),
110 },
111 IndexDirection::Input => {
112 radices.push(idx.index_size());
113 }
114 _ => {
115 if idx.index_size() > 1 {
116 return Err(String::from(
117 "Cannot convert a tensor with non-input or batch indices to a bra system.",
118 ));
119 }
120 }
121 }
122 }
123
124 Ok(BraSystemExpression {
125 inner: value.into(),
126 radices: radices.into(),
127 num_states: num_states.unwrap_or(1),
128 })
129 }
130}
131
132#[cfg(feature = "python")]
133mod python {
134 use super::*;
135 use crate::python::PyExpressionRegistrar;
136 use pyo3::prelude::*;
137 use pyo3_stub_gen::derive::*;
138 use qudit_core::Radix;
139
140 #[gen_stub_pyclass]
142 #[pyclass(name = "BraSystemExpression", module = "openqudit.expressions")]
143 pub struct PyBraSystemExpression {
144 expr: BraSystemExpression,
145 }
146
147 #[gen_stub_pymethods]
148 #[pymethods]
149 impl PyBraSystemExpression {
150 #[new]
156 fn new(expr: String) -> Self {
157 Self {
158 expr: BraSystemExpression::new(expr),
159 }
160 }
161
162 fn num_params(&self) -> usize {
164 self.expr.num_params()
165 }
166
167 fn name(&self) -> String {
169 self.expr.name().to_string()
170 }
171
172 fn radices(&self) -> Vec<Radix> {
174 self.expr.radices.to_vec()
175 }
176
177 fn num_qudits(&self) -> usize {
179 self.expr.num_qudits()
180 }
181
182 fn num_states(&self) -> usize {
184 self.expr.num_states
185 }
186
187 fn dimension(&self) -> usize {
189 self.expr.radices.dimension()
190 }
191
192 fn __repr__(&self) -> String {
193 format!(
194 "BraSystemExpression(name='{}', radices={:?}, num_states={}, params={})",
195 self.expr.name(),
196 self.expr.radices.to_vec(),
197 self.expr.num_states,
198 self.expr.num_params()
199 )
200 }
201 }
202
203 impl From<BraSystemExpression> for PyBraSystemExpression {
204 fn from(value: BraSystemExpression) -> Self {
205 PyBraSystemExpression { expr: value }
206 }
207 }
208
209 impl From<PyBraSystemExpression> for BraSystemExpression {
210 fn from(value: PyBraSystemExpression) -> Self {
211 value.expr
212 }
213 }
214
215 impl<'py> IntoPyObject<'py> for BraSystemExpression {
216 type Target = <PyBraSystemExpression as IntoPyObject<'py>>::Target;
217 type Output = Bound<'py, Self::Target>;
218 type Error = PyErr;
219
220 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
221 let py_expr = PyBraSystemExpression::from(self);
222 Bound::new(py, py_expr)
223 }
224 }
225
226 impl<'a, 'py> FromPyObject<'a, 'py> for BraSystemExpression {
227 type Error = PyErr;
228
229 fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
230 let py_expr: PyRef<PyBraSystemExpression> = ob.extract()?;
231 Ok(py_expr.expr.clone())
232 }
233 }
234
235 fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
237 parent_module.add_class::<PyBraSystemExpression>()?;
238 Ok(())
239 }
240 inventory::submit!(PyExpressionRegistrar { func: register });
241}