qudit_expr/expressions/
bra.rs1use std::ops::Deref;
2use std::ops::DerefMut;
3
4use crate::GenerationShape;
5use crate::TensorExpression;
6use crate::expressions::JittableExpression;
7use crate::index::IndexDirection;
8use crate::index::TensorIndex;
9
10use super::NamedExpression;
11use qudit_core::QuditSystem;
12use qudit_core::Radices;
13
14#[derive(PartialEq, Eq, Debug, Clone)]
15pub struct BraExpression {
16 inner: NamedExpression,
17 radices: Radices,
18}
19
20impl BraExpression {
21 pub fn new<T: AsRef<str>>(input: T) -> Self {
22 TensorExpression::new(input).try_into().unwrap()
23 }
24}
25
26impl JittableExpression for BraExpression {
27 fn generation_shape(&self) -> GenerationShape {
28 GenerationShape::Vector(self.radices.dimension())
29 }
30}
31
32impl AsRef<NamedExpression> for BraExpression {
33 fn as_ref(&self) -> &NamedExpression {
34 &self.inner
35 }
36}
37
38impl From<BraExpression> for NamedExpression {
39 fn from(value: BraExpression) -> Self {
40 value.inner
41 }
42}
43
44impl Deref for BraExpression {
45 type Target = NamedExpression;
46
47 fn deref(&self) -> &Self::Target {
48 &self.inner
49 }
50}
51
52impl DerefMut for BraExpression {
53 fn deref_mut(&mut self) -> &mut Self::Target {
54 &mut self.inner
55 }
56}
57
58impl From<BraExpression> for TensorExpression {
59 fn from(value: BraExpression) -> Self {
60 let BraExpression { inner, radices } = value;
61 let indices = radices
63 .iter()
64 .enumerate()
65 .map(|(i, r)| TensorIndex::new(IndexDirection::Input, i, usize::from(*r)))
66 .collect();
67 TensorExpression::from_raw(indices, inner)
68 }
69}
70
71impl TryFrom<TensorExpression> for BraExpression {
72 type Error = String;
74
75 fn try_from(value: TensorExpression) -> Result<Self, Self::Error> {
76 if value
77 .indices()
78 .iter()
79 .any(|idx| idx.direction() != IndexDirection::Input)
80 {
81 return Err(String::from(
82 "Cannot convert a tensor with non-input indices to a bra.",
83 ));
84 }
85 let radices = Radices::from_iter(value.indices().iter().map(|idx| idx.index_size()));
86 Ok(BraExpression {
87 inner: value.into(),
88 radices,
89 })
90 }
91}
92
93impl QuditSystem for BraExpression {
94 fn radices(&self) -> Radices {
95 self.radices.clone()
96 }
97
98 fn num_qudits(&self) -> usize {
99 self.radices.num_qudits()
100 }
101}
102
103#[cfg(feature = "python")]
104mod python {
105 use super::*;
106 use crate::python::PyExpressionRegistrar;
107 use pyo3::prelude::*;
108 use pyo3_stub_gen::derive::*;
109 use qudit_core::Radix;
110
111 #[gen_stub_pyclass]
113 #[pyclass(name = "BraExpression", module = "openqudit.expressions")]
114 pub struct PyBraExpression {
115 expr: BraExpression,
116 }
117
118 #[gen_stub_pymethods]
119 #[pymethods]
120 impl PyBraExpression {
121 #[new]
127 fn new(expr: String) -> Self {
128 Self {
129 expr: BraExpression::new(expr),
130 }
131 }
132
133 fn num_params(&self) -> usize {
135 self.expr.num_params()
136 }
137
138 fn name(&self) -> String {
140 self.expr.name().to_string()
141 }
142
143 fn radices(&self) -> Vec<Radix> {
145 self.expr.radices().to_vec()
146 }
147
148 fn dimension(&self) -> usize {
150 self.expr.dimension()
151 }
152
153 fn __repr__(&self) -> String {
154 format!(
155 "BraExpression(name='{}', radices={:?}, params={})",
156 self.expr.name(),
157 self.expr.radices().to_vec(),
158 self.expr.num_params()
159 )
160 }
161 }
162
163 impl From<BraExpression> for PyBraExpression {
164 fn from(value: BraExpression) -> Self {
165 PyBraExpression { expr: value }
166 }
167 }
168
169 impl From<PyBraExpression> for BraExpression {
170 fn from(value: PyBraExpression) -> Self {
171 value.expr
172 }
173 }
174
175 impl<'py> IntoPyObject<'py> for BraExpression {
176 type Target = <PyBraExpression as IntoPyObject<'py>>::Target;
177 type Output = Bound<'py, Self::Target>;
178 type Error = PyErr;
179
180 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
181 let py_expr = PyBraExpression::from(self);
182 Bound::new(py, py_expr)
183 }
184 }
185
186 impl<'a, 'py> FromPyObject<'a, 'py> for BraExpression {
187 type Error = PyErr;
188
189 fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
190 let py_expr: PyRef<PyBraExpression> = ob.extract()?;
191 Ok(py_expr.expr.clone())
192 }
193 }
194
195 fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
197 parent_module.add_class::<PyBraExpression>()?;
198 Ok(())
199 }
200 inventory::submit!(PyExpressionRegistrar { func: register });
201}