use std::mem;
use super::ar_product;
use crate::algebra::types::{Alpha, Form, Index, Sign, Term};
pub trait AR {
type Output: AR;
fn as_terms(&self) -> Vec<Term>;
fn from_terms(terms: Vec<Term>) -> Self;
fn inverse(&self) -> Self::Output {
Self::Output::from_terms(self.as_terms().iter().map(|t| t.inverse()).collect())
}
fn as_alphas(&self) -> Vec<Alpha> {
self.as_terms().iter().map(|t| t.alpha()).collect()
}
fn from_alphas(alphas: Vec<Alpha>) -> Self::Output {
Self::Output::from_terms(alphas.iter().map(|a| Term::new(None, a.clone())).collect())
}
fn is_scalar(&self) -> bool {
self.as_terms()
.iter()
.fold(true, |acc, t| acc && t.form() == Form::Point)
}
fn reversed(&self) -> Self::Output {
Self::Output::from_terms(
self.as_terms()
.iter()
.map(|t| match t.alpha().form() {
Form::Vector(_) | Form::Quadrivector(_, _, _, _) => t.clone(),
_ => -t.clone(),
})
.collect(),
)
}
fn project(&self, grade: &Form) -> Self::Output {
Self::Output::from_terms(
self.as_terms()
.iter()
.filter(|t| mem::discriminant(&t.form()) == mem::discriminant(grade))
.cloned()
.collect(),
)
}
fn hermitian(&self) -> Self::Output {
Self::Output::from_terms(
self.as_terms()
.iter()
.map(|t| match ar_product(&t.alpha(), &t.alpha()).sign() {
Sign::Neg => -t.clone(),
Sign::Pos => t.clone(),
})
.collect(),
)
}
fn dagger(&self) -> Self::Output {
self.hermitian()
}
fn diamond(&self) -> Self::Output {
Self::Output::from_terms(
self.as_terms()
.iter()
.map(|t| match t.form() {
Form::Point => t.clone(),
_ => -t.clone(),
})
.collect(),
)
}
fn double_dagger(&self) -> Self::Output {
Self::Output::from_terms(
self.as_terms()
.iter()
.map(|t| match t.form() {
Form::Bivector(_, _) => t.clone(),
_ => -t.clone(),
})
.collect(),
)
}
fn dual(&self) -> Self::Output {
let indices = [0, 1, 2, 3]
.iter()
.map(|n| Index::try_from_u8(*n).unwrap())
.collect();
let q = Term::new(None, Alpha::try_from_indices(Sign::Neg, &indices).unwrap());
Self::Output::from_terms(
self.as_terms()
.iter()
.map(|t| q.form_product_with(&t))
.collect(),
)
}
}
impl AR for Vec<Term> {
type Output = Self;
fn as_terms(&self) -> Vec<Term> {
self.clone()
}
fn from_terms(terms: Vec<Term>) -> Self {
terms
}
}
impl AR for Vec<Alpha> {
type Output = Self;
fn as_terms(&self) -> Vec<Term> {
self.iter().map(|a| Term::new(None, a.clone())).collect()
}
fn from_terms(terms: Vec<Term>) -> Self {
terms.iter().map(|t| t.alpha()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::algebra::{ar_product, Alpha, MultiVector, Term, ALLOWED_ALPHA_FORMS};
#[test]
fn hermitian_conjugation_is_correct_for_alphas() {
for c in ALLOWED_ALPHA_FORMS.iter() {
let alpha = Alpha::new(Sign::Pos, *c).unwrap();
let sign = ar_product(&alpha, &alpha).sign();
let conjugate = alpha.hermitian();
assert_eq!(conjugate, Alpha::new(sign, *c).unwrap());
}
}
#[test]
fn hermitian_conjugation_is_correct_for_terms() {
for c in ALLOWED_ALPHA_FORMS.iter() {
let alpha = Alpha::new(Sign::Pos, *c).unwrap();
let sign = ar_product(&alpha, &alpha).sign();
let term = Term::new(None, alpha.clone());
let conjugate = term.hermitian();
assert_eq!(conjugate, Term::new(None, Alpha::new(sign, *c).unwrap()));
}
}
#[test]
fn hermitian_conjugation_is_correct_for_multivectors() {
let mut terms: Vec<Term> = vec![];
let mut negated: Vec<Term> = vec![];
for c in ALLOWED_ALPHA_FORMS.iter() {
let alpha = Alpha::new(Sign::Pos, *c).unwrap();
let sign = ar_product(&alpha, &alpha).sign();
terms.push(Term::new(None, alpha));
negated.push(Term::new(None, Alpha::new(sign, *c).unwrap()));
}
let conjugate = MultiVector::from_terms(terms).hermitian();
assert_eq!(conjugate, MultiVector::from_terms(negated));
}
}