Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Algorithm standardisation #1896

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 126 additions & 93 deletions python/python/raphtory/algorithms/__init__.pyi

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion python/tests/test_graphdb/test_graphdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ def check(g):
lotr_graph, "Frodo"
)
lotr_local_triangle_count = algorithms.local_triangle_count(lotr_graph, "Frodo")
assert lotr_clustering_coefficient == 0.1984313726425171
assert lotr_clustering_coefficient == 0.1984313725490196
assert lotr_local_triangle_count == 253

check(g)
Expand Down
21 changes: 16 additions & 5 deletions raphtory-graphql/src/model/algorithms/algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ use dynamic_graphql::{internal::TypeName, SimpleObject};
use futures_util::future::BoxFuture;
use itertools::Itertools;
use ordered_float::OrderedFloat;
use raphtory::algorithms::{
centrality::pagerank::unweighted_page_rank,
pathing::dijkstra::dijkstra_single_source_shortest_paths,
use raphtory::{
algorithms::{
centrality::pagerank::unweighted_page_rank,
pathing::dijkstra::dijkstra_single_source_shortest_paths,
},
core::Prop,
};
use raphtory_api::core::Direction;
use std::collections::HashMap;

#[derive(SimpleObject)]
pub(crate) struct PagerankOutput {
Expand Down Expand Up @@ -160,8 +164,15 @@ fn apply_shortest_path<'b>(
.iter()
.map(|v| v.string())
.collect::<Result<Vec<&str>, _>>()?;
let binding =
dijkstra_single_source_shortest_paths(&entry_point.graph, source, targets, None, direction);
let binding: Result<HashMap<String, (f64, Vec<String>)>, &str> =
Ok(dijkstra_single_source_shortest_paths(
&entry_point.graph,
source,
targets,
None,
direction,
)?
.get_all_with_names());
let result: Vec<FieldValue> = binding
.into_iter()
.flat_map(|pair| {
Expand Down
12 changes: 12 additions & 0 deletions raphtory/src/algorithms/algorithm_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ impl<T: FloatCore> AsOrd<OrderedFloat<T>> for T {
}
}

impl<T: FloatCore> AsOrd<[OrderedFloat<T>; 2]> for [T; 2] {
fn as_ord(&self) -> &[OrderedFloat<T>; 2] {
unsafe { &*(self as *const [T; 2] as *const [OrderedFloat<T>; 2]) }
}
}

impl<T: FloatCore> AsOrd<(OrderedFloat<T>, Vec<String>)> for (T, Vec<String>) {
fn as_ord(&self) -> &(OrderedFloat<T>, Vec<String>) {
unsafe { &*(self as *const (T, Vec<String>) as *const (OrderedFloat<T>, Vec<String>)) }
}
}

impl<T: FloatCore> AsOrd<(OrderedFloat<T>, OrderedFloat<T>)> for (T, T) {
fn as_ord(&self) -> &(OrderedFloat<T>, OrderedFloat<T>) {
// Safety: OrderedFloat is #[repr(transparent)] and has no invalid values, i.e. there is no physical difference between OrderedFloat and Float.
Expand Down
12 changes: 8 additions & 4 deletions raphtory/src/algorithms/bipartite/max_weight_matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,17 +826,21 @@ fn verify_optimum(
///
/// The function takes time O(n**3)
///
/// Arguments:
/// # Arguments
///
/// * `graph` - The graph to compute the maximum weight matching for
/// * `max_cardinality` - If set to true compute the maximum-cardinality matching
/// - `graph` - The graph to compute the maximum weight matching for
/// - `max_cardinality` - If set to true compute the maximum-cardinality matching
/// with maximum weight among all maximum-cardinality matchings
/// * `verify_optimum_flag`: If true prior to returning an additional routine
/// - `verify_optimum_flag`: If true prior to returning an additional routine
/// to verify the optimal solution was found will be run after computing
/// the maximum weight matching. If it's true and the found matching is not
/// an optimal solution this function will panic. This option should
/// normally be only set true during testing.
///
/// # Returns
///
/// A [Matching] object that contains a mapping of vertices to outwardly and inwardly assigned target vertices.
///
/// # Example
/// ```rust
///
Expand Down
4 changes: 2 additions & 2 deletions raphtory/src/algorithms/centrality/betweenness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use std::collections::{HashMap, VecDeque};

/// Computes the betweenness centrality for nodes in a given graph.
///
/// # Parameters
/// # Arguments
///
/// - `g`: A reference to the graph.
/// - `k`: An `Option<usize>` specifying the number of nodes to consider for the centrality computation. Defaults to all nodes if `None`.
/// - `normalized`: If `true` normalize the centrality values.
///
/// # Returns
///
/// Returns an `AlgorithmResult` containing the betweenness centrality of each node.
/// An [AlgorithmResult] containing the betweenness centrality of each node.
pub fn betweenness_centrality<'graph, G: GraphViewOps<'graph>>(
g: &'graph G,
k: Option<usize>,
Expand Down
9 changes: 9 additions & 0 deletions raphtory/src/algorithms/centrality/degree_centrality.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ use ordered_float::OrderedFloat;
/// Computes the degree centrality of all nodes in the graph. The values are normalized
/// by dividing each result with the maximum possible degree. Graphs with self-loops can have
/// values of centrality greater than 1.
///
/// # Arguments
///
/// - `g`: A reference to the graph.
/// - `threads` - Number of threads to use
///
/// # Returns
///
/// An [AlgorithmResult] containing the degree centrality of each node.
pub fn degree_centrality<G: StaticGraphViewOps>(
g: &G,
threads: Option<usize>,
Expand Down
10 changes: 8 additions & 2 deletions raphtory/src/algorithms/centrality/hits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,15 @@ impl Default for Hits {
/// HubScore of a node (A) = Sum of AuthScore of all nodes pointing away from node (A) from previous iteration /
/// Sum of AuthScore of all nodes in the current iteration
///
/// Returns
/// # Arguments
///
/// * An AlgorithmResult object containing the mapping from node ID to the hub and authority score of the node
/// - `g`: A reference to the graph.
/// - `iter_count` - The number of iterations to run
/// - `threads` - Number of threads to use
///
/// # Returns
///
/// An [AlgorithmResult] object containing the mapping from node ID to the hub and authority score of the node
pub fn hits<G: StaticGraphViewOps>(
g: &G,
iter_count: usize,
Expand Down
18 changes: 9 additions & 9 deletions raphtory/src/algorithms/centrality/pagerank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ impl PageRankState {
/// PageRank Algorithm:
/// PageRank shows how important a node is in a graph.
///
/// Arguments:
/// # Arguments
///
/// * `g`: A GraphView object
/// * `iter_count`: Number of iterations to run the algorithm for
/// * `threads`: Number of threads to use for parallel execution
/// * `tol`: The tolerance value for convergence
/// * `use_l2_norm`: Whether to use L2 norm for convergence
/// * `damping_factor`: Probability of likelihood the spread will continue
/// - `g`: A GraphView object
/// - `iter_count`: Number of iterations to run the algorithm for
/// - `threads`: Number of threads to use for parallel execution
/// - `tol`: The tolerance value for convergence
/// - `use_l2_norm`: Whether to use L2 norm for convergence
/// - `damping_factor`: Probability of likelihood the spread will continue
///
/// Result:
/// # Returns
///
/// * An AlgorithmResult object containing the mapping from node ID to the PageRank score of the node
/// An [AlgorithmResult] object containing the mapping from node ID to the PageRank score of the node
///
pub fn unweighted_page_rank<G: StaticGraphViewOps>(
g: &G,
Expand Down
10 changes: 5 additions & 5 deletions raphtory/src/algorithms/community_detection/label_propagation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ use crate::{
///
/// # Arguments
///
/// * `g` - A reference to the graph
/// * `seed` - (Optional) Array of 32 bytes of u8 which is set as the rng seed
/// - `g` - A reference to the graph
/// - `seed` - (Optional) Array of 32 bytes of u8 which is set as the rng seed
///
/// Returns:
/// # Returns
///
/// A vector of hashsets each containing nodes
///
pub fn label_propagation<G>(
graph: &G,
g: &G,
seed: Option<[u8; 32]>,
) -> Result<Vec<HashSet<NodeView<G>>>, &'static str>
where
G: StaticGraphViewOps,
{
let mut labels: HashMap<NodeView<&G>, GID> = HashMap::new();
let nodes = &graph.nodes();
let nodes = &g.nodes();
for node in nodes.iter() {
labels.insert(node, node.id());
}
Expand Down
22 changes: 17 additions & 5 deletions raphtory/src/algorithms/community_detection/louvain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,34 @@ use crate::{
use rand::prelude::SliceRandom;
use std::collections::HashMap;

/// Louvain algorithm for community detection
///
/// # Arguments
///
/// - `g` (GraphView): the graph view
/// - `resolution` (float): the resolution parameter for modularity
/// - `weight_prop` (str | None): the edge property to use for weights (has to be float)
/// - `tol` (None | float): the floating point tolerance for deciding if improvements are significant (default: 1e-8)
///
/// # Returns
///
/// An [AlgorithmResult] containing a mapping of vertices to cluster ID.
pub fn louvain<'graph, M: ModularityFunction, G: GraphViewOps<'graph>>(
graph: &G,
g: &G,
resolution: f64,
weight_prop: Option<&str>,
tol: Option<f64>,
) -> AlgorithmResult<G, usize> {
let tol = tol.unwrap_or(1e-8);
let mut rng = rand::thread_rng();
let mut modularity_state = M::new(
graph,
g,
weight_prop,
resolution,
Partition::new_singletons(graph.count_nodes()),
Partition::new_singletons(g.count_nodes()),
tol,
);
let mut global_partition: HashMap<_, _> = graph
let mut global_partition: HashMap<_, _> = g
.nodes()
.iter()
.enumerate()
Expand Down Expand Up @@ -59,7 +71,7 @@ pub fn louvain<'graph, M: ModularityFunction, G: GraphViewOps<'graph>>(
*c = partition.com(&VID(*c)).index();
}
}
AlgorithmResult::new(graph.clone(), "louvain", "usize", global_partition)
AlgorithmResult::new(g.clone(), "louvain", "usize", global_partition)
}

#[cfg(test)]
Expand Down
15 changes: 7 additions & 8 deletions raphtory/src/algorithms/components/connected_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ struct WccState {
/// * `iter_count` - The number of iterations to run
/// * `threads` - Number of threads to use
///
/// Returns:
/// # Returns
///
/// An AlgorithmResult containing the mapping from the node to its component ID
/// An [AlgorithmResult] containing the mapping from each node to its component ID
///
pub fn weakly_connected_components<G>(
graph: &G,
g: &G,
iter_count: usize,
threads: Option<usize>,
) -> AlgorithmResult<G, GID, GID>
where
G: StaticGraphViewOps,
{
let ctx: Context<G, ComputeStateVec> = graph.into();
let ctx: Context<G, ComputeStateVec> = g.into();
let step1 = ATask::new(move |vv| {
let min_neighbour_id = vv.neighbours().iter().map(|n| n.node.0).min();
let id = vv.node.0;
Expand Down Expand Up @@ -73,12 +73,11 @@ where
vec![Job::read_only(step2)],
None,
|_, _, _, local: Vec<WccState>| {
graph
.nodes()
g.nodes()
.par_iter()
.map(|node| {
let VID(id) = node.node;
let comp = graph.node_id(VID(local[id].component));
let comp = g.node_id(VID(local[id].component));
(id, comp)
})
.collect()
Expand All @@ -89,7 +88,7 @@ where
None,
);

AlgorithmResult::new(graph.clone(), "Connected Components", results_type, res)
AlgorithmResult::new(g.clone(), "Connected Components", results_type, res)
}

#[cfg(test)]
Expand Down
25 changes: 12 additions & 13 deletions raphtory/src/algorithms/components/in_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ struct InState {
///
/// # Arguments
///
/// * `g` - A reference to the graph
/// * `threads` - Number of threads to use
/// - `g` - A reference to the graph
/// - `threads` - Number of threads to use
///
/// Returns:
/// # Returns
///
/// An AlgorithmResult containing the mapping from node to a vector of node ids (the nodes in component)
/// An [AlgorithmResult] containing the mapping from each node to a vector of node ids (the nodes in component)
///
pub fn in_components<G>(graph: &G, threads: Option<usize>) -> AlgorithmResult<G, Vec<GID>, Vec<GID>>
pub fn in_components<G>(g: &G, threads: Option<usize>) -> AlgorithmResult<G, Vec<GID>, Vec<GID>>
where
G: StaticGraphViewOps,
{
let ctx: Context<G, ComputeStateVec> = graph.into();
let ctx: Context<G, ComputeStateVec> = g.into();
let step1 = ATask::new(move |vv: &mut EvalNodeView<G, InState>| {
let mut in_components = HashSet::new();
let mut to_check_stack = Vec::new();
Expand Down Expand Up @@ -76,15 +76,14 @@ where
vec![],
None,
|_, _, _, local: Vec<InState>| {
graph
.nodes()
g.nodes()
.par_iter()
.map(|node| {
let VID(id) = node.node;
let components = local[id]
.in_components
.iter()
.map(|vid| graph.node_id(*vid))
.map(|vid| g.node_id(*vid))
.collect();
(id, components)
})
Expand All @@ -95,15 +94,15 @@ where
None,
None,
);
AlgorithmResult::new(graph.clone(), "In Components", results_type, res)
AlgorithmResult::new(g.clone(), "In Components", results_type, res)
}
/// Computes the in-component of a given node in the graph
///
/// # Arguments
/// # Arguments:
///
/// * `node` - The node whose in-component we wish to calculate
/// - `node` - The node whose in-component we wish to calculate
///
/// Returns:
/// # Returns:
///
/// The nodes within the given nodes in-component and their distances from the starting node.
///
Expand Down
Loading
Loading