use crate::error::KohoError;
pub struct Cell {
pub dimension: usize,
pub upper: Vec<usize>,
pub lower: Vec<usize>,
}
impl Cell {
pub fn new(dimension: usize) -> Self {
Self {
dimension,
upper: Vec::new(),
lower: Vec::new(),
}
}
fn attach(
&mut self,
skeleton: &mut Skeleton,
upper: Option<&[usize]>,
lower: Option<&[usize]>,
) {
while skeleton.cells.len() <= self.dimension {
skeleton.cells.push(Vec::new());
}
let max = skeleton.cells[self.dimension].len();
if let Some(upper) = upper {
for i in upper {
while skeleton.cells.len() <= self.dimension + 1 {
skeleton.cells.push(Vec::new());
}
skeleton.cells[self.dimension + 1][*i].lower.push(max);
self.upper.push(*i);
}
}
if let Some(lower) = lower {
for i in lower {
skeleton.cells[self.dimension - 1][*i].upper.push(max);
self.lower.push(*i);
}
}
}
}
pub struct Skeleton {
pub dimension: usize,
pub cells: Vec<Vec<Cell>>,
}
impl Skeleton {
pub fn init() -> Self {
Self {
dimension: 0,
cells: vec![Vec::new()],
}
}
pub fn attach(
&mut self,
mut cell: Cell,
upper: Option<&[usize]>,
lower: Option<&[usize]>,
) -> Result<usize, KohoError> {
let incoming_dim = cell.dimension as i64;
if incoming_dim - self.dimension as i64 > 1 {
return Err(KohoError::DimensionMismatch);
}
cell.attach(self, upper, lower);
if cell.dimension < self.cells.len() {
self.cells[cell.dimension].push(cell);
}
if incoming_dim > self.dimension as i64 {
self.dimension = incoming_dim as usize
}
Ok(self.cells[incoming_dim as usize].len() - 1)
}
pub fn incidences(
&self,
k: usize,
cell_idx: usize,
) -> Result<(&Vec<usize>, &Vec<usize>), KohoError> {
if k >= self.cells.len() {
return Err(KohoError::DimensionMismatch);
}
if cell_idx >= self.cells[k].len() {
return Err(KohoError::InvalidCellIdx);
}
let upper = &self.cells[k][cell_idx].upper;
let lower = &self.cells[k][cell_idx].lower;
Ok((upper, lower))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_attach_zero_cells() {
let mut sk = Skeleton::init();
let idx = sk.attach(Cell::new(0), None, None).unwrap();
assert_eq!(idx, 0, "Index for first 0-cell should be 1");
assert_eq!(
sk.cells[0].len(),
1,
"There should be one 0-cell in the skeleton"
);
}
#[test]
fn test_incidences_empty_and_invalid() {
let sk = Skeleton::init();
let err = sk.incidences(0, 0).unwrap_err();
assert!(matches!(err, KohoError::InvalidCellIdx));
let err = sk.incidences(1, 0).unwrap_err();
assert!(matches!(err, KohoError::DimensionMismatch));
}
#[test]
fn test_dimension_mismatch_on_attach() {
let mut sk = Skeleton::init();
let err = sk.attach(Cell::new(2), None, None).unwrap_err();
assert!(matches!(err, KohoError::DimensionMismatch));
}
#[test]
fn test_attach_edge_and_incidence_relations() {
let mut sk = Skeleton::init();
sk.attach(Cell::new(0), None, None).unwrap(); sk.attach(Cell::new(0), None, None).unwrap(); assert_eq!(sk.cells[0].len(), 2, "There should be two 0-cells");
let e_idx = sk.attach(Cell::new(1), None, Some(&[0, 1])).unwrap();
assert_eq!(e_idx, 0, "Index for first 1-cell should be 0");
assert_eq!(sk.cells[1].len(), 1, "There should be one 1-cell");
let edge = &sk.cells[1][0];
assert_eq!(
edge.lower,
vec![0, 1],
"Edge should be incident to vertices 0 and 1"
);
assert_eq!(
sk.cells[0][0].upper,
vec![0],
"Vertex 0 should have edge 0 in its upper incidences"
);
assert_eq!(
sk.cells[0][1].upper,
vec![0],
"Vertex 1 should have edge 0 in its upper incidences"
);
let (upper, _lower) = sk.incidences(0, 0).unwrap();
assert_eq!(
upper,
&[0],
"Upper incidences of vertex 0 should contain the edge"
);
}
#[test]
fn test_invalid_cell_idx_in_incidences() {
let mut sk = Skeleton::init();
sk.attach(Cell::new(0), None, None).unwrap();
let err = sk.incidences(0, 1).unwrap_err();
assert!(matches!(err, KohoError::InvalidCellIdx));
}
}