use std::marker::PhantomData;
use linnet::permutation::Permutation;
use tabled::{builder::Builder, settings::Style};
use super::{
abstract_index::AbstractIndex,
dimension::Dimension,
named::{ArgDisplay, IdentityName},
permuted::PermuteTensor,
representation::{LibraryRep, RepName, Representation},
slot::{AbsInd, IsAbstractSlot, Slot},
HasName, NamedStructure, OrderedStructure, PermutedStructure, ScalarStructure,
SmartShadowStructure, StructureError, TensorStructure,
};
use anyhow::{anyhow, Result};
use delegate::delegate;
use crate::network::StructureLessDisplay;
#[cfg(feature = "shadowing")]
use crate::{
shadowing::symbolica_utils::IntoSymbol,
structure::ToSymbolic,
tensors::parametric::{ExpandedCoefficent, TensorCoefficient},
};
#[cfg(feature = "shadowing")]
use crate::{structure::FlatIndex, tensors::data::DenseTensor};
#[cfg(not(feature = "shadowing"))]
use serde::{Deserialize, Serialize};
#[cfg(feature = "shadowing")]
use symbolica::atom::{Atom, FunctionBuilder, Symbol};
#[derive(
Clone, PartialEq, Eq, Default, Hash, bincode_trait_derive::Encode, bincode_trait_derive::Decode,
)]
#[cfg_attr(not(feature = "shadowing"), derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "shadowing",
trait_decode(trait = symbolica::state::HasStateMap),
)]
pub struct IndexLess<T: RepName = LibraryRep, Aind = AbstractIndex> {
pub structure: Vec<Representation<T>>,
ind: PhantomData<Aind>,
}
impl<T: RepName, Aind> StructureLessDisplay for IndexLess<T, Aind> {
fn display(&self) -> String {
String::new()
}
}
impl<R: RepName<Dual = R>, Aind: AbsInd> PermuteTensor for IndexLess<R, Aind> {
type Id = Self;
type Permuted = (IndexLess<LibraryRep>, Vec<IndexLess<LibraryRep, Aind>>);
type IdSlot = Slot<R, Aind>;
fn permute_inds(self, _permutation: &Permutation) -> Self::Permuted {
todo!()
}
fn permute_reps(self, _rep_perm: &Permutation) -> Self::Permuted {
todo!()
}
fn id(i: Slot<R, Aind>, j: Slot<R, Aind>) -> Self::Id {
if i.dim() == j.dim() {
IndexLess::new(vec![i.rep, j.rep])
} else {
panic!("Not same dimension for ID")
}
}
}
impl<R: RepName, Aind> std::fmt::Display for IndexLess<R, Aind> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut table = Builder::new();
table.push_record(&["".to_string()]);
for item in self.structure.iter() {
table.push_record(&[item.rep.to_string(), item.dim.to_string()]);
}
writeln!(f)?;
table.build().with(Style::rounded()).fmt(f)
}
}
impl<R: RepName, Aind> std::fmt::Debug for IndexLess<R, Aind> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut table = Builder::new();
table.push_record(&["IndexLess".to_string()]);
for (index, item) in self.structure.iter().enumerate() {
table.push_record(&[
index.to_string(),
format!("{:?}", item.rep),
format!("{:?}", item.dim),
]);
}
writeln!(f)?;
write!(f, "{}", table.build().with(Style::rounded()))
}
}
impl<R: RepName, Aind> FromIterator<Representation<R>> for PermutedStructure<IndexLess<R, Aind>> {
fn from_iter<I: IntoIterator<Item = Representation<R>>>(iter: I) -> Self {
let structure: Vec<_> = iter.into_iter().collect();
structure.into()
}
}
impl<R: RepName, Aind> From<Vec<Representation<R>>> for PermutedStructure<IndexLess<R, Aind>> {
fn from(mut structure: Vec<Representation<R>>) -> Self {
let permutation = Permutation::sort(&structure);
permutation.apply_slice_in_place(&mut structure);
PermutedStructure {
rep_permutation: permutation,
index_permutation: Permutation::id(structure.len()),
structure: IndexLess {
structure,
ind: PhantomData,
},
}
}
}
impl<R: RepName, Aind> From<OrderedStructure<R, Aind>> for IndexLess<R, Aind> {
fn from(structure: OrderedStructure<R, Aind>) -> Self {
IndexLess {
structure: structure.into_iter().map(|a| a.rep).collect(),
ind: PhantomData,
}
}
}
impl<N, A, R: RepName, Aind> From<NamedStructure<N, A, R, Aind>> for IndexLess<R, Aind> {
fn from(structure: NamedStructure<N, A, R, Aind>) -> Self {
structure.structure.into()
}
}
impl<N, A, R: RepName, Aind> From<IndexlessNamedStructure<N, A, R, Aind>> for IndexLess<R, Aind> {
fn from(structure: IndexlessNamedStructure<N, A, R, Aind>) -> Self {
structure.structure
}
}
impl<N, A, R: RepName, Aind: AbsInd> From<SmartShadowStructure<N, A, R, Aind>>
for IndexLess<R, Aind>
{
fn from(structure: SmartShadowStructure<N, A, R, Aind>) -> Self {
structure.structure.into()
}
}
impl<T: RepName, Aind: AbsInd> IndexLess<T, Aind> {
pub fn new(structure: Vec<Representation<T>>) -> Self {
Self {
structure,
ind: PhantomData,
}
}
pub fn empty() -> Self {
Self {
structure: vec![],
ind: PhantomData,
}
}
pub fn to_indexed(self, indices: &[Aind]) -> Result<Vec<Slot<T, Aind>>, StructureError> {
if self.structure.len() != indices.len() {
return Err(StructureError::WrongNumberOfArguments(
indices.len(),
self.structure.len(),
));
}
Ok(indices
.iter()
.cloned()
.zip(self.structure.iter().cloned())
.map(|(i, r)| Representation::slot(&r, i))
.collect())
}
}
impl<T: RepName<Dual = T>, Aind: AbsInd> ScalarStructure for IndexLess<T, Aind> {
fn scalar_structure() -> Self {
Self::empty()
}
}
impl<T: RepName<Dual = T>, Aind: AbsInd> TensorStructure for IndexLess<T, Aind> {
type Slot = Slot<T, Aind>;
type Indexed = OrderedStructure<T, Aind>;
fn is_fully_self_dual(&self) -> bool {
self.structure.iter().all(|r| r.rep.is_self_dual())
}
fn reindex(
self,
indices: &[Aind],
) -> Result<PermutedStructure<OrderedStructure<T, Aind>>, StructureError> {
if self.structure.len() != indices.len() {
return Err(StructureError::WrongNumberOfArguments(
indices.len(),
self.structure.len(),
));
}
Ok(indices
.iter()
.cloned()
.zip(self.structure.iter().cloned())
.map(|(i, r)| Representation::slot(&r, i))
.collect())
}
fn dual(self) -> Self {
self.structure
.into_iter()
.map(|r| r.dual())
.collect::<PermutedStructure<_>>()
.structure
}
fn external_reps_iter(
&self,
) -> impl Iterator<Item = Representation<<Self::Slot as IsAbstractSlot>::R>> {
self.structure.iter().copied()
}
fn external_dims_iter(&self) -> impl Iterator<Item = Dimension> {
self.structure.iter().map(|s| s.dim)
}
fn get_aind(&self, _: usize) -> Option<Aind> {
None
}
fn external_indices_iter(&self) -> impl Iterator<Item = Aind> {
[].iter().cloned()
}
fn external_structure_iter(&self) -> impl Iterator<Item = Self::Slot> {
[].iter().cloned()
}
fn order(&self) -> usize {
self.structure.len()
}
fn get_slot(&self, _: usize) -> Option<Self::Slot> {
None
}
fn find_permutation(&self, other: &Self) -> Result<Permutation> {
if self.order() != other.order() {
return Err(anyhow!(
"Mismatched order: {} vs {}",
self.order(),
other.order()
));
}
let other_structure = &other.structure;
let self_structure = &self.structure;
let other_sort = Permutation::sort(other_structure);
let self_sort = Permutation::sort(self_structure);
if other_sort.apply_slice(other_structure) == self_sort.apply_slice(self_structure) {
Ok(other_sort.compose(&self_sort.inverse()))
} else {
Err(anyhow!("Mismatched structure"))
}
}
fn get_rep(&self, i: usize) -> Option<Representation<<Self::Slot as IsAbstractSlot>::R>> {
self.structure.get(i).copied()
}
fn get_dim(&self, i: usize) -> Option<Dimension> {
self.structure.get(i).map(|&r| r.into())
}
}
#[cfg(feature = "shadowing")]
impl<T: RepName<Dual = T>, Aind: AbsInd> ToSymbolic for IndexLess<T, Aind> {
fn concrete_atom(&self, id: FlatIndex) -> ExpandedCoefficent<()> {
ExpandedCoefficent {
name: None,
index: self.co_expanded_index(id).unwrap(),
args: None,
}
}
fn to_dense_labeled<R>(
self,
index_to_atom: impl Fn(&Self, FlatIndex) -> R,
) -> Result<DenseTensor<Atom, Self>>
where
Self: Sized,
R: TensorCoefficient,
{
let mut data = vec![];
for index in 0..self.size()? {
data.push(index_to_atom(&self, index.into()).to_atom().unwrap());
}
Ok(DenseTensor {
data,
structure: self,
})
}
fn to_dense_labeled_complex<R>(
self,
index_to_atom: impl Fn(&Self, FlatIndex) -> R,
) -> Result<DenseTensor<Atom, Self>>
where
Self: Sized,
R: TensorCoefficient,
{
let mut data = vec![];
for index in 0..self.size()? {
let re = index_to_atom(&self, index.into()).to_atom_re().unwrap();
let im = index_to_atom(&self, index.into()).to_atom_im().unwrap();
let i = Atom::i();
data.push(&re + i * &im);
}
Ok(DenseTensor {
data,
structure: self,
})
}
fn to_symbolic_with(&self, name: Symbol, args: &[Atom], perm: Option<Permutation>) -> Atom {
let mut slots = self
.external_reps_iter()
.map(|slot| slot.to_symbolic([]))
.collect::<Vec<_>>();
if let Some(p) = perm {
p.apply_slice_in_place(&mut slots);
}
FunctionBuilder::new(name.ref_into_symbol())
.add_args(args)
.add_args(&slots)
.finish()
}
}
#[derive(
Clone, PartialEq, Eq, Default, Hash, bincode_trait_derive::Encode, bincode_trait_derive::Decode,
)]
#[cfg_attr(not(feature = "shadowing"), derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "shadowing",
trait_decode(trait = symbolica::state::HasStateMap),
)]
pub struct IndexlessNamedStructure<
Name = String,
Args = usize,
R: RepName = LibraryRep,
Aind = AbstractIndex,
> {
pub structure: IndexLess<R, Aind>,
pub global_name: Option<Name>,
pub additional_args: Option<Args>,
}
impl<N: IdentityName, A, R: RepName<Dual = R>, Aind: AbsInd> PermuteTensor
for IndexlessNamedStructure<N, A, R, Aind>
{
type Id = Self;
type IdSlot = Slot<R, Aind>;
type Permuted = (
IndexlessNamedStructure<N, A, LibraryRep, Aind>,
Vec<IndexlessNamedStructure<N, A, LibraryRep, Aind>>,
);
fn id(i: Self::IdSlot, j: Self::IdSlot) -> Self::Id {
Self {
structure: IndexLess::id(i, j),
global_name: Some(N::id()),
additional_args: None,
}
}
fn permute_inds(self, _permutation: &Permutation) -> Self::Permuted {
todo!()
}
fn permute_reps(self, _rep_perm: &Permutation) -> Self::Permuted {
todo!()
}
}
impl<Name, Args, R: RepName<Dual = R>, Aind: AbsInd> TensorStructure
for IndexlessNamedStructure<Name, Args, R, Aind>
{
type Slot = Slot<R, Aind>;
type Indexed = NamedStructure<Name, Args, R, Aind>;
fn reindex(
self,
indices: &[Aind],
) -> Result<PermutedStructure<NamedStructure<Name, Args, R, Aind>>, StructureError> {
let res = self.structure.reindex(indices)?;
Ok(PermutedStructure {
rep_permutation: Permutation::id(res.structure.order()),
structure: NamedStructure {
global_name: self.global_name,
additional_args: self.additional_args,
structure: res.structure,
},
index_permutation: res.index_permutation,
})
}
fn dual(self) -> Self {
Self {
structure: self.structure.dual(),
global_name: self.global_name,
additional_args: self.additional_args,
}
}
delegate! {
to self.structure{
fn is_fully_self_dual(&self) -> bool;
fn external_reps_iter(&self) -> impl Iterator<Item = Representation<<Self::Slot as IsAbstractSlot>::R>>;
fn external_indices_iter(&self) -> impl Iterator<Item = Aind>;
fn external_dims_iter(&self)->impl Iterator<Item=Dimension>;
fn external_structure_iter(&self) -> impl Iterator<Item = Self::Slot>;
fn order(&self) -> usize;
fn get_slot(&self, i: usize) -> Option<Self::Slot>;
fn get_rep(&self, i: usize) -> Option<Representation<<Self::Slot as IsAbstractSlot>::R>>;
fn get_aind(&self,i:usize)->Option<Aind>;
fn get_dim(&self, i: usize) -> Option<Dimension>;
}
}
}
impl<N, A, T: RepName<Dual = T>, Aind: AbsInd> ScalarStructure
for IndexlessNamedStructure<N, A, T, Aind>
{
fn scalar_structure() -> Self {
IndexlessNamedStructure {
structure: IndexLess::scalar_structure(),
global_name: None,
additional_args: None,
}
}
}
impl<Name, Args, R: RepName, Aind> IndexlessNamedStructure<Name, Args, R, Aind> {
#[must_use]
pub fn from_iter<I, T>(iter: T, name: Name, args: Option<Args>) -> PermutedStructure<Self>
where
I: RepName,
R: From<I>,
T: IntoIterator<Item = Representation<I>>,
{
iter.into_iter()
.map(|a| a.cast())
.collect::<PermutedStructure<_>>()
.map_structure(move |structure| Self {
structure,
global_name: Some(name),
additional_args: args,
})
}
}
impl<N, A, R: RepName, Aind> HasName for IndexlessNamedStructure<N, A, R, Aind>
where
N: Clone,
A: Clone,
{
type Name = N;
type Args = A;
fn name(&self) -> Option<Self::Name> {
self.global_name.clone()
}
fn set_name(&mut self, name: Self::Name) {
self.global_name = Some(name);
}
fn args(&self) -> Option<Self::Args> {
self.additional_args.clone()
}
}
impl<N, A, R: RepName, Aind> From<IndexLess<R, Aind>> for IndexlessNamedStructure<N, A, R, Aind> {
fn from(value: IndexLess<R, Aind>) -> Self {
IndexlessNamedStructure {
structure: value,
global_name: None,
additional_args: None,
}
}
}
impl<N, A, R: RepName, Aind> From<NamedStructure<N, A, R, Aind>>
for IndexlessNamedStructure<N, A, R, Aind>
{
fn from(value: NamedStructure<N, A, R, Aind>) -> Self {
IndexlessNamedStructure {
structure: value.structure.into(),
global_name: value.global_name,
additional_args: value.additional_args,
}
}
}
impl<N: std::fmt::Display, A: ArgDisplay, R: RepName, Aind> std::fmt::Display
for IndexlessNamedStructure<N, A, R, Aind>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut table = Builder::new();
table.push_record(&[
self.global_name
.as_ref()
.map(|a| format!("{}", a))
.unwrap_or("NO NAME".to_string()),
self.additional_args
.as_ref()
.map(|a| a.arg_display())
.unwrap_or("".to_string()),
]);
for item in self.structure.structure.iter() {
table.push_record(&[item.rep.to_string(), item.dim.to_string()]);
}
writeln!(f)?;
table.build().with(Style::rounded()).fmt(f)
}
}
impl<N: std::fmt::Debug, A: ArgDisplay, R: RepName, Aind> std::fmt::Debug
for IndexlessNamedStructure<N, A, R, Aind>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut table = Builder::new();
table.push_record(&[
self.global_name
.as_ref()
.map(|a| format!("{:?}", a))
.unwrap_or("NO NAME".to_string()),
self.additional_args
.as_ref()
.map(|a| a.arg_debug())
.unwrap_or("".to_string()),
]);
for (index, item) in self.structure.structure.iter().enumerate() {
table.push_record(&[
index.to_string(),
format!("{:?}", item.rep),
format!("{:?}", item.dim),
]);
}
writeln!(f)?;
write!(f, "{}", table.build().with(Style::rounded()))
}
}