Skip to main content

fso_graph/
lib.rs

1#![warn(unused_crate_dependencies)]
2//! A library that provides a collection of high-performant graph algorithms.
3//! This crate builds on top of the [fso-graph-builder](https://docs.rs/fso-graph-builder/latest/)
4//! crate, which can be used as a building block for custom graph algorithms.
5//!
6//! `fso-graph-builder` provides implementations for directed and undirected graphs.
7//! Graphs can be created programatically or read from custom input formats in a
8//! type-safe way. The library uses [rayon](https://github.com/rayon-rs/rayon)
9//! to parallelize all steps during graph creation. The implementation uses a
10//! Compressed-Sparse-Row (CSR) data structure which is tailored for fast and
11//!  concurrent access to the graph topology.
12//!
13//! `graph` provides graph algorithms which take graphs created using `fso-graph-builder`
14//! as input. The algorithm implementations are designed to run efficiently on
15//! large-scale graphs with billions of nodes and edges.
16//!
17//! **Note**: The development is mainly driven by
18//! [Neo4j](https://github.com/neo4j/neo4j) developers. However, the library is
19//! __not__ an official product of Neo4j.
20//!
21//! # What is a graph?
22//!
23//! A graph consists of nodes and edges where edges connect exactly two nodes. A
24//! graph can be either directed, i.e., an edge has a source and a target node
25//! or undirected where there is no such distinction.
26//!
27//! In a directed graph, each node `u` has outgoing and incoming neighbors. An
28//! outgoing neighbor of node `u` is any node `v` for which an edge `(u, v)`
29//! exists. An incoming neighbor of node `u` is any node `v` for which an edge
30//! `(v, u)` exists.
31//!
32//! In an undirected graph there is no distinction between source and target
33//! node. A neighbor of node `u` is any node `v` for which either an edge `(u,
34//! v)` or `(v, u)` exists.
35//!
36//! # How to use graph?
37//!
38//! The library provides a builder that can be used to construct a graph from a
39//! given list of edges.
40//!
41//! For example, to create a directed graph that uses `usize` as node
42//! identifier, one can use the builder like so:
43//!
44//! ```
45//! use fso_graph::prelude::*;
46//!
47//! let graph: DirectedCsrGraph<usize> = GraphBuilder::new()
48//!     .csr_layout(CsrLayout::Sorted)
49//!     .edges(vec![(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)])
50//!     .build();
51//!
52//! assert_eq!(graph.node_count(), 4);
53//! assert_eq!(graph.edge_count(), 5);
54//!
55//! assert_eq!(graph.out_degree(1), 2);
56//! assert_eq!(graph.in_degree(1), 1);
57//!
58//! assert_eq!(graph.out_neighbors(1).as_slice(), &[2, 3]);
59//! assert_eq!(graph.in_neighbors(1).as_slice(), &[0]);
60//! ```
61//!
62//! To build an undirected graph using `u32` as node identifer, we only need to
63//! change the expected types:
64//!
65//! ```
66//! use fso_graph::prelude::*;
67//!
68//! let graph: UndirectedCsrGraph<u32> = GraphBuilder::new()
69//!     .csr_layout(CsrLayout::Sorted)
70//!     .edges(vec![(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)])
71//!     .build();
72//!
73//! assert_eq!(graph.node_count(), 4);
74//! assert_eq!(graph.edge_count(), 5);
75//!
76//! assert_eq!(graph.degree(1), 3);
77//!
78//! assert_eq!(graph.neighbors(1).as_slice(), &[0, 2, 3]);
79//! ```
80//!
81//! Check out the [fso-graph-builder](https://docs.rs/fso-graph-builder/latest/) crate for
82//! for more examples on how to build graphs from various input formats.
83//!
84//! # How to run algorithms
85//!
86//! In the following we will demonstrate running [Page Rank](https://en.wikipedia.org/wiki/PageRank),
87//! a graph algorithm to determine the importance of nodes in a graph based on the
88//! number and quality of their incoming edges.
89//!
90//! Page Rank requires a directed graph and returns the rank value for each node.
91//!
92//! ```
93//! use fso_graph::prelude::*;
94//!
95//! // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.svg
96//! let graph: DirectedCsrGraph<usize> = GraphBuilder::new()
97//!     .edges(vec![
98//!            (1,2), // B->C
99//!            (2,1), // C->B
100//!            (4,0), // D->A
101//!            (4,1), // D->B
102//!            (5,4), // E->D
103//!            (5,1), // E->B
104//!            (5,6), // E->F
105//!            (6,1), // F->B
106//!            (6,5), // F->E
107//!            (7,1), // G->B
108//!            (7,5), // F->E
109//!            (8,1), // G->B
110//!            (8,5), // G->E
111//!            (9,1), // H->B
112//!            (9,5), // H->E
113//!            (10,1), // I->B
114//!            (10,5), // I->E
115//!            (11,5), // J->B
116//!            (12,5), // K->B
117//!     ])
118//!     .build();
119//!
120//! let (ranks, iterations, _) = page_rank(&graph, PageRankConfig::new(10, 1E-4, 0.85));
121//!
122//! assert_eq!(iterations, 10);
123//!
124//! let expected = vec![
125//!     0.024064068,
126//!     0.3145448,
127//!     0.27890152,
128//!     0.01153846,
129//!     0.029471997,
130//!     0.06329483,
131//!     0.029471997,
132//!     0.01153846,
133//!     0.01153846,
134//!     0.01153846,
135//!     0.01153846,
136//!     0.01153846,
137//!     0.01153846,
138//! ];
139//!
140//! assert_eq!(ranks, expected);
141//! ```
142
143pub mod afforest;
144pub mod dss;
145pub mod page_rank;
146pub mod prelude;
147pub mod sssp;
148pub mod triangle_count;
149pub mod utils;
150pub mod wcc;
151
152const DEFAULT_PARALLELISM: usize = 4;
153
154// Related to https://github.com/rust-lang/rust/issues/72686
155// `unused_crate_dependencies` does not differentiate between `dev-dependencies` and `dependencies`
156// so we fake the usage by blank importing the dev0dependencies in test scope.
157#[cfg(test)]
158use env_logger as _;
159#[cfg(test)]
160use polars as _;