diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c77b8b9..044f1de 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,11 +3,11 @@ updates: - package-ecosystem: cargo directory: / schedule: - interval: weekly + interval: monthly - package-ecosystem: github-actions directory: / schedule: - interval: weekly + interval: monthly - package-ecosystem: cargo directory: /algae schedule: @@ -28,7 +28,3 @@ updates: directory: /mmr schedule: interval: weekly - - package-ecosystem: cargo - directory: /spline - schedule: - interval: weekly diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index a6300b0..12f2c40 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -1,8 +1,8 @@ name: Clippy concurrency: - group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} on: pull_request: diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml index db72159..8c3f8d8 100644 --- a/.github/workflows/crates.yml +++ b/.github/workflows/crates.yml @@ -1,11 +1,12 @@ -name: Publish +name: crates-io -concurrency: +concurrency: cancel-in-progress: true - group: ${{ github.event.repository.name }} + group: ${{ github.workflow }}-${{ github.ref }} env: CARGO_TERM_COLOR: always + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} on: release: @@ -28,11 +29,11 @@ jobs: matrix: feature: [ core ] env: - PACKAGE_NAME: ${{ github.event.repository.name }}-${{ matrix.feature }} + CRATE_NAME: ${{ github.event.repository.name }}-${{ matrix.feature }} steps: - uses: actions/checkout@v4 - - name: Publish (${{env.PACKAGE_NAME}}) - run: cargo publish --all-features -v -p ${{ env.PACKAGE_NAME }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + - name: Publish (${{env.CRATE_NAME}}) + run: cargo publish --all-features -v -p ${{ env.CRATE_NAME }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} features: name: Publish (features) runs-on: ubuntu-latest @@ -40,11 +41,11 @@ jobs: matrix: feature: [ graph, merkle, spline ] env: - PACKAGE_NAME: ${{ github.event.repository.name }}-${{ matrix.feature }} + CRATE_NAME: ${{ github.event.repository.name }}-${{ matrix.feature }} steps: - uses: actions/checkout@v4 - - name: Publish (${{env.PACKAGE_NAME}}) - run: cargo publish --all-features -v -p ${{ env.PACKAGE_NAME }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + - name: Publish (${{env.CRATE_NAME}}) + run: cargo publish --all-features -v -p ${{ env.CRATE_NAME }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} publish: name: Publish (sdk) needs: features diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f438d02..9ae5d71 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,16 +1,15 @@ -name: Rust +name: rust -concurrency: - cancel-in-progress: false - group: ${{ github.event.repository.name }}-rust +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} env: CARGO_TERM_COLOR: always on: - push: + pull_request: branches: [ main ] - tags: [ nightly*, v*.*.*] release: types: [ created ] repository_dispatch: @@ -22,39 +21,36 @@ on: permissions: write-all jobs: - build: - name: Build + workspace: + name: Workspace strategy: matrix: platform: [ ubuntu-latest ] - target: [ wasm32-unknown-unknown, wasm32-wasi ] toolchain: [ stable, nightly ] runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 - - name: setup (rustup) - run: rustup default ${{ matrix.toolchain }} && rustup update - - name: target (${{ matrix.target }}) + - name: rustup + run: | + rustup default ${{ matrix.toolchain }} + rustup update + - name: build + run: cargo build --all-features -r -v --workspace + - name: test + run: cargo test --all-features -r -v --workspace + - name: benchmark if: matrix.toolchain == 'nightly' - run: rustup target add ${{ matrix.target }} - - name: cargo (build) - run: cargo build --features full -r -v --workspace + run: cargo bench --features full -v --workspace - name: cache uses: actions/cache@v4 with: - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }} path: | ~/.cargo/registry ~/.cargo/git + target/debug target/release - - name: cargo (test) - run: cargo test --all-features -r -v --workspace - benchmark: - name: Bench - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: rustup default nightly && rustup update - - name: cargo (bench) - run: cargo bench --features full -v --workspace + restore-keys: | + ${{ runner.os }}-cargo-${{ matrix.toolchain }}- + ${{ runner.os }}-cargo- + ${{ runner.os }}- diff --git a/Cargo.toml b/Cargo.toml index 70cbc02..d15c6b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ members = [ "core", "graph", "merkle", - "spline", ] resolver = "2" diff --git a/README.md b/README.md index 3be349a..ff5f211 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,79 @@ [![crates.io](https://img.shields.io/crates/v/algae.svg)](https://crates.io/crates/algae) [![docs.rs](https://docs.rs/algae/badge.svg)](https://docs.rs/algae) +[![License](https://img.shields.io/crates/l/algae.svg)](https://crates.io/crates/algae) + [![Clippy](https://github.com/FL03/algae/actions/workflows/clippy.yml/badge.svg)](https://github.com/FL03/algae/actions/workflows/clippy.yml) [![Rust](https://github.com/FL03/algae/actions/workflows/rust.yml/badge.svg)](https://github.com/FL03/algae/actions/workflows/rust.yml) *** +_**Warning: the library is currently in development and the API is subject to heavy changes!**_ + Welcome to algae, a collection of optimized data-structures and algorithms intended for use within blockchain environments. +## Features + +- [ ] `graph` - a hyper-graph implementation written in pure Rust. +- [ ] `merkle` - an optimized merkle tree library +- [ ] `mmr` - a merkle mountain range implementation + ## Getting Started ### Build from the source -#### _Clone the repository_ +Start by cloning the repository: ```bash - git clone https://github.com/FL03/algae + git clone https://github.com/FL03/algae.git ``` -#### _Build the project_ +Then, build the project using cargo: ```bash - cargo build --release + cargo build --all-features --workspace +``` + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies.algae] +features = [] +version = "0.1" +``` + +### Examples + +#### _HyperGraph: Basic Usage_ + +```rust +extern crate algae; + +use algae::graph::HyperGraph; + +fn main() -> Result<(), Box> { + // Create a new graph + let mut graph = HyperGraph::new(); + + Ok(()) +} +``` + +#### _MerkleTree: Basic Usage_ + +```rust +extern crate algae; + +use algae::merkle::MerkleTree; + +fn main() -> Result<(), Box> { + // Create a new merkle tree + let mut merkle = MerkleTree::new(); + + Ok(()) +} ``` ## Contributors @@ -30,8 +82,3 @@ Welcome to algae, a collection of optimized data-structures and algorithms inten Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate. - -## License - -- [Apache-2.0](https://choosealicense.com/licenses/apache-2.0/) -- [MIT](https://choosealicense.com/licenses/mit/) diff --git a/algae/Cargo.toml b/algae/Cargo.toml index cc888ff..8030bf5 100644 --- a/algae/Cargo.toml +++ b/algae/Cargo.toml @@ -42,10 +42,6 @@ merkle = [ # "dep:algae-mmr" # ] -spline = [ - "dep:algae-spline", -] - serde = [ "algae-core/serde", "algae-graph?/serde", @@ -99,12 +95,6 @@ version = "0.1.20" # path = "../mmr" # version = "0.1.20" -[dependencies.algae-spline] -default-features = false -optional = true -path = "../spline" -version = "0.1.20" - [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] diff --git a/algae/src/lib.rs b/algae/src/lib.rs index 2527e38..55b3cd1 100644 --- a/algae/src/lib.rs +++ b/algae/src/lib.rs @@ -13,8 +13,6 @@ pub use algae_graph as graph; pub use algae_merkle as merkle; // #[cfg(feature = "mmr")] // pub use algae_mmr as mmr; -#[cfg(feature = "spline")] -pub use algae_spline as spline; pub mod list; @@ -26,8 +24,6 @@ pub mod prelude { pub use algae_merkle::prelude::*; // #[cfg(feature = "mmr")] // pub use algae_mmr::*; - #[cfg(feature = "spline")] - pub use algae_spline::prelude::*; pub use crate::list::*; } diff --git a/graph/Cargo.toml b/graph/Cargo.toml index 77431cd..8c116f6 100644 --- a/graph/Cargo.toml +++ b/graph/Cargo.toml @@ -21,12 +21,19 @@ full = [ "serde", ] +# ********* [FF] Dependencies ********* +alloc = [ + "serde?/alloc", + "strum/alloc", +] + serde = [ "dep:serde", - "dep:serde_json" ] +# ********* [FF] Environments ********* std = [ + "alloc", "serde?/std", "strum/std", ] @@ -45,9 +52,8 @@ test = true [dependencies] itertools.workspace = true -serde_json = { optional = true, version = "1" } smart-default.workspace = true -strum.workspace = true +thiserror = "1" [dependencies.serde] default-features = false @@ -55,6 +61,11 @@ optional = true features = ["derive"] version = "1" +[dependencies.strum] +default-features = false +features = ["derive"] +version = "0.26" + [dev-dependencies] [package.metadata.docs.rs] diff --git a/graph/src/algo/mod.rs b/graph/src/algo/mod.rs deleted file mode 100644 index 430ab60..0000000 --- a/graph/src/algo/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -/* - Appellation: algo - Contrib: FL03 -*/ - -pub mod search; -pub mod toposort; - -pub(crate) mod prelude { - pub use super::search::*; -} diff --git a/graph/src/algo/search/bfs.rs b/graph/src/algo/search/bfs.rs deleted file mode 100644 index 16af5d6..0000000 --- a/graph/src/algo/search/bfs.rs +++ /dev/null @@ -1,83 +0,0 @@ -/* - Appellation: bfs - Contrib: FL03 -*/ -use super::Searcher; -use crate::prelude::{Contain, Graph, Node, Weight}; -use std::collections::{HashSet, VecDeque}; - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct BreadthFirstSearch { - queue: VecDeque, - visited: HashSet, -} - -impl BreadthFirstSearch { - pub fn new() -> Self { - Self { - queue: VecDeque::new(), - visited: HashSet::new(), - } - } -} - -impl Contain for BreadthFirstSearch { - fn contains(&self, elem: &N) -> bool { - self.visited.contains(elem) - } -} - -impl Searcher for BreadthFirstSearch -where - N: Node, - V: Weight, -{ - fn reset(&mut self) { - self.visited.clear(); - self.queue.clear(); - } - fn search(&mut self, graph: impl Graph, start: N) -> Vec { - self.queue.push_back(start); - - while let Some(node) = self.queue.pop_front() { - if !self.visited.contains(&node) { - self.visited.insert(node.clone()); - - if let Some(edges) = graph.store().get(&node) { - for (n, _) in edges { - self.queue.push_back(n.clone()); - } - } - } - } - - self.visited.iter().cloned().collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cmp::Edge; - use crate::DirectedGraph; - - const TEST_EDGES: [(&str, &str, usize); 5] = [ - ("a", "b", 5), - ("c", "a", 7), - ("b", "c", 10), - ("d", "c", 10), - ("e", "f", 10), - ]; - - #[test] - fn test_bfs_directed() { - let mut graph = DirectedGraph::<&str, usize>::new(); - for i in TEST_EDGES { - graph.add_edge(Edge::from(i)); - } - let mut bfs = BreadthFirstSearch::new(); - bfs.search(graph, "a"); - assert!(bfs.all(["b", "c", "a"])); - } -} diff --git a/graph/src/algo/search/dfs.rs b/graph/src/algo/search/dfs.rs deleted file mode 100644 index 98d9890..0000000 --- a/graph/src/algo/search/dfs.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - Appellation: dfs - Contrib: FL03 -*/ -use super::Searcher; -use crate::{Contain, Graph, Node, Weight}; - -#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct DepthFirstSearch { - stack: Vec, - visited: Vec, -} - -impl DepthFirstSearch { - pub fn new() -> Self { - Self { - stack: Vec::new(), - visited: Vec::new(), - } - } -} - -impl Contain for DepthFirstSearch { - fn contains(&self, elem: &N) -> bool { - self.visited.contains(elem) - } -} - -impl Searcher for DepthFirstSearch -where - N: Node, - V: Weight, -{ - fn reset(&mut self) { - self.stack.clear(); - self.visited.clear(); - } - - fn search(&mut self, graph: impl Graph, start: N) -> Vec { - self.stack.push(start); - while let Some(node) = self.stack.pop() { - if !self.visited.contains(&node) { - self.visited.push(node.clone()); - if let Ok(neighbor) = graph.neighbors(node) { - for (node, _) in neighbor { - self.stack.push(node.clone()); - } - } - } - } - self.visited.clone() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{DirectedGraph, Edge}; - - const TEST_EDGES: [(&str, &str, usize); 5] = [ - ("a", "b", 5), - ("c", "a", 7), - ("b", "c", 10), - ("d", "c", 10), - ("e", "f", 10), - ]; - - #[test] - fn test_dfs_directed() { - let mut graph = DirectedGraph::<&str, usize>::new(); - for i in TEST_EDGES { - graph.add_edge(Edge::from(i)); - } - // - let mut dfs = DepthFirstSearch::new(); - // - dfs.search(graph, "a"); - // - assert!(dfs.all(["b", "c", "a"])); - } -} diff --git a/graph/src/algo/search/mod.rs b/graph/src/algo/search/mod.rs deleted file mode 100644 index 175abaf..0000000 --- a/graph/src/algo/search/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - Appellation: search - Contrib: FL03 -*/ -pub use self::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}; - -pub(crate) mod bfs; -pub(crate) mod dfs; - -use crate::{Contain, Graph, Node, Weight}; - -/// [Searcher] is a trait that defines the behavior of a graph search algorithm. -pub trait Searcher: Contain -where - N: Node, - V: Weight, -{ - /// Search the graph for nodes. - fn search(&mut self, graph: impl Graph, start: N) -> Vec; - /// Reset the search state. - fn reset(&mut self); -} diff --git a/graph/src/algo/toposort.rs b/graph/src/algo/toposort.rs deleted file mode 100644 index 0a42d1d..0000000 --- a/graph/src/algo/toposort.rs +++ /dev/null @@ -1,63 +0,0 @@ -/* - Appellation: algo - Contrib: FL03 -*/ -use crate::errors::CycleError; -use core::hash::Hash; -use std::collections::{HashMap, VecDeque}; - -/// Given a directed graph, modeled as a list of edges from source to destination -/// Uses Kahn's algorithm to either: -/// return the topological sort of the graph -/// or detect if there's any cycle -pub fn topological_sort( - edges: &Vec<(Node, Node)>, -) -> Result, CycleError> { - // Preparation: - // Build a map of edges, organised from source to destinations - // Also, count the number of incoming edges by node - let mut edges_by_source: HashMap> = HashMap::default(); - let mut incoming_edges_count: HashMap = HashMap::default(); - for (source, destination) in edges { - incoming_edges_count.entry(*source).or_insert(0); // if we haven't seen this node yet, mark it as having 0 incoming nodes - edges_by_source // add destination to the list of outgoing edges from source - .entry(*source) - .or_default() - .push(*destination); - // then make destination have one more incoming edge - *incoming_edges_count.entry(*destination).or_insert(0) += 1; - } - - // Now Kahn's algorithm: - // Add nodes that have no incoming edges to a queue - let mut no_incoming_edges_q = VecDeque::default(); - for (node, count) in &incoming_edges_count { - if *count == 0 { - no_incoming_edges_q.push_back(*node); - } - } - // For each node in this "O-incoming-edge-queue" - let mut sorted = Vec::default(); - while let Some(no_incoming_edges) = no_incoming_edges_q.pop_back() { - sorted.push(no_incoming_edges); // since the node has no dependency, it can be safely pushed to the sorted result - incoming_edges_count.remove(&no_incoming_edges); - // For each node having this one as dependency - for neighbour in edges_by_source.get(&no_incoming_edges).unwrap_or(&vec![]) { - if let Some(count) = incoming_edges_count.get_mut(neighbour) { - *count -= 1; // decrement the count of incoming edges for the dependent node - if *count == 0 { - // `node` was the last node `neighbour` was dependent on - incoming_edges_count.remove(neighbour); // let's remove it from the map, so that we can know if we covered the whole graph - no_incoming_edges_q.push_front(*neighbour); // it has no incoming edges anymore => push it to the queue - } - } - } - } - if incoming_edges_count.is_empty() { - // we have visited every node - Ok(sorted) - } else { - // some nodes haven't been visited, meaning there's a cycle in the graph - Err(CycleError::CycleDetected) - } -} diff --git a/graph/src/cmp/edge.rs b/graph/src/cmp/edge.rs deleted file mode 100644 index 670d5db..0000000 --- a/graph/src/cmp/edge.rs +++ /dev/null @@ -1,87 +0,0 @@ -/* - Appellation: edge - Contrib: FL03 - Description: an edge consists of two nodes and an optional edge value -*/ -//! # Edge -//! -//! -use super::Pair; -use crate::{Node, Weight}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -pub trait Related {} - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub struct Edge -where - N: Node, - V: Weight, -{ - pair: Pair, - weight: V, -} - -impl Edge -where - N: Node, - V: Weight, -{ - pub fn new(a: N, b: N, weight: V) -> Self { - Self { - pair: Pair::new(a, b), - weight, - } - } - pub fn pair(&self) -> Pair { - self.pair.clone() - } - pub fn value(&self) -> &V { - &self.weight - } -} - -impl AsMut> for Edge -where - N: Node, - V: Weight, -{ - fn as_mut(&mut self) -> &mut Pair { - &mut self.pair - } -} - -impl AsRef> for Edge -where - N: Node, - V: Weight, -{ - fn as_ref(&self) -> &Pair { - &self.pair - } -} - -impl From<(N, N, V)> for Edge -where - N: Node, - V: Weight, -{ - fn from(data: (N, N, V)) -> Self { - Self::new(data.0, data.1, data.2) - } -} - -impl From<(Pair, V)> for Edge -where - N: Node, - V: Weight, -{ - fn from(data: (Pair, V)) -> Self { - Self { - pair: data.0, - weight: data.1, - } - } -} diff --git a/graph/src/cmp/entry.rs b/graph/src/cmp/entry.rs deleted file mode 100644 index 6b167d9..0000000 --- a/graph/src/cmp/entry.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* - Appellation: entry - Contrib: FL03 -*/ -//! # Entry -//! -//! -use crate::prelude::Contain; - -#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Entry { - key: N, - value: Vec<(N, V)>, -} - -impl Entry { - pub fn new(key: N, value: Vec<(N, V)>) -> Self { - Self { key, value } - } - pub fn key(&self) -> &N { - &self.key - } - pub fn value(&self) -> &Vec<(N, V)> { - &self.value - } - pub fn value_mut(&mut self) -> &mut Vec<(N, V)> { - &mut self.value - } -} - -impl Contain for Entry -where - N: PartialEq, -{ - fn contains(&self, node: &N) -> bool { - self.value.iter().any(|(n, _)| n == node) - } -} diff --git a/graph/src/cmp/mod.rs b/graph/src/cmp/mod.rs deleted file mode 100644 index c668049..0000000 --- a/graph/src/cmp/mod.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - Appellation: cmp - Contrib: FL03 - Description: components (cmp) for building effecient graph data-structures -*/ -//! # Components (cmp) -//! -//! -pub use self::{edge::*, pair::*}; - -pub(crate) mod edge; -pub(crate) mod pair; - -pub mod entry; - -pub trait GraphIndex {} - -pub trait GraphEntry { - type Key: GraphIndex; - type Value; - - fn key(&self) -> &Self::Key; - - fn value(&self) -> &Self::Value; - - fn value_mut(&mut self) -> &mut Self::Value; -} - -pub(crate) mod prelude { - pub use super::edge::*; - pub use super::entry::*; - pub use super::pair::*; - pub use super::{GraphEntry, GraphIndex}; -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_edge() { - let a = "a"; - let b = "b"; - let weight = 1; - let edge = Edge::new(a, b, weight); - assert_eq!(edge.pair(), Pair::new(a, b)); - assert_eq!(edge.value(), &weight); - } -} diff --git a/graph/src/cmp/pair.rs b/graph/src/cmp/pair.rs deleted file mode 100644 index f6666c2..0000000 --- a/graph/src/cmp/pair.rs +++ /dev/null @@ -1,41 +0,0 @@ -/* - Appellation: pair - Contrib: FL03 - Description: a pair can either be scalar or vector; if vector, than direction matters -*/ -//! # Pair -use crate::Node; - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Pair(pub T, pub T) -where - T: Node; - -impl Pair -where - T: Node, -{ - pub fn new(a: T, b: T) -> Self { - Self(a, b) - } - pub fn reverse(&mut self) { - std::mem::swap(&mut self.0, &mut self.1) - } - pub fn reverse_mut(&mut self) -> &mut Self { - self.reverse(); - self - } - pub fn pair(&self) -> (T, T) { - (self.0.clone(), self.1.clone()) - } -} - -impl From<(T, T)> for Pair -where - T: Node, -{ - fn from(data: (T, T)) -> Self { - Self(data.0, data.1) - } -} diff --git a/graph/src/directed.rs b/graph/src/directed.rs deleted file mode 100644 index fa25172..0000000 --- a/graph/src/directed.rs +++ /dev/null @@ -1,184 +0,0 @@ -/* - Appellation: directed - Contrib: FL03 -*/ -use crate::{store::AdjacencyTable, Edge, Node, Weight}; -use crate::{Contain, Graph, GraphExt, Subgraph}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub struct DirectedGraph -where - N: Node, - V: Weight, -{ - store: AdjacencyTable, -} - -impl DirectedGraph -where - N: Node, - V: Weight, -{ - pub fn new() -> Self { - Self { - store: AdjacencyTable::new(), - } - } - pub fn with_capacity(capacity: usize) -> Self { - Self { - store: AdjacencyTable::with_capacity(capacity), - } - } -} - -impl AsMut> for DirectedGraph -where - N: Node, - V: Weight, -{ - fn as_mut(&mut self) -> &mut AdjacencyTable { - &mut self.store - } -} - -impl AsRef> for DirectedGraph -where - N: Node, - V: Weight, -{ - fn as_ref(&self) -> &AdjacencyTable { - &self.store - } -} - -impl Contain for DirectedGraph -where - N: Node, - V: Weight, -{ - fn contains(&self, elem: &N) -> bool { - self.store.contains_key(elem) - } -} - -impl Contain> for DirectedGraph -where - N: Node, - V: Weight, -{ - fn contains(&self, elem: &Edge) -> bool { - self.edges().contains(elem) - } -} - -impl Graph for DirectedGraph -where - N: Node, - V: Weight, -{ - fn store_mut(&mut self) -> &mut AdjacencyTable { - &mut self.store - } - fn store(&self) -> &AdjacencyTable { - &self.store - } -} - -impl GraphExt for DirectedGraph -where - N: Node, - V: Weight, -{ -} - -impl Subgraph for DirectedGraph -where - N: Node, - V: Weight, -{ -} - -impl From> for DirectedGraph -where - N: Node, - V: Weight, -{ - fn from(store: AdjacencyTable) -> Self { - Self { store } - } -} - -impl std::ops::Index for DirectedGraph -where - N: Node, - V: Weight, -{ - type Output = Vec<(N, V)>; - - fn index(&self, index: N) -> &Self::Output { - self.store.get(&index).unwrap() - } -} - -impl std::ops::IndexMut for DirectedGraph -where - N: Node, - V: Weight, -{ - fn index_mut(&mut self, index: N) -> &mut Self::Output { - self.store.get_mut(&index).unwrap() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - const TEST_EDGES: [(&str, &str, usize); 3] = [("a", "b", 5), ("c", "a", 7), ("b", "c", 10)]; - - #[test] - fn test_add_node() { - let mut graph = DirectedGraph::<&str, i64>::new(); - graph.add_node("a"); - graph.add_node("b"); - graph.add_node("c"); - assert_eq!(graph.nodes(), ["a", "b", "c"].iter().cloned().collect()); - } - - #[test] - fn test_add_edge() { - let mut graph = DirectedGraph::new(); - - for i in TEST_EDGES { - graph.add_edge(i.into()); - } - for edge in TEST_EDGES { - assert!(graph.contains(&Edge::from(edge))); - } - } - - #[test] - fn test_neighbours() { - let mut graph = DirectedGraph::new(); - - for i in TEST_EDGES { - graph.add_edge(i.into()); - } - - assert_eq!(graph.neighbors("a").unwrap(), &vec![("b", 5)]); - } - - #[test] - fn test_contains() { - let mut graph = DirectedGraph::<&str, i64>::new(); - graph.add_node("a"); - graph.add_node("b"); - graph.add_node("c"); - assert!(graph.all(["a", "b", "c"])); - assert!(graph.any(["a", "b", "c", "d"])); - assert!(graph.remove_node(&"a").is_ok()); - } -} diff --git a/graph/src/error.rs b/graph/src/error.rs new file mode 100644 index 0000000..0e5445b --- /dev/null +++ b/graph/src/error.rs @@ -0,0 +1,13 @@ +/* + Appellation: error + Contrib: FL03 +*/ + +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::EnumIs, thiserror::Error)] +pub enum GraphError { + + #[error("[CycleError] {0}")] + CycleError(String), + #[error("[UnknownError] {0}")] + Unknown(String) +} \ No newline at end of file diff --git a/graph/src/errors.rs b/graph/src/errors.rs deleted file mode 100644 index ea01653..0000000 --- a/graph/src/errors.rs +++ /dev/null @@ -1,60 +0,0 @@ -/* - Appellation: errors - Contrib: FL03 -*/ -pub use self::cycle::*; - -pub(crate) mod cycle; - -use smart_default::SmartDefault; -use strum::{Display, EnumCount, EnumIs, EnumIter, EnumString, VariantNames}; - -#[derive( - Clone, - Debug, - Display, - EnumCount, - EnumIs, - EnumIter, - EnumString, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - SmartDefault, - VariantNames, -)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "snake_case") -)] -#[strum(serialize_all = "snake_case")] -pub enum GraphError { - Cycle(CycleError), - NodeInGraph, - #[default] - NodeNotInGraph, - Unknown(String), -} - -#[cfg(feature = "std")] -impl std::error::Error for GraphError {} - -macro_rules! impl_from_err { - ($($variant:ident<$err:ident>),*) => { - $( - impl_from_err!(@impl $variant<$err>); - )* - }; - (@impl $variant:ident<$err:ident>) => { - impl From<$err> for GraphError { - fn from(err: $err) -> Self { - Self::$variant(err) - } - } - }; -} - -impl_from_err!(Cycle); diff --git a/graph/src/errors/cycle.rs b/graph/src/errors/cycle.rs deleted file mode 100644 index 57f726e..0000000 --- a/graph/src/errors/cycle.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - Appellation: algo - Contrib: FL03 -*/ -use strum::{Display, EnumCount, EnumIs, EnumIter, EnumString, VariantNames}; - -#[derive( - Clone, - Copy, - Debug, - Default, - Display, - EnumCount, - EnumIs, - EnumIter, - EnumString, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - VariantNames, -)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "snake_case") -)] -#[repr(C)] -#[strum(serialize_all = "snake_case")] -pub enum CycleError { - #[default] - CycleDetected, -} - -#[cfg(feature = "std")] -impl std::error::Error for CycleError {} diff --git a/graph/src/graph/mod.rs b/graph/src/graph/mod.rs deleted file mode 100644 index 862cbde..0000000 --- a/graph/src/graph/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -/* - Appellation: graph - Contrib: FL03 - Description: This module implements an abstract graph data structure -*/ -use crate::cmp::entry::Entry; -use strum::{Display, EnumCount, EnumIs, EnumIter, EnumString, VariantNames}; - -pub trait GraphStore: Default { - fn capacity(&self) -> usize; - fn clear(&mut self); - fn dim(&self) -> (usize, usize); - fn get_entries(&self, key: &N) -> Option<&Entry>; -} - -#[derive( - Clone, - Copy, - Debug, - Default, - Display, - EnumCount, - EnumIs, - EnumIter, - EnumString, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - VariantNames, -)] -#[repr(u8)] -#[strum(serialize_all = "snake_case")] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "lowercase", untagged) -)] -pub enum GraphType { - Directed, - #[default] - Undirected, -} diff --git a/graph/src/hyper/graph.rs b/graph/src/hyper/graph.rs new file mode 100644 index 0000000..0c6f6ee --- /dev/null +++ b/graph/src/hyper/graph.rs @@ -0,0 +1,9 @@ +/* + Appellation: graph + Contrib: FL03 +*/ + + +pub struct HyperGraph { + +} \ No newline at end of file diff --git a/graph/src/hyper/mod.rs b/graph/src/hyper/mod.rs new file mode 100644 index 0000000..8fa3465 --- /dev/null +++ b/graph/src/hyper/mod.rs @@ -0,0 +1,15 @@ +/* + Appellation: hyper + Contrib: FL03 +*/ +//! # HyperGraphs +//! +//! +#[doc(inline)] +pub use self::graph::HyperGraph; + +mod graph; + +pub(crate) mod prelude { + pub use crate::graph::HyperGraph; +} \ No newline at end of file diff --git a/graph/src/lib.rs b/graph/src/lib.rs index 214d012..37f981f 100644 --- a/graph/src/lib.rs +++ b/graph/src/lib.rs @@ -3,219 +3,16 @@ Contrib: FL03 */ //! # Graph +//! +//! This library focuses on implementing hyper-graphs //! -#[cfg(not(feature = "std"))] +#[cfg(feature = "alloc")] extern crate alloc; -pub use self::{directed::*, errors::GraphError, specs::*, undirected::*}; - -pub(crate) mod directed; -pub(crate) mod specs; -pub(crate) mod undirected; - -pub mod algo; -pub mod cmp; -pub mod errors; -pub mod graph; -pub mod store; - -use cmp::Edge; -use std::{collections::HashSet, ops::IndexMut}; -use store::AdjacencyTable; - -/// [Graph] describes the basic operations of a graph data-structure -pub trait Graph: - AsMut> - + Clone - + Contain - + Contain> - + IndexMut> -where - N: Node, - V: Weight, -{ - /// [Graph::add_edge] inserts a new [Edge] into the graph - fn add_edge(&mut self, edge: Edge) { - let pair = edge.pair(); - self.add_node(pair.0.clone()); - self.add_node(pair.1.clone()); - - self.store_mut().entry(pair.0.clone()).and_modify(|e| { - e.push((pair.1, edge.value().clone())); - }); - } - /// [Graph::add_edges] insert several edges into the graph - fn add_edges(&mut self, iter: impl IntoIterator>) { - for i in iter { - self.add_edge(i) - } - } - /// [Graph::add_node] if the given [Node] is not already in the [Graph], insert the [Node] and return true; else return false - fn add_node(&mut self, node: N) -> bool { - match self.store().get(&node) { - None => { - self.store_mut().insert(node, Vec::new()); - true - } - _ => false, - } - } - /// [Graph::add_nodes] insert several nodes into the graph - fn add_nodes(&mut self, iter: impl IntoIterator) { - for i in iter { - self.add_node(i); - } - } - /// [Graph::contains_edge] returns true if the given [Edge] is in the graph - fn contains_edge(&self, edge: &Edge) -> bool { - match self.store().get(&edge.pair().0) { - Some(edges) => edges.contains(&(edge.pair().1, edge.value().clone())), - None => false, - } - } - /// [Graph::contains_node] returns true if the given [Node] is in the graph - fn contains_node(&self, node: &N) -> bool { - self.store().contains_key(node) - } - /// [Graph::degree] returns the degree of the given [Node] - fn degree(&self, node: &N) -> Result { - match self.store().get(node) { - Some(edges) => Ok(edges.len()), - None => Err(GraphError::NodeNotInGraph), - } - } - /// [Graph::edges] returns all of the edges persisting within the graph - fn edges(&self) -> Vec> { - let mut edges = Vec::new(); - for (from_node, from_node_neighbours) in self.store().clone() { - for (to_node, weight) in from_node_neighbours { - edges.push((from_node.clone(), to_node, weight).into()); - } - } - edges - } - /// [Graph::edges_from] returns all of the edges originating from the given [Node] - fn edges_from(&self, node: &N) -> Result>, GraphError> { - match self.store().get(node) { - Some(edges) => Ok(edges - .iter() - .cloned() - .map(|(n, v)| Edge::new(node.clone(), n, v)) - .collect()), - None => Err(GraphError::NodeNotInGraph), - } - } - /// [Graph::edges_to] returns all of the edges terminating at the given [Node] - fn edges_to(&self, node: &N) -> Result>, GraphError> { - let mut edges = Vec::new(); - for (origin, neighbours) in self.store().clone() { - for (dest, weight) in neighbours { - if &dest == node { - edges.push((origin.clone(), dest, weight).into()); - } - } - } - Ok(edges) - } - /// [Graph::is_connected] returns true if the graph is connected - fn is_connected(&self) -> bool { - let mut visited = HashSet::new(); - let mut stack = self.nodes().iter().cloned().collect::>(); - - while let Some(node) = stack.pop() { - if !visited.contains(&node) { - visited.insert(node.clone()); - stack.extend( - self.neighbors(node) - .unwrap() - .iter() - .map(|(n, _)| n) - .cloned(), - ); - } - } - - visited.len() == self.nodes().len() - } - /// [Graph::remove_edge] attempts to remove an edge from the graph - fn remove_edge(&mut self, edge: &Edge) -> Result<(), GraphError> { - match self.store_mut().get_mut(&edge.pair().0) { - Some(edges) => { - edges.retain(|(n, _)| n != &edge.pair().1); - Ok(()) - } - None => Err(GraphError::NodeNotInGraph), - } - } - /// [Graph::remove_edges] attempts to remove several edges from the graph - fn remove_edges( - &mut self, - iter: impl IntoIterator>, - ) -> Result<(), GraphError> { - for i in iter { - self.remove_edge(&i)?; - } - Ok(()) - } - /// [Graph::remove_node] attempts to remove a node from the graph - fn remove_node(&mut self, node: &N) -> Result<(), GraphError> { - if self.contains_node(node) { - self.store_mut().remove(node); - for (_, edges) in self.store_mut().iter_mut() { - edges.retain(|(n, _)| n != node); - } - Ok(()) - } else { - Err(GraphError::NodeNotInGraph) - } - } - /// [Graph::remove_nodes] attempts to remove several nodes from the graph - fn remove_nodes(&mut self, iter: impl IntoIterator) -> Result<(), GraphError> { - for i in iter { - self.remove_node(&i)?; - } - Ok(()) - } - /// [Graph::store_mut] returns an owned, mutable instance of the [AdjacencyTable] - fn store_mut(&mut self) -> &mut AdjacencyTable; - /// [Graph::store] returns an owned instance of the [AdjacencyTable] - fn store(&self) -> &AdjacencyTable; - /// [Graph::neighbors] attempts to return a [Vec] that contains all of the connected [Node] and their values - fn neighbors(&self, node: N) -> Result<&Vec<(N, V)>, GraphError> { - if self.nodes().contains(&node) { - Ok(&self[node]) - } else { - Err(GraphError::NodeNotInGraph) - } - } - /// [Graph::nodes] returns a cloned [HashSet] of the graph's current [Node]s - fn nodes(&self) -> HashSet { - self.store().keys().cloned().collect() - } -} - -pub trait GraphExt: Graph -where - N: Node, - V: Weight, -{ -} - -pub trait Subgraph: Graph -where - N: Node, - V: Weight, -{ - fn is_subgraph(&self, graph: impl Graph) -> bool { - self.nodes().is_subset(&graph.nodes()) - } -} +pub mod error; +pub mod hyper; +pub mod types; pub mod prelude { - pub use crate::algo::prelude::*; - pub use crate::cmp::prelude::*; - pub use crate::directed::*; - pub use crate::errors::*; - pub use crate::specs::*; - pub use crate::{Graph, GraphExt, Subgraph}; -} + +} \ No newline at end of file diff --git a/graph/src/specs.rs b/graph/src/specs.rs deleted file mode 100644 index f9951be..0000000 --- a/graph/src/specs.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - Appellation: specs - Contrib: FL03 -*/ - -pub trait Contain -where - T: PartialEq, -{ - /// [contains](Contain::contains) returns true if the given element is in the collection - fn contains(&self, elem: &T) -> bool; - /// [all](Contain::all) returns true if all elements in the iterator are in the collection - fn all(&self, iter: impl IntoIterator) -> bool { - iter.into_iter().all(|i| self.contains(&i)) - } - /// [any](Contain::any) returns true if *any* element in the given iterator is in the [Contain] instance - fn any(&self, iter: impl IntoIterator) -> bool { - iter.into_iter().any(|i| self.contains(&i)) - } -} - -/// [Node] describes compatible vertices of the [crate::Graph] -pub trait Node: Clone + Default + Eq + core::hash::Hash {} - -impl Node for T where T: Clone + Default + Eq + core::hash::Hash {} - -pub trait Weight: Clone + PartialEq {} - -impl Weight for T where T: Clone + PartialEq {} diff --git a/graph/src/store/matrix.rs b/graph/src/store/matrix.rs deleted file mode 100644 index 1050df9..0000000 --- a/graph/src/store/matrix.rs +++ /dev/null @@ -1,111 +0,0 @@ -/* - Appellation: atable - Contrib: FL03 -*/ -//! # Adjacency Table -use crate::Node; -use core::ops::{Index, IndexMut}; - -#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct AdjacencyMatrix -where - N: Node, - V: Clone + PartialEq, -{ - store: Vec<(N, Vec<(N, V)>)>, -} - -impl AdjacencyMatrix { - pub fn new() -> Self { - Self { store: Vec::new() } - } - /// Clears the matrix, removing all elements. - pub fn clear(&mut self) { - self.store.clear() - } - /// Returns the number of elements the matrix can hold without reallocating. - pub fn capacity(&self) -> usize { - self.store.capacity() - } - /// Returns a reference to the value corresponding to the key. - pub fn get(&self, key: &N) -> Option<&Vec<(N, V)>> { - self.store - .iter() - .find_map(|(k, v)| if k == key { Some(v) } else { None }) - } - /// Returns a reference to the key and its value(s). - pub fn get_key_value(&self, key: &N) -> Option<(&N, &Vec<(N, V)>)> { - self.store - .iter() - .find_map(|(k, v)| if k == key { Some((k, v)) } else { None }) - } - /// Returns a mutable reference to the value corresponding to the key. - pub fn get_mut(&mut self, key: &N) -> Option<&mut Vec<(N, V)>> { - self.store - .iter_mut() - .find_map(|(k, v)| if k == key { Some(v) } else { None }) - } - /// Returns an iterator over the elements of the matrix. - pub fn keys(&self) -> impl Iterator { - self.store.iter().map(|(k, _)| k) - } - /// Returns the number of elements in the matrix. - pub fn len(&self) -> usize { - self.store.len() - } - /// Pushes a new element to the matrix. - pub fn push(&mut self, elem: N, value: Vec<(N, V)>) { - self.store.push((elem, value)); - } - /// Shrinks the capacity of the matrix as much as possible. - pub fn shrink_to_fit(&mut self) { - self.store.shrink_to_fit() - } - /// Reserves capacity for at least `additional` more elements to be inserted in the matrix. - pub fn with_capacity(capacity: usize) -> Self { - Self { - store: Vec::with_capacity(capacity), - } - } -} - -impl Extend<(N, Vec<(N, V)>)> for AdjacencyMatrix { - fn extend)>>(&mut self, iter: T) { - self.store.extend(iter); - } -} - -impl Index for AdjacencyMatrix -where - N: Node, - V: Clone + PartialEq, -{ - type Output = Vec<(N, V)>; - - fn index(&self, index: N) -> &Self::Output { - self.get(&index).unwrap() - } -} - -impl Index<&N> for AdjacencyMatrix -where - N: Node, - V: Clone + PartialEq, -{ - type Output = Vec<(N, V)>; - - fn index(&self, index: &N) -> &Self::Output { - self.get(index).unwrap() - } -} - -impl IndexMut for AdjacencyMatrix -where - N: Node, - V: Clone + PartialEq, -{ - fn index_mut(&mut self, index: N) -> &mut Self::Output { - self.get_mut(&index).unwrap() - } -} diff --git a/graph/src/store/mod.rs b/graph/src/store/mod.rs deleted file mode 100644 index 7021c07..0000000 --- a/graph/src/store/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - Appellation: store - Contrib: FL03 -*/ -//! # Store -pub use self::{matrix::*, table::*}; - -mod matrix; -mod table; - -use crate::{Edge, Node, Weight}; - -use std::ops::IndexMut; - -pub trait Store: Extend> + IndexMut> -where - N: Node, - V: Weight, -{ - fn clear(&mut self); - fn contains_key(&self, key: &N) -> bool; - fn drain(&mut self); - fn entry(&mut self, key: N); - fn get(&self, key: &N) -> Option<&Vec<(N, V)>> { - if self.contains_key(key) { - Some(&self[key.clone()]) - } else { - None - } - } -} diff --git a/graph/src/store/table.rs b/graph/src/store/table.rs deleted file mode 100644 index c42f55c..0000000 --- a/graph/src/store/table.rs +++ /dev/null @@ -1,158 +0,0 @@ -/* - Appellation: atable - Contrib: FL03 -*/ -use crate::{Node, Weight}; -use std::collections::{hash_map, HashMap}; - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct AdjacencyTable -where - N: Node, - V: Weight, -{ - store: HashMap>, -} - -impl AdjacencyTable -where - N: Node, - V: Weight, -{ - pub fn new() -> Self { - Self { - store: HashMap::new(), - } - } - pub fn capacity(&self) -> usize { - self.store.capacity() - } - pub fn clear(&mut self) { - self.store.clear() - } - pub fn contains_key(&self, key: &N) -> bool { - self.store.contains_key(key) - } - pub fn drain(&mut self) -> hash_map::Drain<'_, N, Vec<(N, V)>> { - self.store.drain() - } - pub fn entry(&mut self, key: N) -> hash_map::Entry<'_, N, Vec<(N, V)>> { - self.store.entry(key) - } - pub fn insert(&mut self, key: N, val: Vec<(N, V)>) -> Option> { - self.store.insert(key, val) - } - pub fn is_empty(&self) -> bool { - self.store.is_empty() - } - pub fn iter(&self) -> hash_map::Iter<'_, N, Vec<(N, V)>> { - self.store.iter() - } - pub fn iter_mut(&mut self) -> hash_map::IterMut<'_, N, Vec<(N, V)>> { - self.store.iter_mut() - } - pub fn get(&self, key: &N) -> Option<&Vec<(N, V)>> { - self.store.get(key) - } - pub fn get_key_value(&self, key: &N) -> Option<(&N, &Vec<(N, V)>)> { - self.store.get_key_value(key) - } - pub fn get_mut(&mut self, key: &N) -> Option<&mut Vec<(N, V)>> { - self.store.get_mut(key) - } - pub fn keys(&self) -> hash_map::Keys> { - self.store.keys() - } - pub fn len(&self) -> usize { - self.store.len() - } - pub fn remove(&mut self, key: &N) -> Option> { - self.store.remove(key) - } - pub fn reserve(&mut self, additional: usize) { - self.store.reserve(additional) - } - pub fn table(self) -> HashMap> { - self.store - } - pub fn values(&self) -> hash_map::Values> { - self.store.values() - } - pub fn values_mut(&mut self) -> hash_map::ValuesMut> { - self.store.values_mut() - } - pub fn with_capacity(capacity: usize) -> Self { - Self { - store: HashMap::with_capacity(capacity), - } - } -} - -impl Extend<(N, Vec<(N, V)>)> for AdjacencyTable -where - N: Node, - V: Weight, -{ - fn extend)>>(&mut self, iter: T) { - self.store.extend(iter) - } -} - -impl From>> for AdjacencyTable -where - N: Node, - V: Weight, -{ - fn from(store: HashMap>) -> Self { - Self { store } - } -} - -impl FromIterator<(N, Vec<(N, V)>)> for AdjacencyTable -where - N: Node, - V: Weight, -{ - fn from_iter)>>(iter: T) -> Self { - let mut map = HashMap::with_hasher(Default::default()); - map.extend(iter); - AdjacencyTable::from(map) - } -} - -impl IntoIterator for AdjacencyTable -where - N: Node, - V: Weight, -{ - type Item = (N, Vec<(N, V)>); - - type IntoIter = hash_map::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - self.store.into_iter() - } -} - -impl std::ops::Index for AdjacencyTable -where - N: Node, - V: Weight, -{ - type Output = Vec<(N, V)>; - - fn index(&self, index: N) -> &Self::Output { - &self.store[&index] - } -} - -impl std::ops::IndexMut for AdjacencyTable -where - N: Node, - V: Weight, -{ - fn index_mut(&mut self, index: N) -> &mut Self::Output { - self.store.get_mut(&index).unwrap() - } -} diff --git a/graph/src/types/edge.rs b/graph/src/types/edge.rs new file mode 100644 index 0000000..792c704 --- /dev/null +++ b/graph/src/types/edge.rs @@ -0,0 +1,7 @@ +/* + Appellation: edge + Contrib: FL03 +*/ + +pub struct Edge(pub A, pub B); + diff --git a/graph/src/types/kinds.rs b/graph/src/types/kinds.rs new file mode 100644 index 0000000..0d391cd --- /dev/null +++ b/graph/src/types/kinds.rs @@ -0,0 +1,29 @@ +/* + Appellation: kinds + Contrib: FL03 +*/ + + +macro_rules! uninit { + (@impl $vis:vis enum $name:ident) => { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + $vis enum $name {} + + impl $name { + pub fn phantom() -> ::core::marker::PhantomData:: { + ::core::marker::PhantomData:: + } + } + }; + + ($($vis:vis $name:ident),* $(,)?) => { + $( + uninit!(@impl $vis enum $name); + )* + }; +} + +uninit! { + pub Directed, + pub Undirected, +} \ No newline at end of file diff --git a/graph/src/types/mod.rs b/graph/src/types/mod.rs new file mode 100644 index 0000000..94dd91a --- /dev/null +++ b/graph/src/types/mod.rs @@ -0,0 +1,14 @@ +/* + Appellation: types + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::kinds::*; + +pub mod edge; +pub mod kinds; +pub mod node; + +pub(crate) mod prelude { + pub use crate::kinds::*; +} \ No newline at end of file diff --git a/graph/src/types/node.rs b/graph/src/types/node.rs new file mode 100644 index 0000000..c6eff7f --- /dev/null +++ b/graph/src/types/node.rs @@ -0,0 +1,10 @@ +/* + Appellation: node + Contrib: FL03 +*/ +use core::marker::PhantomData; + +pub struct Node { + pub data: Option, + _class: PhantomData, +} \ No newline at end of file diff --git a/graph/src/undirected.rs b/graph/src/undirected.rs deleted file mode 100644 index b74dd4c..0000000 --- a/graph/src/undirected.rs +++ /dev/null @@ -1,185 +0,0 @@ -/* - Appellation: undirected - Contrib: FL03 -*/ -use crate::cmp::Edge; -use crate::prelude::{Contain, Graph, GraphExt, Node, Subgraph, Weight}; -use crate::store::AdjacencyTable; - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct UndirectedGraph -where - N: Node, - V: Weight, -{ - store: AdjacencyTable, -} - -impl UndirectedGraph -where - N: Node, - V: Weight, -{ - pub fn new() -> Self { - Self { - store: AdjacencyTable::new(), - } - } - pub fn with_capacity(capacity: usize) -> Self { - Self { - store: AdjacencyTable::with_capacity(capacity), - } - } -} - -impl AsMut> for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn as_mut(&mut self) -> &mut AdjacencyTable { - &mut self.store - } -} - -impl AsRef> for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn as_ref(&self) -> &AdjacencyTable { - &self.store - } -} - -impl Contain for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn contains(&self, elem: &N) -> bool { - self.store.contains_key(elem) - } -} - -impl Contain> for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn contains(&self, elem: &Edge) -> bool { - self.edges().contains(elem) - } -} - -impl Graph for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn add_edge(&mut self, edge: Edge) { - let pair = edge.pair(); - self.add_node(pair.0.clone()); - self.add_node(pair.1.clone()); - - self.store.entry(pair.0.clone()).and_modify(|e| { - e.push((pair.1.clone(), edge.value().clone())); - }); - self.store.entry(pair.1).and_modify(|e| { - e.push((pair.0, edge.value().clone())); - }); - } - fn store_mut(&mut self) -> &mut AdjacencyTable { - &mut self.store - } - fn store(&self) -> &AdjacencyTable { - &self.store - } -} - -impl GraphExt for UndirectedGraph -where - N: Node, - V: Weight, -{ -} - -impl Subgraph for UndirectedGraph -where - N: Node, - V: Weight, -{ -} - -impl From> for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn from(store: AdjacencyTable) -> Self { - Self { store } - } -} - -impl std::ops::Index for UndirectedGraph -where - N: Node, - V: Weight, -{ - type Output = Vec<(N, V)>; - - fn index(&self, index: N) -> &Self::Output { - &self.store[index] - } -} - -impl std::ops::IndexMut for UndirectedGraph -where - N: Node, - V: Weight, -{ - fn index_mut(&mut self, index: N) -> &mut Self::Output { - self.store.index_mut(index) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - const TEST_EDGES: [(&str, &str, usize); 3] = [("a", "b", 5), ("c", "a", 7), ("b", "c", 10)]; - - const EXPECTED: [(&str, &str, usize); 6] = [ - ("a", "b", 5), - ("b", "a", 5), - ("c", "a", 7), - ("a", "c", 7), - ("b", "c", 10), - ("c", "b", 10), - ]; - - #[test] - fn test_add_edge() { - let mut graph = UndirectedGraph::new(); - - for i in TEST_EDGES { - graph.add_edge(i.into()); - } - // assert that the graph contains all the edges - assert!(graph.all(EXPECTED.into_iter().map(Edge::from).collect::>())); - // assert that the graph can be indexed - assert_eq!(graph["a"], vec![("b", 5), ("c", 7)]); - } - - #[test] - fn test_neighbours() { - let mut graph = UndirectedGraph::new(); - - for i in TEST_EDGES { - graph.add_edge(i.into()); - } - - assert_eq!(graph["a"], vec![("b", 5), ("c", 7)]); - } -} diff --git a/merkle/tests/merkle.rs b/merkle/tests/merkle.rs index 551d2b1..5483ba8 100644 --- a/merkle/tests/merkle.rs +++ b/merkle/tests/merkle.rs @@ -1,7 +1,10 @@ +/* + Appellation: merkle + Contrib: FL03 +*/ /* TODO: Update the hashes to match the Blake3 Hash Digests */ -#[cfg(test)] /* Map(A -> a) def. diff --git a/spline/Cargo.toml b/spline/Cargo.toml deleted file mode 100644 index b1bdbb0..0000000 --- a/spline/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -[package] -authors.workspace = true -build = "build.rs" -categories.workspace = true -description.workspace = true -edition.workspace = true -homepage.workspace = true -keywords.workspace = true -license.workspace = true -name = "algae-spline" -readme.workspace = true -repository.workspace = true -version.workspace = true - -[features] -default = [ - "std", -] - -full = [ - "default", - "serde" -] - -# ******** [FF] Dependencies ******** -alloc = [ - "num/alloc", -] - -serde = [ - "dep:serde", - "num/serde", -] - -# ******** [FF] Environments ******** -std = [ - "alloc", - "num/std", - "serde?/std", - "strum/std" -] - -[lib] -bench = false -crate-type = ["cdylib", "rlib"] -doctest = true -test = true - -[build-dependencies] - -[dependencies] -num.workspace = true -strum = { default-features = false, features = ["derive"], version = "0.26" } - -[dependencies.serde] -default-features = false -features = ["derive"] -optional = true -version = "1" diff --git a/spline/build.rs b/spline/build.rs deleted file mode 100644 index 940a4ce..0000000 --- a/spline/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -/* - Appellation: build - Contrib: FL03 -*/ - -fn main() { - println!("cargo::rustc-check-cfg=cfg(no_std)"); -} diff --git a/spline/src/bspline/mod.rs b/spline/src/bspline/mod.rs deleted file mode 100644 index 9a60688..0000000 --- a/spline/src/bspline/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -/* - Appellation: bspline - Contrib: FL03 -*/ -pub use self::spline::*; - -pub(crate) mod spline; - -pub(crate) mod prelude { - pub use super::spline::*; -} diff --git a/spline/src/bspline/spline.rs b/spline/src/bspline/spline.rs deleted file mode 100644 index 9417d8d..0000000 --- a/spline/src/bspline/spline.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Appellation: spline - Contrib: FL03 -*/ -use crate::error::*; - -pub struct BSpline { - pub(crate) degree: usize, - pub(crate) ctrls: Vec, - pub(crate) knots: Vec, -} - -impl BSpline { - pub fn new(degree: usize, ctrls: Vec, knots: Vec) -> Result { - if ctrls.len() < degree { - return Err(SplineError::NotEnoughPoints); - } - if knots.len() != ctrls.len() + degree + 1 { - return Err(SplineError::not_enough_knots(knots.len(), ctrls.len() + degree + 1)); - } - let spline = Self { - ctrls, - degree, - knots, - }; - Ok(spline) - } - - pub fn degree(&self) -> usize { - self.degree - } - - pub fn knots(&self) -> &[K] { - &self.knots - } - - pub fn knots_mut(&mut self) -> &mut [K] { - &mut self.knots - } - - pub fn points(&self) -> &[C] { - &self.ctrls - } - - pub fn points_mut(&mut self) -> &mut [C] { - &mut self.ctrls - } -} diff --git a/spline/src/error.rs b/spline/src/error.rs deleted file mode 100644 index 0fcdfb8..0000000 --- a/spline/src/error.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - Appellation: error - Contrib: FL03 -*/ - -pub type Result = core::result::Result; - -macro_rules! error_kind { - ($(rename_all: $lit:literal,)? $vis:vis enum $name:ident $($rest:tt)*) => { - error_kind!(@impl $(rename_all: $lit,)? $vis enum $name $($rest)*); - }; - (@impl $vis:vis enum $name:ident $($rest:tt)*) => { - error_kind!(@impl rename_all: "PascalCase", $vis enum $name $($rest)*); - - }; - (@impl rename_all: $lit:literal, $vis:vis enum $name:ident $($rest:tt)*) => { - #[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumCount, - strum::EnumIs, - strum::VariantNames, - )] - #[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = $lit) - )] - #[strum(serialize_all = $lit)] - $vis enum $name $($rest)* - }; -} - -error_kind! { - pub enum SplineError { - Shape(ShapeError), - TooFewKnots, - NotEnoughPoints, - } -} - -error_kind! { - pub enum ShapeError { - DegreeMismatch, - NotEnoughKnots { - exp: usize, - res: usize, - }, - NotEnoughPoints, - } -} - -impl SplineError { - pub fn not_enough_knots(exp: usize, res: usize) -> Self { - let err = ShapeError::NotEnoughKnots { - exp, - res, - }; - Self::Shape(err) - - } - pub fn shape_error(err: ShapeError) -> Self { - Self::Shape(err) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for SplineError {} - -impl From for SplineError { - fn from(err: ShapeError) -> Self { - Self::shape_error(err) - } -} \ No newline at end of file diff --git a/spline/src/lib.rs b/spline/src/lib.rs deleted file mode 100644 index 6e21f6c..0000000 --- a/spline/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* - Appellation: algae-spline - Contrib: FL03 -*/ -//! # Algae Spline -//! -//! -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "alloc")] -extern crate alloc; - -pub use self::error::{Result, SplineError}; -pub use self::traits::prelude::*; - -pub mod bspline; -pub mod error; -pub mod traits; - -pub mod prelude { - pub use super::bspline::prelude::*; - pub use super::error::*; - pub use super::traits::prelude::*; -} diff --git a/spline/src/traits/interpolate.rs b/spline/src/traits/interpolate.rs deleted file mode 100644 index 12c8c29..0000000 --- a/spline/src/traits/interpolate.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - Appellation: interpolate - Contrib: FL03 -*/ -use core::ops::Mul; -use num::traits::{MulAdd, Num, NumRef}; - -pub trait Interpolate { - type Output; - - fn interpolate(&self, data: A, t: B) -> Self::Output; -} - -/* - ************* Implementations ************* -*/ -impl Interpolate for T -where - A: Num + Mul, - B: Clone + Num + NumRef, - T: Clone + MulAdd + Num, -{ - type Output = >::Output; - - fn interpolate(&self, data: A, t: B) -> Self::Output { - // *self * (B::one() - t) + *data * t - self.clone().mul_add(B::one() - t.clone(), data * t) - } -} diff --git a/spline/src/traits/mod.rs b/spline/src/traits/mod.rs deleted file mode 100644 index 33444e7..0000000 --- a/spline/src/traits/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -/* - Appellation: traits - Contrib: FL03 -*/ -#[doc(inline)] -pub use self::prelude::*; - -pub mod interpolate; - -pub(crate) mod prelude { - pub use super::interpolate::*; -} diff --git a/spline/src/types/knot.rs b/spline/src/types/knot.rs deleted file mode 100644 index 97237f9..0000000 --- a/spline/src/types/knot.rs +++ /dev/null @@ -1,6 +0,0 @@ -/* - Appellation: knot - Contrib: FL03 -*/ - -pub struct Knot; \ No newline at end of file diff --git a/spline/src/types/mod.rs b/spline/src/types/mod.rs deleted file mode 100644 index 5463d07..0000000 --- a/spline/src/types/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* - Appellation: types - Contrib: FL03 -*/ -pub use self::prelude::*; - -pub mod knot; -pub mod point; - -pub(crate) mod prelude { - pub use super::knot::Knot; - pub use super::point::Point; -} \ No newline at end of file diff --git a/spline/src/types/point.rs b/spline/src/types/point.rs deleted file mode 100644 index 972ec6b..0000000 --- a/spline/src/types/point.rs +++ /dev/null @@ -1,6 +0,0 @@ -/* - Appellation: point - Contrib: FL03 -*/ - -pub struct Point; \ No newline at end of file diff --git a/spline/tests/default.rs b/spline/tests/default.rs deleted file mode 100644 index 233a07a..0000000 --- a/spline/tests/default.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - Appellation: default - Contrib: FL03 -*/ - -fn add(a: A, b: B) -> C -where - A: core::ops::Add, -{ - a + b -} - -#[test] -fn compiles() { - assert_eq!(add(10, 10), 20); - assert_ne!(add(1, 1), 3); -}