Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!(core): add new variants to OrbitPolicy #238

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 42 additions & 22 deletions honeycomb-core/src/attributes/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ use std::{any::TypeId, collections::HashMap};
macro_rules! get_storage {
($slf: ident, $id: ident) => {
let probably_storage = match A::BIND_POLICY {
OrbitPolicy::Vertex => $slf.vertices.get(&TypeId::of::<A>()),
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
$slf.vertices.get(&TypeId::of::<A>())
}
OrbitPolicy::Edge => $slf.edges.get(&TypeId::of::<A>()),
OrbitPolicy::Face => $slf.faces.get(&TypeId::of::<A>()),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => $slf.faces.get(&TypeId::of::<A>()),
OrbitPolicy::Custom(_) => $slf.others.get(&TypeId::of::<A>()),
};
let $id = probably_storage
Expand All @@ -35,9 +37,11 @@ macro_rules! get_storage {
macro_rules! get_storage_mut {
($slf: ident, $id: ident) => {
let probably_storage = match A::BIND_POLICY {
OrbitPolicy::Vertex => $slf.vertices.get_mut(&TypeId::of::<A>()),
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
$slf.vertices.get_mut(&TypeId::of::<A>())
}
OrbitPolicy::Edge => $slf.edges.get_mut(&TypeId::of::<A>()),
OrbitPolicy::Face => $slf.faces.get_mut(&TypeId::of::<A>()),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => $slf.faces.get_mut(&TypeId::of::<A>()),
OrbitPolicy::Custom(_) => $slf.others.get_mut(&TypeId::of::<A>()),
};
let $id = probably_storage
Expand Down Expand Up @@ -162,9 +166,13 @@ impl AttrStorageManager {
let typeid = TypeId::of::<A>();
let new_storage = <A as AttributeBind>::StorageType::new(size);
if match A::BIND_POLICY {
OrbitPolicy::Vertex => self.vertices.insert(typeid, Box::new(new_storage)),
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.vertices.insert(typeid, Box::new(new_storage))
}
OrbitPolicy::Edge => self.edges.insert(typeid, Box::new(new_storage)),
OrbitPolicy::Face => self.faces.insert(typeid, Box::new(new_storage)),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.faces.insert(typeid, Box::new(new_storage))
}
OrbitPolicy::Custom(_) => self.others.insert(typeid, Box::new(new_storage)),
}
.is_some()
Expand Down Expand Up @@ -212,9 +220,9 @@ impl AttrStorageManager {
#[must_use = "unused getter result - please remove this method call"]
pub fn get_storage<A: AttributeBind>(&self) -> Option<&<A as AttributeBind>::StorageType> {
let probably_storage = match A::BIND_POLICY {
OrbitPolicy::Vertex => &self.vertices[&TypeId::of::<A>()],
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => &self.vertices[&TypeId::of::<A>()],
OrbitPolicy::Edge => &self.edges[&TypeId::of::<A>()],
OrbitPolicy::Face => &self.faces[&TypeId::of::<A>()],
OrbitPolicy::Face | OrbitPolicy::FaceLinear => &self.faces[&TypeId::of::<A>()],
OrbitPolicy::Custom(_) => &self.others[&TypeId::of::<A>()],
};
probably_storage.downcast_ref::<<A as AttributeBind>::StorageType>()
Expand All @@ -231,9 +239,11 @@ impl AttrStorageManager {
pub fn remove_storage<A: AttributeBind>(&mut self) {
// we could return it ?
let _ = match A::BIND_POLICY {
OrbitPolicy::Vertex => &self.vertices.remove(&TypeId::of::<A>()),
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
&self.vertices.remove(&TypeId::of::<A>())
}
OrbitPolicy::Edge => &self.edges.remove(&TypeId::of::<A>()),
OrbitPolicy::Face => &self.faces.remove(&TypeId::of::<A>()),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => &self.faces.remove(&TypeId::of::<A>()),
OrbitPolicy::Custom(_) => &self.others.remove(&TypeId::of::<A>()),
};
}
Expand All @@ -256,9 +266,13 @@ impl AttrStorageManager {
id_in_rhs: DartIdType,
) {
match orbit_policy {
OrbitPolicy::Vertex => self.force_merge_vertex_attributes(id_out, id_in_lhs, id_in_rhs),
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.force_merge_vertex_attributes(id_out, id_in_lhs, id_in_rhs);
}
OrbitPolicy::Edge => self.force_merge_edge_attributes(id_out, id_in_lhs, id_in_rhs),
OrbitPolicy::Face => self.force_merge_face_attributes(id_out, id_in_lhs, id_in_rhs),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.force_merge_face_attributes(id_out, id_in_lhs, id_in_rhs);
}
OrbitPolicy::Custom(_) => unimplemented!(),
}
}
Expand Down Expand Up @@ -335,11 +349,13 @@ impl AttrStorageManager {
id_in_rhs: DartIdType,
) -> StmResult<()> {
match orbit_policy {
OrbitPolicy::Vertex => {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.merge_vertex_attributes(trans, id_out, id_in_lhs, id_in_rhs)
}
OrbitPolicy::Edge => self.merge_edge_attributes(trans, id_out, id_in_lhs, id_in_rhs),
OrbitPolicy::Face => self.merge_face_attributes(trans, id_out, id_in_lhs, id_in_rhs),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.merge_face_attributes(trans, id_out, id_in_lhs, id_in_rhs)
}
OrbitPolicy::Custom(_) => unimplemented!(),
}
}
Expand Down Expand Up @@ -448,13 +464,13 @@ impl AttrStorageManager {
id_in_rhs: DartIdType,
) -> CMapResult<()> {
match orbit_policy {
OrbitPolicy::Vertex => {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.try_merge_vertex_attributes(trans, id_out, id_in_lhs, id_in_rhs)
}
OrbitPolicy::Edge => {
self.try_merge_edge_attributes(trans, id_out, id_in_lhs, id_in_rhs)
}
OrbitPolicy::Face => {
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.try_merge_face_attributes(trans, id_out, id_in_lhs, id_in_rhs)
}
OrbitPolicy::Custom(_) => unimplemented!(),
Expand Down Expand Up @@ -637,11 +653,13 @@ impl AttrStorageManager {
id_in: DartIdType,
) {
match orbit_policy {
OrbitPolicy::Vertex => {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.force_split_vertex_attributes(id_out_lhs, id_out_rhs, id_in);
}
OrbitPolicy::Edge => self.force_split_edge_attributes(id_out_lhs, id_out_rhs, id_in),
OrbitPolicy::Face => self.force_split_face_attributes(id_out_lhs, id_out_rhs, id_in),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.force_split_face_attributes(id_out_lhs, id_out_rhs, id_in);
}
OrbitPolicy::Custom(_) => unimplemented!(),
}
}
Expand Down Expand Up @@ -721,11 +739,13 @@ impl AttrStorageManager {
id_in: DartIdType,
) -> StmResult<()> {
match orbit_policy {
OrbitPolicy::Vertex => {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.split_vertex_attributes(trans, id_out_lhs, id_out_rhs, id_in)
}
OrbitPolicy::Edge => self.split_edge_attributes(trans, id_out_lhs, id_out_rhs, id_in),
OrbitPolicy::Face => self.split_face_attributes(trans, id_out_lhs, id_out_rhs, id_in),
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.split_face_attributes(trans, id_out_lhs, id_out_rhs, id_in)
}
OrbitPolicy::Custom(_) => unimplemented!(),
}
}
Expand Down Expand Up @@ -835,13 +855,13 @@ impl AttrStorageManager {
id_in: DartIdType,
) -> CMapResult<()> {
match orbit_policy {
OrbitPolicy::Vertex => {
OrbitPolicy::Vertex | OrbitPolicy::VertexLinear => {
self.try_split_vertex_attributes(trans, id_out_lhs, id_out_rhs, id_in)
}
OrbitPolicy::Edge => {
self.try_split_edge_attributes(trans, id_out_lhs, id_out_rhs, id_in)
}
OrbitPolicy::Face => {
OrbitPolicy::Face | OrbitPolicy::FaceLinear => {
self.try_split_face_attributes(trans, id_out_lhs, id_out_rhs, id_in)
}
OrbitPolicy::Custom(_) => unimplemented!(),
Expand Down
13 changes: 7 additions & 6 deletions honeycomb-core/src/cmap/builder/grid/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ fn square_cmap2_correctness() {
assert_eq!(cmap.face_id(3), 1);
assert_eq!(cmap.face_id(4), 1);

// i-cell uses beta 0 to ensure correctness, so the iterator is BFS-like
let mut face = cmap.i_cell::<2>(1);
assert_eq!(face.next(), Some(1));
assert_eq!(face.next(), Some(2));
assert_eq!(face.next(), Some(3));
assert_eq!(face.next(), Some(4));
assert_eq!(face.next(), Some(2)); // b1
assert_eq!(face.next(), Some(4)); // b0
assert_eq!(face.next(), Some(3)); // b1b1
assert_eq!(face.next(), None);

assert_eq!(cmap.beta::<1>(1), 2);
Expand All @@ -138,8 +139,8 @@ fn square_cmap2_correctness() {
let mut face = cmap.i_cell::<2>(5);
assert_eq!(face.next(), Some(5));
assert_eq!(face.next(), Some(6));
assert_eq!(face.next(), Some(7));
assert_eq!(face.next(), Some(8));
assert_eq!(face.next(), Some(7));
assert_eq!(face.next(), None);

assert_eq!(cmap.beta::<1>(5), 6);
Expand All @@ -161,8 +162,8 @@ fn square_cmap2_correctness() {
let mut face = cmap.i_cell::<2>(9);
assert_eq!(face.next(), Some(9));
assert_eq!(face.next(), Some(10));
assert_eq!(face.next(), Some(11));
assert_eq!(face.next(), Some(12));
assert_eq!(face.next(), Some(11));
assert_eq!(face.next(), None);

assert_eq!(cmap.beta::<1>(9), 10);
Expand All @@ -184,8 +185,8 @@ fn square_cmap2_correctness() {
let mut face = cmap.i_cell::<2>(13);
assert_eq!(face.next(), Some(13));
assert_eq!(face.next(), Some(14));
assert_eq!(face.next(), Some(15));
assert_eq!(face.next(), Some(16));
assert_eq!(face.next(), Some(15));
assert_eq!(face.next(), None);

assert_eq!(cmap.beta::<1>(13), 14);
Expand Down
78 changes: 70 additions & 8 deletions honeycomb-core/src/cmap/dim2/orbits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ use std::collections::{BTreeSet, VecDeque};
pub enum OrbitPolicy {
/// 0-cell orbit.
Vertex,
/// 0-cell orbit, without using beta 0. This requires the cell to be complete / closed.
VertexLinear,
/// 1-cell orbit.
Edge,
/// 2-cell orbit.
Face,
/// 2-cell orbit, without using beta 0. This requires the cell to be complete / closed.
FaceLinear,
/// Ordered array of beta functions that define the orbit.
Custom(&'static [u8]),
}
Expand Down Expand Up @@ -125,7 +129,6 @@ impl<'a, T: CoordsFloat> Iterator for Orbit2<'a, T> {
match self.orbit_policy {
OrbitPolicy::Vertex => {
// THIS CODE IS ONLY VALID IN 2D

let image1 = self.map_handle.beta::<1>(self.map_handle.beta::<2>(d));
if self.marked.insert(image1) {
// if true, we did not see this dart yet
Expand All @@ -139,6 +142,15 @@ impl<'a, T: CoordsFloat> Iterator for Orbit2<'a, T> {
self.pending.push_back(image2);
}
}
OrbitPolicy::VertexLinear => {
// THIS CODE IS ONLY VALID IN 2D
let image = self.map_handle.beta::<1>(self.map_handle.beta::<2>(d));
if self.marked.insert(image) {
// if true, we did not see this dart yet
// i.e. we need to visit it later
self.pending.push_back(image);
}
}
OrbitPolicy::Edge => {
// THIS CODE IS ONLY VALID IN 2D
let image = self.map_handle.beta::<2>(d);
Expand All @@ -150,7 +162,21 @@ impl<'a, T: CoordsFloat> Iterator for Orbit2<'a, T> {
}
OrbitPolicy::Face => {
// THIS CODE IS ONLY VALID IN 2D
// WE ASSUME THAT THE FACE IS COMPLETE
let image1 = self.map_handle.beta::<1>(d);
if self.marked.insert(image1) {
// if true, we did not see this dart yet
// i.e. we need to visit it later
self.pending.push_back(image1);
}
let image2 = self.map_handle.beta::<0>(d);
if self.marked.insert(image2) {
// if true, we did not see this dart yet
// i.e. we need to visit it later
self.pending.push_back(image2);
}
}
OrbitPolicy::FaceLinear => {
// THIS CODE IS ONLY VALID IN 2D
let image = self.map_handle.beta::<1>(d);
if self.marked.insert(image) {
// if true, we did not see this dart yet
Expand Down Expand Up @@ -184,18 +210,34 @@ mod tests {
use super::*;

fn simple_map() -> CMap2<f64> {
let mut map: CMap2<f64> = CMap2::new(6);
let mut map: CMap2<f64> = CMap2::new(11);
// tri1
map.force_one_link(1, 2);
map.force_one_link(2, 3);
map.force_one_link(3, 1);
// tri2
map.force_one_link(4, 5);
map.force_one_link(5, 6);
map.force_one_link(6, 4);
// pent on top
map.force_one_link(7, 8);
map.force_one_link(8, 9);
map.force_one_link(9, 10);
map.force_one_link(10, 11);
map.force_one_link(11, 7);

// link all
map.force_two_link(2, 4);
map.force_two_link(6, 7);

assert!(map.force_write_vertex(1, (0.0, 0.0)).is_none());
assert!(map.force_write_vertex(2, (1.0, 0.0)).is_none());
assert!(map.force_write_vertex(6, (1.0, 1.0)).is_none());
assert!(map.force_write_vertex(3, (0.0, 1.0)).is_none());
assert!(map.force_write_vertex(9, (1.5, 1.5)).is_none());
assert!(map.force_write_vertex(10, (0.5, 2.0)).is_none());
assert!(map.force_write_vertex(11, (-0.5, 1.5)).is_none());

map
}

Expand All @@ -204,9 +246,30 @@ mod tests {
let map = simple_map();
let orbit = Orbit2::new(&map, OrbitPolicy::Custom(&[1, 2]), 3);
let darts: Vec<DartIdType> = orbit.collect();
assert_eq!(darts.len(), 6);
assert_eq!(darts.len(), 11);
// because the algorithm is consistent, we can predict the exact layout
assert_eq!(&darts, &[3, 1, 2, 4, 5, 6]);
assert_eq!(&darts, &[3, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11]);
}

#[test]
fn orbit_variants() {
let map = simple_map();

// face is complete, so everything works
let face: Vec<DartIdType> = Orbit2::new(&map, OrbitPolicy::Face, 7).collect();
let face_linear: Vec<DartIdType> = Orbit2::new(&map, OrbitPolicy::FaceLinear, 7).collect();
let face_custom: Vec<DartIdType> =
Orbit2::new(&map, OrbitPolicy::Custom(&[0, 1]), 7).collect();
assert_eq!(&face, &[7, 8, 11, 9, 10]);
assert_eq!(&face_linear, &[7, 8, 9, 10, 11]);
assert_eq!(&face_custom, &[7, 11, 8, 10, 9]);

// vertex is incomplete, so using the linear variant will yield an incomplete orbit
let vertex: Vec<DartIdType> = Orbit2::new(&map, OrbitPolicy::Vertex, 4).collect();
let vertex_linear: Vec<DartIdType> =
Orbit2::new(&map, OrbitPolicy::VertexLinear, 4).collect();
assert_eq!(&vertex, &[4, 3, 7]);
assert_eq!(&vertex_linear, &[4, 3]);
}

#[test]
Expand Down Expand Up @@ -240,9 +303,8 @@ mod tests {
let map = simple_map();
let orbit = Orbit2::new(&map, OrbitPolicy::Vertex, 4);
let darts: Vec<DartIdType> = orbit.collect();
// note that this one fails if we start at 3, because the vertex is not complete
assert_eq!(darts.len(), 2);
assert_eq!(&darts, &[4, 3]);
assert_eq!(darts.len(), 3);
assert_eq!(&darts, &[4, 3, 7]);
}

#[test]
Expand Down