From 1efd3a2404c78bfbf3109f5244125a6adbdd167e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Nevyho=C5=A1t=C4=9Bn=C3=BD?= Date: Mon, 1 Apr 2024 15:47:29 +0200 Subject: [PATCH] Allow integer conversions and sentinel value for all id types This will allow more flexibility of code that uses an id type and can handle both integer-like and not-like-integer types with significant performance benefit if the id type is an integer. After this change, this can be detected at runtime, choosing the appropriate implementation depending on the actual instance of the graph passed. And example will be CompactIdMap. For integer indices it can use the current implementation which has minimal overhead. After this change, it can support also non-like-integer ids, keeping the mapping from the id to usize in a hashmap. --- gryf/examples/complex_index.rs | 18 +- gryf/examples/implicit_graph.rs | 8 +- gryf/src/adapt/complement.rs | 4 +- gryf/src/adapt/subgraph.rs | 6 +- gryf/src/algo/shortest_paths/bellman_ford.rs | 20 +- gryf/src/algo/toposort/kahn.rs | 6 +- gryf/src/common/compact_id_map.rs | 14 +- gryf/src/common/visit_set.rs | 8 +- gryf/src/core/base.rs | 2 +- gryf/src/core/id.rs | 188 ++++++++++++++----- gryf/src/graph/path.rs | 4 +- gryf/src/infra/arbitrary.rs | 32 ++-- gryf/src/infra/modeling.rs | 24 +-- gryf/src/storage/adj_list.rs | 62 +++--- gryf/src/storage/adj_matrix.rs | 42 ++--- gryf/src/storage/edge_list.rs | 24 +-- gryf/src/storage/shared.rs | 13 +- 17 files changed, 290 insertions(+), 185 deletions(-) diff --git a/gryf/examples/complex_index.rs b/gryf/examples/complex_index.rs index fbf85c4..055d870 100644 --- a/gryf/examples/complex_index.rs +++ b/gryf/examples/complex_index.rs @@ -10,7 +10,23 @@ use gryf::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] struct ChessSquare(pub usize, pub usize); -impl IdType for ChessSquare {} +impl IdType for ChessSquare { + fn sentinel() -> Self { + Self(usize::MAX, usize::MAX) + } + + fn is_integer() -> bool { + false + } + + fn as_bits(&self) -> u64 { + panic!("unsupported") + } + + fn from_bits(_: u64) -> Self { + panic!("unsupported") + } +} struct Chessboard; diff --git a/gryf/examples/implicit_graph.rs b/gryf/examples/implicit_graph.rs index 74171c0..984ee7b 100644 --- a/gryf/examples/implicit_graph.rs +++ b/gryf/examples/implicit_graph.rs @@ -18,7 +18,7 @@ fn to_vertex(n: u64) -> VertexId { } fn to_num(v: VertexId) -> u64 { - v.to_bits() + v.as_bits() } struct Neighbor { @@ -27,13 +27,13 @@ struct Neighbor { impl NeighborRef for Neighbor { fn id(&self) -> WeakRef<'_, VertexId> { - let n = self.src.to_bits(); + let n = self.src.as_bits(); let c = if n % 2 == 0 { n / 2 } else { 3 * n + 1 }; WeakRef::Owned(to_vertex(c)) } fn edge(&self) -> WeakRef<'_, EdgeId> { - WeakRef::Owned(EdgeId::from_bits(self.src.to_bits())) + WeakRef::Owned(EdgeId::from_bits(self.src.as_bits())) } fn src(&self) -> WeakRef<'_, VertexId> { @@ -80,7 +80,7 @@ impl VerticesBaseWeak for Collatz { impl VerticesWeak for Collatz { fn vertex_weak(&self, id: &VertexId) -> Option> { - Some(id.to_bits().into()) + Some(id.as_bits().into()) } } diff --git a/gryf/src/adapt/complement.rs b/gryf/src/adapt/complement.rs index 0f1c3f9..d609f5e 100644 --- a/gryf/src/adapt/complement.rs +++ b/gryf/src/adapt/complement.rs @@ -2,7 +2,7 @@ use rustc_hash::FxHashSet; use crate::core::{ facts, - id::IntegerIdType, + id::{IdType, IntegerIdType}, marker::{Direction, Undirected}, EdgesBase, EdgesMut, Neighbors, Vertices, VerticesBase, VerticesMut, WeakRef, }; @@ -127,7 +127,7 @@ where let v = self.vertices.next()?; if v != self.src && !self.neighbors.contains(&v) { - return Some((v, G::EdgeId::null(), self.src.clone(), self.dir)); + return Some((v, IdType::sentinel(), self.src.clone(), self.dir)); } } } diff --git a/gryf/src/adapt/subgraph.rs b/gryf/src/adapt/subgraph.rs index a84af05..6f5fe50 100644 --- a/gryf/src/adapt/subgraph.rs +++ b/gryf/src/adapt/subgraph.rs @@ -306,7 +306,7 @@ where mod tests { use crate::{ core::{ - id::{DefaultId, EdgeId, IntegerIdType, VertexId}, + id::{DefaultId, EdgeId, IdType, VertexId}, marker::Directed, EdgesMut, VerticesMut, }, @@ -358,10 +358,10 @@ mod tests { graph.add_edge(&v4, &v5, 10); Subgraph::new(graph) - .filter_vertex(|v: &VertexId, _, _| v.to_usize() < 4) + .filter_vertex(|v: &VertexId, _, _| v.as_usize() < 4) .filter_edge(|e, g, _| { let (src, dst): (VertexId, VertexId) = g.endpoints(e).unwrap(); - src.to_usize() + dst.to_usize() < 4 || dst.to_usize() == 5 + src.as_usize() + dst.as_usize() < 4 || dst.as_usize() == 5 }) } diff --git a/gryf/src/algo/shortest_paths/bellman_ford.rs b/gryf/src/algo/shortest_paths/bellman_ford.rs index d574eab..f91dff2 100644 --- a/gryf/src/algo/shortest_paths/bellman_ford.rs +++ b/gryf/src/algo/shortest_paths/bellman_ford.rs @@ -26,9 +26,9 @@ where let vertex_map = graph.vertex_id_map(); let mut dist = vec![W::inf(); vertex_map.len()]; - let mut pred = vec![Virtual::null(); vertex_map.len()]; + let mut pred = vec![Virtual::sentinel(); vertex_map.len()]; - dist[vertex_map.virt(start).unwrap().to_usize()] = W::zero(); + dist[vertex_map.virt(start).unwrap().as_usize()] = W::zero(); let mut terminated_early = false; @@ -39,8 +39,8 @@ where for edge in graph.edges() { if let Some((next_dist, u, v)) = process_edge(&edge, &edge_weight, &vertex_map, &dist) { // Relax if better. - dist[v.to_usize()] = next_dist; - pred[v.to_usize()] = u; + dist[v.as_usize()] = next_dist; + pred[v.as_usize()] = u; relaxed = true; } @@ -50,8 +50,8 @@ where if let Some((next_dist, u, v)) = process_edge(&TransposeRef::new(edge), &edge_weight, &vertex_map, &dist) { - dist[v.to_usize()] = next_dist; - pred[v.to_usize()] = u; + dist[v.as_usize()] = next_dist; + pred[v.as_usize()] = u; relaxed = true; } } @@ -84,7 +84,7 @@ where } if let Some(goal) = goal { - if dist[vertex_map.virt(goal).unwrap().to_usize()] == W::inf() { + if dist[vertex_map.virt(goal).unwrap().as_usize()] == W::inf() { return Err(Error::GoalNotReached); } } @@ -105,7 +105,7 @@ where .into_iter() .enumerate() .filter_map(|(i, p)| { - if !p.is_null() { + if !p.is_sentinel() { Some(( vertex_map.real(Virtual::from(i)).unwrap(), vertex_map.real(p).unwrap(), @@ -135,7 +135,7 @@ where { let u = vertex_map.virt(*edge.src()).unwrap(); - let short_dist = &dist[u.to_usize()]; + let short_dist = &dist[u.as_usize()]; if short_dist == &W::inf() { return None; } @@ -145,7 +145,7 @@ where let edge_dist = edge_weight.get(edge.data()); let next_dist = short_dist.clone() + edge_dist; - if next_dist < dist[v.to_usize()] { + if next_dist < dist[v.as_usize()] { Some((next_dist, u, v)) } else { None diff --git a/gryf/src/algo/toposort/kahn.rs b/gryf/src/algo/toposort/kahn.rs index 7a538e7..4dc1a1b 100644 --- a/gryf/src/algo/toposort/kahn.rs +++ b/gryf/src/algo/toposort/kahn.rs @@ -2,7 +2,7 @@ use crate::{ algo::Cycle, common::CompactIdMap, core::{ - id::{IntegerIdType, Virtual}, + id::{IdType, IntegerIdType, Virtual}, marker::Direction, GraphBase, NeighborRef, Neighbors, VerticesBase, }, @@ -64,7 +64,7 @@ where self.visited += 1; for n in self.graph.neighbors_directed(&vertex, Direction::Outgoing) { - let i = self.map.virt(*n.id()).unwrap().to_usize(); + let i = self.map.virt(*n.id()).unwrap().as_usize(); let deg = &mut self.in_deg[i]; *deg -= 1; @@ -101,7 +101,7 @@ where .graph .neighbors_directed(&v, Direction::Incoming) .find_map(|n| { - let i = self.map.virt(*n.id()).unwrap().to_usize(); + let i = self.map.virt(*n.id()).unwrap().as_usize(); if self.in_deg[i] > 0 { Some(n.edge().into_owned()) } else { diff --git a/gryf/src/common/compact_id_map.rs b/gryf/src/common/compact_id_map.rs index 9c60a33..19b329b 100644 --- a/gryf/src/common/compact_id_map.rs +++ b/gryf/src/common/compact_id_map.rs @@ -1,6 +1,6 @@ use std::cmp::min; -use crate::core::id::{IntegerIdType, Virtual}; +use crate::core::id::{IdType, IntegerIdType, Virtual}; // For compact storages, the space and time for both directions is constant (use // `isomorphic`). For storages with holes, the space is O(|V|), virtual to real @@ -18,7 +18,7 @@ impl CompactIdMap { A: Iterator, { let mut map = iter.collect::>(); - map.sort_unstable_by_key(|id| id.to_bits()); + map.sort_unstable_by_key(|id| id.as_bits()); let len = map.len(); Self { map, len } @@ -50,19 +50,19 @@ impl CompactIdMap { let id: Virtual = id.into(); if self.is_isomorphic() { - (id.to_usize() < self.len()).then(|| I::from_bits(id.to_bits())) + (id.as_usize() < self.len()).then(|| I::from_bits(id.as_bits())) } else { - self.map.get(id.to_usize()).copied() + self.map.get(id.as_usize()).cloned() } } pub fn virt(&self, id: I) -> Option> { if self.is_isomorphic() { - (id.to_usize() < self.len()).then(|| Virtual::new(id.to_bits())) + (id.as_usize() < self.len()).then(|| Virtual::new(id.as_bits())) } else { // Using `wrapping_sub` not to panic on overflow. - let direct = min(id.to_usize(), self.len().wrapping_sub(1)); - let direct_elem = self.map.get(direct).copied()?; + let direct = min(id.as_usize(), self.len().wrapping_sub(1)); + let direct_elem = self.map.get(direct).cloned()?; // This will always be true for storages without holes, and sometimes // for storages with holes. diff --git a/gryf/src/common/visit_set.rs b/gryf/src/common/visit_set.rs index 946a49f..4b85d79 100644 --- a/gryf/src/common/visit_set.rs +++ b/gryf/src/common/visit_set.rs @@ -54,14 +54,14 @@ impl VisitSet for HashSet { impl VisitSet for FixedBitSet { fn visit(&mut self, id: I) -> bool { - if self.len() < id.to_usize() { - self.grow(id.to_usize() - self.len()); + if self.len() < id.as_usize() { + self.grow(id.as_usize() - self.len()); } - !self.put(id.to_usize()) + !self.put(id.as_usize()) } fn is_visited(&self, id: &I) -> bool { - self.contains(id.to_usize()) + self.contains(id.as_usize()) } fn visited_count(&self) -> usize { diff --git a/gryf/src/core/base.rs b/gryf/src/core/base.rs index 0bdc293..77b7b7b 100644 --- a/gryf/src/core/base.rs +++ b/gryf/src/core/base.rs @@ -180,7 +180,7 @@ where { for edge in iter { let (src, dst, edge) = edge.unpack(); - let vertex_bound = max(src, dst).to_usize(); + let vertex_bound = max(&src, &dst).as_usize(); while self.vertex_count() <= vertex_bound { self.add_vertex(V::default()); diff --git a/gryf/src/core/id.rs b/gryf/src/core/id.rs index e13923a..b778cff 100644 --- a/gryf/src/core/id.rs +++ b/gryf/src/core/id.rs @@ -1,27 +1,84 @@ -use std::{hash::Hash, marker::PhantomData}; - -pub trait IdType: Clone + Ord + Hash + core::fmt::Debug {} - -pub trait IntegerIdType: IdType + Copy + From + Into { - fn to_bits(self) -> u64; +use std::{fmt::Debug, hash::Hash, marker::PhantomData}; + +/// A unique identification of a vertex or edge in a graph. +/// +/// In standard graph representations, the id type is an integer. Conceptually, +/// such an integer id is of type `usize`, but one can choose a smaller integer +/// type (such as u8 or u16) to lower the memory footprint. In these cases, the +/// algorithms can treat the id as usize with all the benefits (e.g., indexing +/// to a contiguous array). +/// +/// For implicit graphs, an id can be of any form as long as it implements +/// required interface and super traits. In general, such ids can't be treated +/// as integers and require a different handling, usually with overhead. +/// +/// Any id must also have a representation for a "sentinel" value. For integers, +/// we use the maximum value of the corresponding type for the sentinel, so we +/// don't introduce the overhead of using `Option` and can use 0 as the +/// first index (as is natural). +pub trait IdType: Clone + Ord + Hash + Debug { + /// Conceptually `None` in `Option`, but without using `Option`. + fn sentinel() -> Self; + + /// Determines if the id type is `usize`-compatible. + /// + /// Types that are not `usize`-compatible require a special, often less + /// efficient handling. + fn is_integer() -> bool; + + /// Converts an id into the corresponding `u64`. + /// + /// Types for which `is_integer() == false` should panic in this function. + fn as_bits(&self) -> u64; + + /// Converts an `u64` into the corresponding id. + /// + /// Types for which `is_integer() == false` should panic in this function. fn from_bits(bits: u64) -> Self; - fn null() -> Self; - fn to_usize(self) -> usize { - self.into() + /// Converts an id into the corresponding `usize`. + /// + /// Types for which `is_integer() == false` should panic in this function. + fn as_usize(&self) -> usize { + self.as_bits() as usize } - fn from_usize(id: usize) -> Self { - Self::from(id) + /// Converts an `usize` into the corresponding id. + /// + /// Types for which `is_integer() == false` should panic in this function. + fn from_usize(index: usize) -> Self { + Self::from_bits(index as u64) } - fn is_null(&self) -> bool { - *self == Self::null() + fn is_sentinel(&self) -> bool { + self == &Self::sentinel() } } +/// Type-level specification that an id type is integer-like. +/// +/// All types that implement this trait must return `true` in +/// `IdType::is_integer`. +pub trait IntegerIdType: IdType + Copy + From + Into {} + // For edge ids that are represented as a pair of vertex ids. -impl IdType for (T, U) {} +impl IdType for (T, U) { + fn sentinel() -> Self { + (T::sentinel(), U::sentinel()) + } + + fn is_integer() -> bool { + false + } + + fn as_bits(&self) -> u64 { + panic!("unsupported") + } + + fn from_bits(_: u64) -> Self { + panic!("unsupported") + } +} #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct VertexId(pub Id); @@ -38,45 +95,49 @@ impl Virtual { } } -impl IdType for Virtual {} +impl IdType for Virtual { + fn sentinel() -> Self { + Self::new(u64::MAX) + } + + fn is_integer() -> bool { + true + } + + fn as_bits(&self) -> u64 { + self.0 + } + + fn from_bits(bits: u64) -> Self { + Self::new(bits) + } +} impl From for Virtual { - fn from(id: usize) -> Self { - Self::new(id.try_into().expect("id type overflow")) + fn from(index: usize) -> Self { + Self::from_usize(index) } } impl From> for usize { fn from(id: Virtual) -> Self { - id.0.try_into().expect("id type overflow") + id.as_usize() } } impl From for Virtual { - fn from(id: u64) -> Self { - Self::new(id) + fn from(bits: u64) -> Self { + Self::from_bits(bits) } } impl From> for u64 { fn from(id: Virtual) -> Self { - id.0 + id.as_bits() } } -impl IntegerIdType for Virtual { - fn to_bits(self) -> u64 { - self.0 - } - - fn from_bits(bits: u64) -> Self { - Self::new(bits) - } - - fn null() -> Self { - Self::new(u64::MAX) - } -} +impl IntegerIdType for Virtual {} pub trait GraphIdTypes { type VertexId: IdType; @@ -119,22 +180,16 @@ impl UseId for UseEdgeId { macro_rules! impl_int_id { ($id_ty:ident, $int_ty:ty) => { - impl IdType for $id_ty<$int_ty> {} - - impl From for $id_ty<$int_ty> { - fn from(id: usize) -> Self { - Self(id.try_into().expect("id type overflow")) + impl IdType for $id_ty<$int_ty> { + fn sentinel() -> Self { + Self(<$int_ty>::MAX) } - } - impl From<$id_ty<$int_ty>> for usize { - fn from(id: $id_ty<$int_ty>) -> Self { - id.0.try_into().expect("id type overflow") + fn is_integer() -> bool { + true } - } - impl IntegerIdType for $id_ty<$int_ty> { - fn to_bits(self) -> u64 { + fn as_bits(&self) -> u64 { self.0 as u64 } @@ -142,10 +197,28 @@ macro_rules! impl_int_id { Self(bits as $int_ty) } - fn null() -> Self { - Self(<$int_ty>::MAX) + fn as_usize(&self) -> usize { + self.0.try_into().expect("id type overflow") + } + + fn from_usize(index: usize) -> Self { + Self(index.try_into().expect("id type overflow")) + } + } + + impl From for $id_ty<$int_ty> { + fn from(index: usize) -> Self { + Self::from_usize(index) + } + } + + impl From<$id_ty<$int_ty>> for usize { + fn from(id: $id_ty<$int_ty>) -> Self { + id.as_usize() } } + + impl IntegerIdType for $id_ty<$int_ty> {} }; } @@ -161,4 +234,21 @@ impl_int_id!(EdgeId, u32); impl_int_id!(EdgeId, u16); impl_int_id!(EdgeId, u8); -impl IdType for () {} +impl IdType for () { + #[allow(clippy::unused_unit)] + fn sentinel() -> Self { + () + } + + fn is_integer() -> bool { + false + } + + fn as_bits(&self) -> u64 { + panic!("unsupported") + } + + fn from_bits(_: u64) -> Self { + panic!("unsupported") + } +} diff --git a/gryf/src/graph/path.rs b/gryf/src/graph/path.rs index 01121bc..9d9c2ef 100644 --- a/gryf/src/graph/path.rs +++ b/gryf/src/graph/path.rs @@ -691,7 +691,7 @@ where #[cfg(test)] mod tests { - use crate::core::id::VertexId; + use crate::core::id::{IdType, VertexId}; use super::*; @@ -999,7 +999,7 @@ mod tests { fn try_add_vertex_empty() { let mut path = Path::<(), (), Undirected, _>::new(); - let result = path.try_add_vertex((), None, VertexId::null()); + let result = path.try_add_vertex((), None, VertexId::sentinel()); assert!(result.is_ok()); let v = result.unwrap(); diff --git a/gryf/src/infra/arbitrary.rs b/gryf/src/infra/arbitrary.rs index ee68dde..9fb82dd 100644 --- a/gryf/src/infra/arbitrary.rs +++ b/gryf/src/infra/arbitrary.rs @@ -199,34 +199,38 @@ impl fmt::Debug for MutOpsSeq { } } -impl IdType for Index {} - -impl From for Index { - fn from(value: usize) -> Self { - Self(value) +impl IdType for Index { + fn sentinel() -> Self { + Self(usize::MAX) } -} -impl From for usize { - fn from(value: Index) -> Self { - value.0 + fn is_integer() -> bool { + true } -} -impl IntegerIdType for Index { - fn to_bits(self) -> u64 { + fn as_bits(&self) -> u64 { self.0 as u64 } fn from_bits(bits: u64) -> Self { Self(bits as usize) } +} + +impl From for Index { + fn from(value: usize) -> Self { + Self(value) + } +} - fn null() -> Self { - Self(usize::MAX) +impl From for usize { + fn from(value: Index) -> Self { + value.0 } } +impl IntegerIdType for Index {} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ArbitraryId {} diff --git a/gryf/src/infra/modeling.rs b/gryf/src/infra/modeling.rs index 0c72656..8847ab8 100644 --- a/gryf/src/infra/modeling.rs +++ b/gryf/src/infra/modeling.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use arbitrary::Arbitrary; use crate::core::{ - id::{EdgeId, IntegerIdType, VertexId}, + id::{EdgeId, IdType, IntegerIdType, VertexId}, marker::{Direction, EdgeType}, AddEdgeError, AddEdgeErrorKind, AddVertexError, Edges, EdgesBase, EdgesMut, GraphBase, Neighbors, Vertices, VerticesBase, VerticesMut, @@ -224,7 +224,7 @@ impl Vertices for Model { V: 'a; fn vertex(&self, id: &Self::VertexId) -> Option<&V> { - self.vertices.get(id.to_usize()).and_then(Option::as_ref) + self.vertices.get(id.as_usize()).and_then(Option::as_ref) } fn vertices(&self) -> Self::VerticesIter<'_> { @@ -235,7 +235,7 @@ impl Vertices for Model { impl VerticesMut for Model { fn vertex_mut(&mut self, id: &Self::VertexId) -> Option<&mut V> { self.vertices - .get_mut(id.to_usize()) + .get_mut(id.as_usize()) .and_then(Option::as_mut) } @@ -253,7 +253,7 @@ impl VerticesMut for Model { fn remove_vertex(&mut self, id: &Self::VertexId) -> Option { self.vertex(id)?; - let index = id.to_usize(); + let index = id.as_usize(); self.removed_vertices += 1; match self.params.removal_behavior { @@ -317,12 +317,12 @@ impl EdgesBase for Model { } fn endpoints(&self, id: &Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> { - let &(src, dst) = self.neighbors.get(id.to_usize())?.as_ref()?; + let &(src, dst) = self.neighbors.get(id.as_usize())?.as_ref()?; Some((VertexId::from_usize(src), VertexId::from_usize(dst))) } fn edge_id(&self, src: &Self::VertexId, dst: &Self::VertexId) -> Self::EdgeIdIter<'_> { - let (src, dst) = (src.to_usize(), dst.to_usize()); + let (src, dst) = (src.as_usize(), dst.as_usize()); EdgeIdIter::new([src, dst], &self.neighbors) } @@ -343,7 +343,7 @@ impl Edges for Model { E: 'a; fn edge(&self, id: &Self::EdgeId) -> Option<&E> { - self.edges.get(id.to_usize()).and_then(Option::as_ref) + self.edges.get(id.as_usize()).and_then(Option::as_ref) } fn edges(&self) -> Self::EdgesIter<'_> { @@ -353,7 +353,7 @@ impl Edges for Model { impl EdgesMut for Model { fn edge_mut(&mut self, id: &Self::EdgeId) -> Option<&mut E> { - self.edges.get_mut(id.to_usize()).and_then(Option::as_mut) + self.edges.get_mut(id.as_usize()).and_then(Option::as_mut) } fn try_add_edge( @@ -374,7 +374,7 @@ impl EdgesMut for Model { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::CapacityOverflow)); } - let (src, dst) = (src.to_usize(), dst.to_usize()); + let (src, dst) = (src.as_usize(), dst.as_usize()); if !self.params.allow_multi_edges && self.edge_exists(src, dst) { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::MultiEdge)); @@ -390,7 +390,7 @@ impl EdgesMut for Model { fn remove_edge(&mut self, id: &Self::EdgeId) -> Option { self.edge(id)?; - let index = id.to_usize(); + let index = id.as_usize(); self.removed_edges += 1; match self.params.removal_behavior { @@ -416,11 +416,11 @@ impl Neighbors for Model { Self: 'a; fn neighbors(&self, src: &Self::VertexId) -> Self::NeighborsIter<'_> { - NeighborsIter::new(src.to_usize(), &self.neighbors, None) + NeighborsIter::new(src.as_usize(), &self.neighbors, None) } fn neighbors_directed(&self, src: &Self::VertexId, dir: Direction) -> Self::NeighborsIter<'_> { - NeighborsIter::new(src.to_usize(), &self.neighbors, Some(dir)) + NeighborsIter::new(src.as_usize(), &self.neighbors, Some(dir)) } } diff --git a/gryf/src/storage/adj_list.rs b/gryf/src/storage/adj_list.rs index d320ffb..150aace 100644 --- a/gryf/src/storage/adj_list.rs +++ b/gryf/src/storage/adj_list.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::{ common::CompactIdMap, core::{ - id::{DefaultId, GraphIdTypes, IntegerIdType}, + id::{DefaultId, GraphIdTypes, IdType, IntegerIdType}, marker::{Direction, EdgeType}, AddEdgeError, AddEdgeErrorKind, AddVertexError, ConnectVertices, Create, Edges, EdgesBase, EdgesMut, GraphBase, Guarantee, MultiEdges, Neighbors, Vertices, VerticesBase, VerticesMut, @@ -46,7 +46,7 @@ where Id::EdgeId: IntegerIdType, { fn remove_edge_inner(&mut self, id: Id::EdgeId, cause: Option) -> Option { - let endpoints = self.endpoints.get(id.to_usize())?; + let endpoints = self.endpoints.get(id.as_usize())?; for (i, dir) in Self::directions().iter().enumerate() { let endpoint = endpoints[i]; @@ -56,32 +56,32 @@ where // to remove it. if Some(endpoint) != cause { Self::disconnect( - &mut self.vertices[endpoint.to_usize()].edges[dir.index()], + &mut self.vertices[endpoint.as_usize()].edges[dir.index()], id, ); } } // Remove the edge from the graph. - let edge = self.edges.swap_remove(id.to_usize()); - self.endpoints.swap_remove(id.to_usize()); + let edge = self.edges.swap_remove(id.as_usize()); + self.endpoints.swap_remove(id.as_usize()); // If `swap_remove` actually moved an existing edge somewhere, we need // to fix its id in the entire graph. - if id.to_usize() < self.edges.len() { - self.relocate_edge(IntegerIdType::from_usize(self.edges.len()), id); + if id.as_usize() < self.edges.len() { + self.relocate_edge(IdType::from_usize(self.edges.len()), id); } Some(edge) } fn relocate_vertex(&mut self, old_id: Id::VertexId, new_id: Id::VertexId) { - let vertex = &mut self.vertices[new_id.to_usize()]; + let vertex = &mut self.vertices[new_id.as_usize()]; // Fix the id of the vertex in all edges it has. for dir in Ty::directions() { for edge_id in vertex.edges[dir.index()].iter() { - let endpoints = &mut self.endpoints[edge_id.to_usize()]; + let endpoints = &mut self.endpoints[edge_id.as_usize()]; for endpoint in endpoints.iter_mut() { if *endpoint == old_id { *endpoint = new_id; @@ -92,11 +92,11 @@ where } fn relocate_edge(&mut self, old_id: Id::EdgeId, new_id: Id::EdgeId) { - let endpoints = &mut self.endpoints[new_id.to_usize()]; + let endpoints = &mut self.endpoints[new_id.as_usize()]; // Fix the id of the edge in all vertices it is incident with. for i in 0..=1 { - let vertex = &mut self.vertices[endpoints[i].to_usize()]; + let vertex = &mut self.vertices[endpoints[i].as_usize()]; for dir in Ty::directions() { for edge_id in &mut vertex.edges[dir.index()] { @@ -185,7 +185,7 @@ where Self: 'a; fn vertex(&self, id: &Self::VertexId) -> Option<&V> { - self.vertices.get(id.to_usize()).map(|vertex| &vertex.data) + self.vertices.get(id.as_usize()).map(|vertex| &vertex.data) } fn vertices(&self) -> Self::VerticesIter<'_> { @@ -200,7 +200,7 @@ where { fn vertex_mut(&mut self, id: &Self::VertexId) -> Option<&mut V> { self.vertices - .get_mut(id.to_usize()) + .get_mut(id.as_usize()) .map(|vertex| &mut vertex.data) } @@ -214,7 +214,7 @@ where for dir in Ty::directions() { // Remove all edges connected to this vertex in this direction. loop { - let vertex = self.vertices.get_mut(id.to_usize())?; + let vertex = self.vertices.get_mut(id.as_usize())?; if vertex.edges[dir.index()].is_empty() { break; } @@ -227,12 +227,12 @@ where } // Remove the vertex from the graph. - let vertex = self.vertices.swap_remove(id.to_usize()); + let vertex = self.vertices.swap_remove(id.as_usize()); // If `swap_remove` actually moved an existing vertex somewhere, we need // to fix its id in the entire graph. - if id.to_usize() < self.vertices.len() { - self.relocate_vertex(IntegerIdType::from_usize(self.vertices.len()), *id); + if id.as_usize() < self.vertices.len() { + self.relocate_vertex(IdType::from_usize(self.vertices.len()), *id); } Some(vertex.data) @@ -267,12 +267,12 @@ where fn endpoints(&self, id: &Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> { self.endpoints - .get(id.to_usize()) + .get(id.as_usize()) .map(|endpoints| (endpoints[0], endpoints[1])) } fn edge_id(&self, src: &Self::VertexId, dst: &Self::VertexId) -> Self::EdgeIdIter<'_> { - match self.vertices.get(src.to_usize()) { + match self.vertices.get(src.as_usize()) { Some(vertex) => EdgeIdIter { src: *src, dst: *dst, @@ -314,7 +314,7 @@ where Self: 'a; fn edge(&self, id: &Self::EdgeId) -> Option<&E> { - self.edges.get(id.to_usize()) + self.edges.get(id.as_usize()) } fn edges(&self) -> Self::EdgesIter<'_> { @@ -328,7 +328,7 @@ where Id::EdgeId: IntegerIdType, { fn edge_mut(&mut self, id: &Self::EdgeId) -> Option<&mut E> { - self.edges.get_mut(id.to_usize()) + self.edges.get_mut(id.as_usize()) } fn try_add_edge( @@ -337,21 +337,21 @@ where dst: &Self::VertexId, edge: E, ) -> Result> { - if src.to_usize() >= self.vertices.len() { + if src.as_usize() >= self.vertices.len() { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::SourceAbsent)); } - if dst.to_usize() >= self.vertices.len() { + if dst.as_usize() >= self.vertices.len() { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::DestinationAbsent)); } - let id = IntegerIdType::from_usize(self.edges.len()); + let id = IdType::from_usize(self.edges.len()); self.edges.push(edge); self.endpoints.push([*src, *dst]); let directions = Self::directions(); - self.vertices[src.to_usize()].edges[directions[0].index()].push(id); - self.vertices[dst.to_usize()].edges[directions[1].index()].push(id); + self.vertices[src.as_usize()].edges[directions[0].index()].push(id); + self.vertices[dst.as_usize()].edges[directions[1].index()].push(id); Ok(id) } @@ -394,7 +394,7 @@ where fn neighbors(&self, src: &Self::VertexId) -> Self::NeighborsIter<'_> { let vertex = self .vertices - .get(src.to_usize()) + .get(src.as_usize()) .expect("vertex does not exist"); NeighborsIter { @@ -409,7 +409,7 @@ where fn neighbors_directed(&self, src: &Self::VertexId, dir: Direction) -> Self::NeighborsIter<'_> { let vertex = self .vertices - .get(src.to_usize()) + .get(src.as_usize()) .expect("vertex does not exist"); let adj_dir = if !Ty::is_directed() { @@ -443,7 +443,7 @@ where fn degree_directed(&self, id: &Self::VertexId, dir: Direction) -> usize { let vertex = self .vertices - .get(id.to_usize()) + .get(id.as_usize()) .expect("vertex does not exist"); let adj_dir = if !Ty::is_directed() { @@ -518,7 +518,7 @@ where let (edge, tail) = self.edges.split_first()?; self.edges = tail; - let endpoints = self.endpoints[edge.to_usize()]; + let endpoints = self.endpoints[edge.as_usize()]; if endpoints[0] == self.src && endpoints[1] == self.dst { return Some(*edge); @@ -559,7 +559,7 @@ where self.edges[self.dir] = tail; let edge = head[0]; - let endpoints = self.endpoints[edge.to_usize()]; + let endpoints = self.endpoints[edge.as_usize()]; let neighbor = if endpoints[0] != self.src { endpoints[0] diff --git a/gryf/src/storage/adj_matrix.rs b/gryf/src/storage/adj_matrix.rs index ab37f58..482c950 100644 --- a/gryf/src/storage/adj_matrix.rs +++ b/gryf/src/storage/adj_matrix.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::{ common::CompactIdMap, core::{ - id::{DefaultId, GraphIdTypes, IntegerIdType}, + id::{DefaultId, GraphIdTypes, IdType, IntegerIdType}, marker::{Direction, EdgeType}, AddEdgeError, AddEdgeErrorKind, AddVertexError, ConnectVertices, Create, Edges, EdgesBase, EdgesMut, GraphBase, Guarantee, Neighbors, Vertices, VerticesBase, VerticesMut, @@ -94,7 +94,7 @@ where V: 'a; fn vertex(&self, id: &Self::VertexId) -> Option<&V> { - self.vertices.get(id.to_usize()) + self.vertices.get(id.as_usize()) } fn vertices(&self) -> Self::VerticesIter<'_> { @@ -108,7 +108,7 @@ where Id::EdgeId: IntegerIdType, { fn vertex_mut(&mut self, id: &Self::VertexId) -> Option<&mut V> { - self.vertices.get_mut(id.to_usize()) + self.vertices.get_mut(id.as_usize()) } fn try_add_vertex(&mut self, vertex: V) -> Result> { @@ -122,7 +122,7 @@ where fn remove_vertex(&mut self, id: &Self::VertexId) -> Option { self.vertex(id)?; - let index = id.to_usize(); + let index = id.as_usize(); // Remove incident edges. for i in 0..self.vertices.len() { @@ -197,7 +197,7 @@ where } fn edge_bound(&self) -> usize { - self.matrix.index(self.vertex_count(), 0).to_usize() + self.matrix.index(self.vertex_count(), 0).as_usize() } fn endpoints(&self, id: &Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> { @@ -210,7 +210,7 @@ where } fn edge_id(&self, src: &Self::VertexId, dst: &Self::VertexId) -> Self::EdgeIdIter<'_> { - let id = self.matrix.index(src.to_usize(), dst.to_usize()); + let id = self.matrix.index(src.as_usize(), dst.as_usize()); self.matrix.get(id).map(|_| id).into_iter() } @@ -268,15 +268,15 @@ where dst: &Self::VertexId, edge: E, ) -> Result> { - if src.to_usize() >= self.vertices.len() { + if src.as_usize() >= self.vertices.len() { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::SourceAbsent)); } - if dst.to_usize() >= self.vertices.len() { + if dst.as_usize() >= self.vertices.len() { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::DestinationAbsent)); } - let id = self.matrix.index(src.to_usize(), dst.to_usize()); + let id = self.matrix.index(src.as_usize(), dst.as_usize()); if self.matrix.contains(id) { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::MultiEdge)); @@ -498,8 +498,8 @@ where self.other += 1; let id = match self.dir { - Direction::Outgoing => self.matrix.index(self.src.to_usize(), dst), - Direction::Incoming => self.matrix.index(dst, self.src.to_usize()), + Direction::Outgoing => self.matrix.index(self.src.as_usize(), dst), + Direction::Incoming => self.matrix.index(dst, self.src.as_usize()), }; if self.matrix.contains(id) { @@ -517,7 +517,7 @@ mod raw { use bitvec::prelude::*; use crate::common::matrix::*; - use crate::core::id::{GraphIdTypes, IntegerIdType}; + use crate::core::id::{GraphIdTypes, IdType, IntegerIdType}; use crate::core::marker::{Direction, EdgeType}; #[derive(Debug)] @@ -753,23 +753,23 @@ mod raw { } pub fn contains(&self, id: Id::EdgeId) -> bool { - self.data.contains(id.to_usize()) + self.data.contains(id.as_usize()) } pub fn get(&self, id: Id::EdgeId) -> Option<&E> { - self.data.get(id.to_usize()) + self.data.get(id.as_usize()) } pub fn get_mut(&mut self, id: Id::EdgeId) -> Option<&mut E> { - self.data.get_mut(id.to_usize()) + self.data.get_mut(id.as_usize()) } pub fn insert(&mut self, id: Id::EdgeId, edge: E) { - self.data.insert(id.to_usize(), edge); + self.data.insert(id.as_usize(), edge); } pub fn remove(&mut self, id: Id::EdgeId) -> Option { - self.data.remove(id.to_usize()) + self.data.remove(id.as_usize()) } pub fn index(&self, row: usize, col: usize) -> Id::EdgeId { @@ -777,11 +777,11 @@ mod raw { } pub fn coords(&self, id: Id::EdgeId) -> (usize, usize) { - coords::(id.to_usize(), self.capacity) + coords::(id.as_usize(), self.capacity) } pub fn degree_directed(&self, v: Id::VertexId, dir: Direction, n_vertices: usize) -> usize { - let v = v.to_usize(); + let v = v.as_usize(); let mut degree = 0; if Ty::is_directed() { @@ -839,7 +839,7 @@ mod raw { Id::EdgeId: IntegerIdType, { pub fn contains(&self, id: Id::EdgeId) -> bool { - self.data[id.to_usize()] + self.data[id.as_usize()] } pub fn index(&self, row: usize, col: usize) -> Id::EdgeId { @@ -848,7 +848,7 @@ mod raw { #[allow(unused)] pub fn coords(&self, id: Id::EdgeId) -> (usize, usize) { - coords::(id.to_usize(), self.capacity) + coords::(id.as_usize(), self.capacity) } } diff --git a/gryf/src/storage/edge_list.rs b/gryf/src/storage/edge_list.rs index 0ad29a9..c3b80fc 100644 --- a/gryf/src/storage/edge_list.rs +++ b/gryf/src/storage/edge_list.rs @@ -2,7 +2,7 @@ use std::{iter::Enumerate, marker::PhantomData, slice}; use crate::common::CompactIdMap; use crate::core::{ - id::{DefaultId, GraphIdTypes, IntegerIdType}, + id::{DefaultId, GraphIdTypes, IdType, IntegerIdType}, marker::{Direction, EdgeType}, AddEdgeError, AddEdgeErrorKind, AddVertexError, ConnectVertices, Create, Edges, EdgesBase, EdgesMut, GraphBase, Guarantee, MultiEdges, Neighbors, Vertices, VerticesBase, VerticesMut, @@ -105,7 +105,7 @@ where V: 'a; fn vertex(&self, id: &Self::VertexId) -> Option<&V> { - self.vertices.get(id.to_usize()) + self.vertices.get(id.as_usize()) } fn vertices(&self) -> Self::VerticesIter<'_> { @@ -118,7 +118,7 @@ where Id::VertexId: IntegerIdType, { fn vertex_mut(&mut self, id: &Self::VertexId) -> Option<&mut V> { - self.vertices.get_mut(id.to_usize()) + self.vertices.get_mut(id.as_usize()) } fn try_add_vertex(&mut self, vertex: V) -> Result> { @@ -143,11 +143,11 @@ where } // Remove the vertex from the graph. - let vertex = self.vertices.swap_remove(id.to_usize()); + let vertex = self.vertices.swap_remove(id.as_usize()); // If `swap_remove` actually moved an existing vertex somewhere, we need // to fix its id in the entire graph. - if id.to_usize() < self.vertices.len() { + if id.as_usize() < self.vertices.len() { self.relocate_vertex(Id::VertexId::from_usize(self.vertices.len()), *id); } @@ -183,7 +183,7 @@ where fn endpoints(&self, id: &Id::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> { self.endpoints - .get(id.to_usize()) + .get(id.as_usize()) .map(|endpoints| (endpoints[0], endpoints[1])) } @@ -224,7 +224,7 @@ where E: 'a; fn edge(&self, id: &Self::EdgeId) -> Option<&E> { - self.edges.get(id.to_usize()) + self.edges.get(id.as_usize()) } fn edges(&self) -> Self::EdgesIter<'_> { @@ -238,7 +238,7 @@ where Id::EdgeId: IntegerIdType, { fn edge_mut(&mut self, id: &Self::EdgeId) -> Option<&mut E> { - self.edges.get_mut(id.to_usize()) + self.edges.get_mut(id.as_usize()) } fn try_add_edge( @@ -247,11 +247,11 @@ where dst: &Self::VertexId, edge: E, ) -> Result> { - if src.to_usize() >= self.vertices.len() { + if src.as_usize() >= self.vertices.len() { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::SourceAbsent)); } - if dst.to_usize() >= self.vertices.len() { + if dst.as_usize() >= self.vertices.len() { return Err(AddEdgeError::new(edge, AddEdgeErrorKind::DestinationAbsent)); } @@ -263,8 +263,8 @@ where fn remove_edge(&mut self, id: &Self::EdgeId) -> Option { self.edge(id)?; - self.endpoints.swap_remove(id.to_usize()); - Some(self.edges.swap_remove(id.to_usize())) + self.endpoints.swap_remove(id.as_usize()); + Some(self.edges.swap_remove(id.as_usize())) } fn clear_edges(&mut self) { diff --git a/gryf/src/storage/shared.rs b/gryf/src/storage/shared.rs index 55e053b..f71be31 100644 --- a/gryf/src/storage/shared.rs +++ b/gryf/src/storage/shared.rs @@ -6,7 +6,7 @@ use std::{ }; use crate::core::{ - id::{GraphIdTypes, IntegerIdType}, + id::{GraphIdTypes, IdType, IntegerIdType}, marker::EdgeType, }; @@ -71,7 +71,7 @@ where fn next(&mut self) -> Option { self.inner .next() - .map(|(id, vertex)| (IntegerIdType::from_usize(id), vertex)) + .map(|(id, vertex)| (IdType::from_usize(id), vertex)) } } @@ -96,7 +96,7 @@ where fn next(&mut self) -> Option { self.inner .next() - .map(|(id, vertex)| (IntegerIdType::from_usize(id), &vertex.data)) + .map(|(id, vertex)| (IdType::from_usize(id), &vertex.data)) } } @@ -122,12 +122,7 @@ where fn next(&mut self) -> Option { self.inner.next().map(|(index, (edge, endpoints))| { - ( - IntegerIdType::from_usize(index), - edge, - endpoints[0], - endpoints[1], - ) + (IdType::from_usize(index), edge, endpoints[0], endpoints[1]) }) } }