use std::hash::Hash;
use indexmap::IndexSet;
use crate::triangulation::simplices::{canonical_oriented_simplex, canonical_simplex};
use crate::triangulation::{Triangulation2D, Triangulation3D, Triangulation4D};
use narray::NArray;
pub trait FaceSimplex: NArray<Item = usize> {
type Boundary: NArray<Item = usize> + Copy;
type Boundaries: NArray<Item = Self::Boundary>;
const BOUNDARIES: Self::Boundaries;
}
pub type Face<S> = <<S as FaceSimplex>::Boundary as NArray>::MapOutput<usize>;
pub type AllFaces<S> = <<S as FaceSimplex>::Boundaries as NArray>::MapOutput<Face<S>>;
pub fn get_face<S: FaceSimplex>(simplex: S, idx: usize) -> Face<S> {
S::BOUNDARIES[idx].map(move |i| simplex[i])
}
pub fn get_faces<S: FaceSimplex>(simplex: S) -> AllFaces<S> {
S::BOUNDARIES.map(|face| face.map(|i| simplex[i]))
}
macro_rules! impl_face_simplex {
($dim:literal, $boundary:expr) => {
impl FaceSimplex for [usize; $dim + 1] {
type Boundary = [usize; $dim];
type Boundaries = [[usize; $dim]; $dim + 1];
const BOUNDARIES: Self::Boundaries = $boundary;
}
};
}
impl_face_simplex!(1, [[1], [0]]);
impl_face_simplex!(2, [[1, 2], [0, 2], [0, 1]]);
impl_face_simplex!(3, [[1, 2, 3], [0, 2, 3], [0, 1, 3], [0, 1, 2]]);
impl_face_simplex!(
4,
[
[1, 2, 3, 4],
[0, 2, 3, 4],
[0, 1, 3, 4],
[0, 1, 2, 4],
[0, 1, 2, 3],
]
);
type MappedFaces<S> = <AllFaces<S> as NArray>::MapOutput<Boundary>;
pub fn compute_boundary_map<S, I>(simplices: I) -> (Vec<Face<S>>, Vec<MappedFaces<S>>)
where
S: FaceSimplex,
Face<S>: CanonicalSimplex + Hash + Eq,
I: Iterator<Item = S>,
{
let mut facemap = IndexSet::new();
let boundary_map = simplices
.map(|simplex| {
let mut sign = true;
get_faces(simplex).map(|face| {
let (orientation, face) = face.make_canonical_oriented();
let label = facemap.insert_full(face).0;
let bound = Boundary::new(label, !(orientation ^ sign));
sign = !sign;
bound
})
})
.collect();
let faces = facemap.into_iter().collect();
(faces, boundary_map)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Parity {
Negative,
Positive,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Boundary {
pub parity: Parity,
pub idx: usize,
}
impl Boundary {
pub fn new(idx: usize, parity: bool) -> Self {
Self {
parity: if parity {
Parity::Positive
} else {
Parity::Negative
},
idx,
}
}
}
pub trait CanonicalSimplex {
fn make_canonical(self) -> Self;
fn make_canonical_oriented(self) -> (bool, Self);
}
impl<T: Ord, const N: usize> CanonicalSimplex for [T; N] {
fn make_canonical(self) -> Self {
canonical_simplex(self)
}
fn make_canonical_oriented(self) -> (bool, [T; N]) {
canonical_oriented_simplex(self)
}
}
pub type BoundaryMap<const N: usize> = Vec<[Boundary; N]>;
impl Triangulation2D {
pub fn boundary_maps(&self) -> (BoundaryMap<2>, BoundaryMap<3>) {
let simplices2_iter = self.simplices.iter().map(|simplex| simplex.vertices);
let (simplices1, boundmap2) = compute_boundary_map(simplices2_iter);
let (_, boundmap1) = compute_boundary_map(simplices1.into_iter());
(boundmap1, boundmap2)
}
}
impl Triangulation3D {
pub fn boundary_maps(&self) -> (BoundaryMap<2>, BoundaryMap<3>, BoundaryMap<4>) {
let simplices3_iter = self.simplices.iter().map(|simplex| simplex.vertices);
let (simplices2, boundmap3) = compute_boundary_map(simplices3_iter);
let (simplices1, boundmap2) = compute_boundary_map(simplices2.into_iter());
let (_, boundmap1) = compute_boundary_map(simplices1.into_iter());
(boundmap1, boundmap2, boundmap3)
}
}
impl Triangulation4D {
pub fn boundary_maps(
&self,
) -> (
BoundaryMap<2>,
BoundaryMap<3>,
BoundaryMap<4>,
BoundaryMap<5>,
) {
let simplices4_iter = self.simplices.iter().map(|simplex| simplex.vertices);
let (simplices3, boundmap4) = compute_boundary_map(simplices4_iter);
let (simplices2, boundmap3) = compute_boundary_map(simplices3.into_iter());
let (simplices1, boundmap2) = compute_boundary_map(simplices2.into_iter());
let (_, boundmap1) = compute_boundary_map(simplices1.into_iter());
(boundmap1, boundmap2, boundmap3, boundmap4)
}
}
mod narray {
use std::ops::Index;
pub trait NArray:
Sized
+ Index<usize, Output = <Self as NArray>::Item>
+ IntoIterator<Item = <Self as NArray>::Item>
{
type Item;
type MapOutput<U>: NArray<Item = U>;
fn map<U, F: FnMut(<Self as NArray>::Item) -> U>(self, f: F) -> Self::MapOutput<U>;
}
impl<T, const N: usize> NArray for [T; N] {
type Item = T;
type MapOutput<U> = [U; N];
fn map<U, F: FnMut(T) -> U>(self, f: F) -> [U; N] {
self.map(f)
}
}
}