#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StateExpression {
pub name: String,
pub radices: QuditRadices,
pub variables: Vec<String>,
pub body: Vec<ComplexExpression>,
}
impl StateExpression {
pub fn new<T: AsRef<str>>(input: T) -> Self {
TensorExpression::new(input).into()
}
pub fn zero<T: ToRadices>(radices: T) -> Self {
let radices = radices.to_radices();
let mut body = vec![ComplexExpression::zero(); radices.dimension()];
body[0] = ComplexExpression::one();
Self {
name: "Zero".into(),
radices,
variables: vec![],
body,
}
}
pub fn to_tensor_expression(self) -> TensorExpression {
let indices = self.radices.iter().enumerate().map(|(id, r)| TensorIndex::new(IndexDirection::Output, id, *r as IndexSize)).collect();
TensorExpression::from_raw(indices, NamedExpression::new(self.name, self.variables, self.body))
}
pub fn eval<C: ComplexScalar>(&self, args: &[C::R]) -> StateVector<C> {
let arg_map = self.variables.iter().zip(args.iter()).map(|(a, b)| (a.as_str(), *b)).collect();
let evaluated_body: Vec<C> = self.body.iter().map(|expr| expr.eval(&arg_map)).collect();
StateVector::new(self.radices.clone(), evaluated_body)
}
pub fn conjugate(&self) -> Self {
let new_body = self.body.iter().map(|expr| expr.conjugate()).collect();
StateExpression {
name: format!("{}^_", self.name),
radices: self.radices.clone(),
variables: self.variables.clone(),
body: new_body,
}
}
pub fn name(&self) -> String {
self.name.clone()
}
}
impl<C: ComplexScalar> From<UnitaryMatrix<C>> for UnitaryExpression {
fn from(utry: UnitaryMatrix<C>) -> Self {
let mut body = vec![Vec::with_capacity(utry.ncols()); utry.nrows()];
for col in utry.col_iter() {
for (row_id, elem) in col.iter().enumerate() {
body[row_id].push(ComplexExpression::from(*elem));
}
}
UnitaryExpression {
name: "Constant".into(),
radices: utry.radices(),
variables: vec![],
body,
}
}
}
impl From<TensorExpression> for UnitaryExpression {
fn from(value: TensorExpression) -> Self {
match value.generation_shape() {
GenerationShape::Matrix(nrows, ncols) => {
assert_eq!(nrows, ncols);
let mut body = Vec::with_capacity(nrows);
for i in 0..nrows {
let start = i * ncols;
let end = start + ncols;
let row = value[start..end].to_vec();
body.push(row);
}
let radices = QuditRadices::from_iter(value.indices().iter().filter(|&i| i.direction().is_input()).map(|i| i.index_size()));
UnitaryExpression {
name: value.name().to_owned(),
radices,
variables: value.variables().to_owned(),
body,
}
}
_ => panic!("TensorExpression shape must be a matrix to convert to UnitaryExpression"),
}
}
}
impl From<TensorExpression> for StateExpression {
fn from(value: TensorExpression) -> Self {
match value.generation_shape() {
GenerationShape::Vector(_) => {
let radices = QuditRadices::from_iter(value.indices().iter().map(|i| i.index_size()));
StateExpression {
name: value.name().to_owned(),
radices,
variables: value.variables().to_owned(),
body: value.elements().to_owned(),
}
}
_ => panic!("TensorExpression shape must be a vector to convert to StateExpression"),
}
}
}
impl From<TensorExpression> for StateSystemExpression {
fn from(value: TensorExpression) -> Self {
match value.generation_shape() {
GenerationShape::Tensor3D(ntens, nrows, ncols) => {
let body = if nrows == 1 {
let mut body = Vec::with_capacity(ntens);
for i in 0..ntens {
let start = i * ncols;
let end = start + ncols;
let row = value[start..end].to_vec();
body.push(row);
}
body
} else if ncols == 1 {
let mut body = Vec::with_capacity(ntens);
for i in 0..ntens {
let start = i * nrows;
let end = start + nrows;
let row = value[start..end].to_vec();
body.push(row);
}
body
} else {
panic!("Wrong (TODO: better message).")
};
let radices = QuditRadices::from_iter(value.indices().iter().filter(|&i| !i.direction().is_batch()).map(|i| i.index_size()));
StateSystemExpression {
name: value.name().to_owned(),
radices,
variables: value.variables().to_owned(),
body,
}
}
_ => panic!("TensorExpression shape must be a Tensor3D to convert to StateSystemExpression"),
}
}
}
impl From<UnitaryExpression> for TensorExpression {
fn from(value: UnitaryExpression) -> Self {
let flattened_body: Vec<ComplexExpression> = value.body.clone().into_iter().flat_map(|row| row.into_iter()).collect();
let indices = value.radices.iter()
.map(|&r| (IndexDirection::Output, r))
.chain(value.radices.iter().map(|&r| (IndexDirection::Input, r)))
.enumerate()
.map(|(id, (dir, size))| TensorIndex::new(dir, id, size as usize))
.collect();
TensorExpression::from_raw(indices, NamedExpression::new(value.name.clone(), value.variables.clone(), flattened_body))
}
}