use serde::{Deserialize, Serialize};
use serde_with::serde_as;
#[serde_as]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Simplex<const N: usize> {
#[serde_as(as = "[_; N]")]
pub neighbours: [usize; N],
#[serde_as(as = "[_; N]")]
pub vertices: [usize; N],
}
impl<const N: usize> Default for Simplex<N> {
fn default() -> Self {
Self {
neighbours: [0; N],
vertices: [0; N],
}
}
}
pub type Triangle = Simplex<3>;
pub type Simplex2 = Simplex<3>;
pub type Tetrahedron = Simplex<4>;
pub type Simplex3 = Simplex<4>;
pub type Simplex4 = Simplex<5>;
impl<const N: usize> Simplex<N> {
#[inline]
pub fn get_neighbour(&self, index: usize) -> usize {
let nbr = self.neighbours[index];
nbr / N
}
#[inline]
pub fn get_neighbour_backindex(&self, index: usize) -> (usize, usize) {
let nbr = self.neighbours[index];
(nbr / N, nbr % N)
}
#[inline]
pub fn get_neighbours(&self) -> [usize; N] {
let adjacent_edges = self.neighbours;
adjacent_edges.map(|nbr| nbr / N)
}
#[inline]
pub fn get_neighbours_backindices(&self) -> [(usize, usize); N] {
let adjacent_edges = self.neighbours;
adjacent_edges.map(|nbr| (nbr / N, nbr % N))
}
}
#[serde_as]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct CausalSimplex<K, const N: usize> {
pub t: u16,
pub kind: K,
#[serde_as(as = "[_; N]")]
pub neighbours: [usize; N],
#[serde_as(as = "[_; N]")]
pub vertices: [usize; N],
}
impl<K: Default, const N: usize> Default for CausalSimplex<K, N> {
fn default() -> Self {
Self {
t: u16::default(),
kind: K::default(),
neighbours: [0; N],
vertices: [0; N],
}
}
}
impl<K, const N: usize> CausalSimplex<K, N> {
#[inline]
pub fn get_neighbour(&self, index: usize) -> usize {
let nbr = self.neighbours[index];
nbr / N
}
#[inline]
pub fn get_neighbour_backindex(&self, index: usize) -> (usize, usize) {
let nbr = self.neighbours[index];
(nbr / N, nbr % N)
}
#[inline]
pub fn get_neighbours(&self) -> [usize; N] {
let adjacent_edges = self.neighbours;
adjacent_edges.map(|nbr| nbr / N)
}
#[inline]
pub fn get_neighbours_backindices(&self) -> [(usize, usize); N] {
let adjacent_edges = self.neighbours;
adjacent_edges.map(|nbr| (nbr / N, nbr % N))
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord, Serialize, Deserialize,
)]
pub enum CausalSimplex2Kind {
#[default]
S21 = 0,
S12 = 1,
}
pub type CausalTriangle = CausalSimplex<CausalSimplex2Kind, 3>;
pub type CausalSimplex2 = CausalSimplex<CausalSimplex2Kind, 3>;
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord, Serialize, Deserialize,
)]
pub enum CausalSimplex3Kind {
#[default]
S31 = 0,
S22 = 1,
S13 = 2,
}
pub type CausalTetrahedron = CausalSimplex<CausalSimplex3Kind, 4>;
pub type CausalSimplex3 = CausalSimplex<CausalSimplex3Kind, 4>;
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord, Serialize, Deserialize,
)]
pub enum CausalSimplex4Kind {
#[default]
S41 = 0,
S32 = 1,
S23 = 2,
S14 = 3,
}
pub type CausalSimplex4 = CausalSimplex<CausalSimplex4Kind, 5>;
impl<K, const N: usize> From<CausalSimplex<K, N>> for Simplex<N> {
fn from(value: CausalSimplex<K, N>) -> Self {
Self {
neighbours: value.neighbours,
vertices: value.vertices,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
pub enum CausalOrientation {
Past = 0,
#[default]
Space = 1,
Future = 2,
}
pub trait CausalSimplexKind {
fn orientation(&self) -> CausalOrientation;
fn signature(&self) -> (u8, u8);
}
impl CausalSimplexKind for CausalSimplex2Kind {
fn orientation(&self) -> CausalOrientation {
match self {
CausalSimplex2Kind::S21 => CausalOrientation::Past,
CausalSimplex2Kind::S12 => CausalOrientation::Future,
}
}
fn signature(&self) -> (u8, u8) {
match self {
CausalSimplex2Kind::S21 => (2, 1),
CausalSimplex2Kind::S12 => (1, 2),
}
}
}
impl CausalSimplexKind for CausalSimplex3Kind {
fn orientation(&self) -> CausalOrientation {
match self {
CausalSimplex3Kind::S31 => CausalOrientation::Past,
CausalSimplex3Kind::S22 => CausalOrientation::Space,
CausalSimplex3Kind::S13 => CausalOrientation::Future,
}
}
fn signature(&self) -> (u8, u8) {
match self {
CausalSimplex3Kind::S31 => (3, 1),
CausalSimplex3Kind::S22 => (2, 2),
CausalSimplex3Kind::S13 => (1, 3),
}
}
}
impl CausalSimplexKind for CausalSimplex4Kind {
fn orientation(&self) -> CausalOrientation {
match self {
CausalSimplex4Kind::S41 => CausalOrientation::Past,
CausalSimplex4Kind::S32 => CausalOrientation::Space,
CausalSimplex4Kind::S23 => CausalOrientation::Space,
CausalSimplex4Kind::S14 => CausalOrientation::Future,
}
}
fn signature(&self) -> (u8, u8) {
match self {
CausalSimplex4Kind::S41 => (4, 1),
CausalSimplex4Kind::S32 => (3, 2),
CausalSimplex4Kind::S23 => (2, 3),
CausalSimplex4Kind::S14 => (1, 4),
}
}
}
pub(crate) fn canonical_simplex<T: Ord, const N: usize>(mut simplex: [T; N]) -> [T; N] {
simplex.sort();
simplex
}
pub(crate) fn canonical_oriented_simplex<T: Ord, const N: usize>(
mut simplex: [T; N],
) -> (bool, [T; N]) {
let mut parity = true;
loop {
let mut unchanged = true;
for i in 0..(N - 1) {
if simplex[i] > simplex[i + 1] {
parity = !parity;
simplex.swap(i, i + 1);
unchanged = false;
}
}
if unchanged {
break;
}
}
(parity, simplex)
}
#[cfg(test)]
mod tests {
use crate::triangulation::simplices::canonical_oriented_simplex;
#[test]
fn test_canonical_oriented_simplex() {
assert_eq!(
canonical_oriented_simplex([0, 1, 2, 3, 4]),
(true, [0, 1, 2, 3, 4])
);
assert_eq!(
canonical_oriented_simplex([1, 0, 2, 3, 4]),
(false, [0, 1, 2, 3, 4])
);
assert_eq!(
canonical_oriented_simplex([3, 1, 2, 0, 4]),
(false, [0, 1, 2, 3, 4])
);
assert_eq!(
canonical_oriented_simplex([4, 1, 2, 3, 0]),
(false, [0, 1, 2, 3, 4])
);
assert_eq!(
canonical_oriented_simplex([1, 3, 0, 4, 2]),
(true, [0, 1, 2, 3, 4])
);
}
}