use std::{collections::HashMap, hash::Hash, mem, ops::Add};
use harness_algebra::{prelude::*, tensors::dynamic::vector::DynamicVector};
use crate::definitions::Topology;
#[derive(Clone, Debug)]
pub struct Chain<'a, T: Topology, R> {
pub space: &'a T,
pub items: Vec<T::Item>,
pub coefficients: Vec<R>,
}
impl<'a, T: Topology, R: Ring> Chain<'a, T, R> {
pub const fn new(space: &'a T) -> Self { Self { space, items: vec![], coefficients: vec![] } }
pub fn from_item_and_coeff(space: &'a T, item: T::Item, coeff: R) -> Self {
Self { space, items: vec![item], coefficients: vec![coeff] }
}
pub const fn from_items_and_coeffs(space: &'a T, items: Vec<T::Item>, coeffs: Vec<R>) -> Self {
Self { space, items, coefficients: coeffs }
}
pub fn boundary(&self) -> Self
where
R: Copy,
T::Item: PartialEq, {
let mut total_boundary = Chain::new(self.space);
for (item, coeff) in self.items.iter().zip(self.coefficients.iter()) {
let simplex_boundary_chain = self.space.boundary(item);
let scaled_simplex_boundary = simplex_boundary_chain * *coeff;
total_boundary = total_boundary + scaled_simplex_boundary;
}
total_boundary
}
pub fn to_coeff_vector(
&self,
basis_map: &HashMap<&T::Item, usize>,
basis_size: usize,
) -> DynamicVector<R>
where
T::Item: Hash + Eq,
R: Ring + Copy,
{
let mut coeffs = vec![R::zero(); basis_size];
for (item, coeff) in self.items.iter().zip(self.coefficients.iter()) {
if let Some(&idx) = basis_map.get(item) {
coeffs[idx] = *coeff;
}
}
DynamicVector::new(coeffs)
}
}
impl<T: Topology, R: PartialEq> PartialEq for Chain<'_, T, R>
where T::Item: PartialEq
{
fn eq(&self, other: &Self) -> bool {
let self_chain = self.coefficients.iter().zip(self.items.iter());
let other_chain = other.coefficients.iter().zip(other.items.iter());
self_chain
.zip(other_chain)
.all(|((coeff_a, item_a), (coeff_b, item_b))| coeff_a == coeff_b && item_a == item_b)
}
}
impl<T: Topology, R: Ring> Add for Chain<'_, T, R>
where T::Item: PartialEq
{
type Output = Self;
fn add(self, other: Self) -> Self::Output {
let mut result_items = Vec::new();
let mut result_coefficients: Vec<R> = Vec::new();
for (item_from_self, original_coeff_from_self) in
self.items.into_iter().zip(self.coefficients.into_iter())
{
let mut opt_coeff = Some(original_coeff_from_self);
let mut found_and_processed = false;
for (res_idx, res_item_ref) in result_items.iter().enumerate() {
if item_from_self == *res_item_ref {
if let Some(coeff_val) = opt_coeff.take() {
let current_res_coeff = mem::replace(&mut result_coefficients[res_idx], R::zero());
result_coefficients[res_idx] = current_res_coeff + coeff_val; }
found_and_processed = true;
break;
}
}
if !found_and_processed {
result_items.push(item_from_self); if let Some(coeff_val) = opt_coeff.take() {
result_coefficients.push(coeff_val); } else {
}
}
}
for (item_from_other, original_coeff_from_other) in
other.items.into_iter().zip(other.coefficients.into_iter())
{
let mut opt_coeff = Some(original_coeff_from_other);
let mut found_and_processed = false;
for (res_idx, res_item_ref) in result_items.iter().enumerate() {
if item_from_other == *res_item_ref {
if let Some(coeff_val) = opt_coeff.take() {
let current_res_coeff = mem::replace(&mut result_coefficients[res_idx], R::zero());
result_coefficients[res_idx] = current_res_coeff + coeff_val;
}
found_and_processed = true;
break;
}
}
if !found_and_processed {
result_items.push(item_from_other);
if let Some(coeff_val) = opt_coeff.take() {
result_coefficients.push(coeff_val);
} else {
}
}
}
let mut i = 0;
while i < result_coefficients.len() {
if result_coefficients[i].is_zero() {
result_coefficients.remove(i);
result_items.remove(i);
} else {
i += 1;
}
}
Self { space: self.space, items: result_items, coefficients: result_coefficients }
}
}
impl<T: Topology, R: Ring + Copy> Neg for Chain<'_, T, R>
where T::Item: PartialEq
{
type Output = Self;
fn neg(self) -> Self::Output {
Self {
space: self.space,
items: self.items,
coefficients: self.coefficients.iter().map(|c| -*c).collect(),
}
}
}
impl<T: Topology, R: Ring + Copy> Sub for Chain<'_, T, R>
where T::Item: PartialEq
{
type Output = Self;
fn sub(self, other: Self) -> Self::Output { self + (-other) }
}
impl<T, R> Mul<R> for Chain<'_, T, R>
where
T: Topology,
R: Ring + Copy,
T::Item: PartialEq,
{
type Output = Self;
fn mul(self, other: R) -> Self::Output {
Chain::from_items_and_coeffs(
self.space,
self.items,
self.coefficients.iter().map(|c| *c * other).collect(),
)
}
}
#[derive(Debug, Clone)]
pub struct Homology<R>
where R: Ring + Copy {
pub dimension: usize,
pub betti_number: usize,
pub homology_generators: Vec<DynamicVector<R>>,
}
impl<R> Homology<R>
where R: Ring + Copy
{
pub const fn trivial(dimension: usize) -> Self {
Self { dimension, betti_number: 0, homology_generators: Vec::new() }
}
}