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 qudit_core::Radix;
109
110 #[pyclass]
111 #[pyo3(name = "BraExpression")]
112 pub struct PyBraExpression {
113 expr: BraExpression,
114 }
115
116 #[pymethods]
117 impl PyBraExpression {
118 #[new]
119 fn new(expr: String) -> Self {
120 Self {
121 expr: BraExpression::new(expr),
122 }
123 }
124
125 fn num_params(&self) -> usize {
126 self.expr.num_params()
127 }
128
129 fn name(&self) -> String {
130 self.expr.name().to_string()
131 }
132
133 fn radices(&self) -> Vec<Radix> {
134 self.expr.radices().to_vec()
135 }
136
137 fn dimension(&self) -> usize {
138 self.expr.dimension()
139 }
140
141 fn __repr__(&self) -> String {
142 format!(
143 "BraExpression(name='{}', radices={:?}, params={})",
144 self.expr.name(),
145 self.expr.radices().to_vec(),
146 self.expr.num_params()
147 )
148 }
149 }
150
151 impl From<BraExpression> for PyBraExpression {
152 fn from(value: BraExpression) -> Self {
153 PyBraExpression { expr: value }
154 }
155 }
156
157 impl From<PyBraExpression> for BraExpression {
158 fn from(value: PyBraExpression) -> Self {
159 value.expr
160 }
161 }
162
163 impl<'py> IntoPyObject<'py> for BraExpression {
164 type Target = <PyBraExpression as IntoPyObject<'py>>::Target;
165 type Output = Bound<'py, Self::Target>;
166 type Error = PyErr;
167
168 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
169 let py_expr = PyBraExpression::from(self);
170 Bound::new(py, py_expr)
171 }
172 }
173
174 impl<'a, 'py> FromPyObject<'a, 'py> for BraExpression {
175 type Error = PyErr;
176
177 fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
178 let py_expr: PyRef<PyBraExpression> = ob.extract()?;
179 Ok(py_expr.expr.clone())
180 }
181 }
182
183 fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
185 parent_module.add_class::<PyBraExpression>()?;
186 Ok(())
187 }
188 inventory::submit!(PyExpressionRegistrar { func: register });
189}