A library that can be used as a building block for high-performant graph algorithms.

Overview

graph

A library that can be used as a building block for high-performant graph algorithms.

Graph provides implementations for directed and undirected graphs. Graphs can be created programatically or read from custom input formats in a type-safe way. The library uses rayon to parallelize all steps during graph creation.

The implementation uses a Compressed-Sparse-Row (CSR) data structure which is tailored for fast and concurrent access to the graph topology.

Note: The development is mainly driven by Neo4j developers. However, the library is not an official product of Neo4j.

What is a graph?

A graph consists of nodes and edges where edges connect exactly two nodes. A graph can be either directed, i.e., an edge has a source and a target node or undirected where there is no such distinction.

In a directed graph, each node u has outgoing and incoming neighbors. An outgoing neighbor of node u is any node v for which an edge (u, v) exists. An incoming neighbor of node u is any node v for which an edge (v, u) exists.

In an undirected graph there is no distinction between source and target node. A neighbor of node u is any node v for which either an edge (u, v) or (v, u) exists.

How to use graph?

The library provides a builder that can be used to construct a graph from a given list of edges.

For example, to create a directed graph that uses usize as node identifier, one can use the builder like so:

use graph::prelude::*;

let graph: DirectedCsrGraph<usize> = GraphBuilder::new()
    .edges(vec![(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)])
    .build();

assert_eq!(graph.node_count(), 4);
assert_eq!(graph.edge_count(), 5);

assert_eq!(graph.out_degree(1), 2);
assert_eq!(graph.in_degree(1), 1);

assert_eq!(graph.out_neighbors(1), &[2, 3]);
assert_eq!(graph.in_neighbors(1), &[0]);

To build an undirected graph using u32 as node identifer, we only need to change the expected types:

use graph::prelude::*;

let graph: UndirectedCsrGraph<u32> = GraphBuilder::new()
    .edges(vec![(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)])
    .build();

assert_eq!(graph.node_count(), 4);
assert_eq!(graph.edge_count(), 5);

assert_eq!(graph.degree(1), 3);

assert_eq!(graph.neighbors(1), &[0, 2, 3]);

Edges can have values attached, this is useful to represent, for example, weighted graphs:

use graph::prelude::*;

let graph: UndirectedCsrGraph<u32, f32> = GraphBuilder::new()
    .edges_with_values(vec![(0, 1, 0.5), (0, 2, 0.7), (1, 2, 0.25), (1, 3, 1.0), (2, 3, 0.33)])
    .build();

assert_eq!(graph.node_count(), 4);
assert_eq!(graph.edge_count(), 5);

assert_eq!(graph.degree(1), 3);

assert_eq!(graph.neighbors_with_values(1), &[Target::new(0, 0.5), Target::new(2, 0.25), Target::new(3, 1.0)]);

It is also possible to create a graph from a specific input format. In the following example we use the EdgeListInput which is an input format where each line of a file contains an edge of the graph.

(); let graph: DirectedCsrGraph = GraphBuilder::new() .csr_layout(CsrLayout::Sorted) .file_format(EdgeListInput::default()) .path(path) .build() .expect("loading failed"); assert_eq!(graph.node_count(), 4); assert_eq!(graph.edge_count(), 5); assert_eq!(graph.out_degree(1), 2); assert_eq!(graph.in_degree(1), 1); assert_eq!(graph.out_neighbors(1), &[2, 3]); assert_eq!(graph.in_neighbors(1), &[0]); ">
use std::path::PathBuf;

use graph::prelude::*;

let path = [env!("CARGO_MANIFEST_DIR"), "resources", "example.el"]
    .iter()
    .collect::<PathBuf>();

let graph: DirectedCsrGraph<usize> = GraphBuilder::new()
    .csr_layout(CsrLayout::Sorted)
    .file_format(EdgeListInput::default())
    .path(path)
    .build()
    .expect("loading failed");

assert_eq!(graph.node_count(), 4);
assert_eq!(graph.edge_count(), 5);

assert_eq!(graph.out_degree(1), 2);
assert_eq!(graph.in_degree(1), 1);

assert_eq!(graph.out_neighbors(1), &[2, 3]);
assert_eq!(graph.in_neighbors(1), &[0]);

The EdgeListInput format also supports weighted edges. This can be controlled by a single type parameter on the graph type. Note, that the edge value type needs to implement [crate::input::ParseValue].

(); let graph: DirectedCsrGraph = GraphBuilder::new() .csr_layout(CsrLayout::Sorted) .file_format(EdgeListInput::default()) .path(path) .build() .expect("loading failed"); assert_eq!(graph.node_count(), 4); assert_eq!(graph.edge_count(), 5); assert_eq!(graph.out_degree(1), 2); assert_eq!(graph.in_degree(1), 1); assert_eq!(graph.out_neighbors_with_values(1), &[Target::new(2, 0.25), Target::new(3, 1.0)]); assert_eq!(graph.in_neighbors_with_values(1), &[Target::new(0, 0.5)]); ">
use std::path::PathBuf;

use graph::prelude::*;

let path = [env!("CARGO_MANIFEST_DIR"), "resources", "example.wel"]
    .iter()
    .collect::<PathBuf>();

let graph: DirectedCsrGraph<usize, f32> = GraphBuilder::new()
    .csr_layout(CsrLayout::Sorted)
    .file_format(EdgeListInput::default())
    .path(path)
    .build()
    .expect("loading failed");

assert_eq!(graph.node_count(), 4);
assert_eq!(graph.edge_count(), 5);

assert_eq!(graph.out_degree(1), 2);
assert_eq!(graph.in_degree(1), 1);

assert_eq!(graph.out_neighbors_with_values(1), &[Target::new(2, 0.25), Target::new(3, 1.0)]);
assert_eq!(graph.in_neighbors_with_values(1), &[Target::new(0, 0.5)]);

Examples?

Check the TriangleCount and PageRank implementations to see how the library is used to implement high-performant graph algorithms.

License: MIT

You might also like...
"Algorithms for approximate string matching" in Rust, with Python bindings.

ukkonen Implementation of a bounded Levenshtein distance by Esko Ukkonen in "Algorithms for approximate string matching" in Rust, with Python bindings

Common data structures and algorithms for competitive programming in Rust
Common data structures and algorithms for competitive programming in Rust

algorithm-rs algorithm-rs is common data structures and algorithms for competitive programming in Rust. Contents TBA How To Contribute Contributions a

zine/book about bitmap drawing algorithms and math with code examples in Rust
zine/book about bitmap drawing algorithms and math with code examples in Rust

A Bitmapper's Companion - zine/book about bitmap drawing algorithms and math with code examples in Rust A small zine/book written in LaTeX. In progres

Algorithms implemented in Rust, explained.

Rusty Algorithms & Data Structures for Learners This repository presents Rust implementations of common algorithms and data structures, many of which

Bandit Algorithms in Rust
Bandit Algorithms in Rust

Multi-armed bandit algorithms in Rust Cargo [dependencies] bandit = "0.12.3" Description and Scope This library currently only implements the annealin

A Rust implementation the HOTP and TOTP Algorithms

xotp A Rust implementation the HOTP and TOTP Algorithms. HOTP was implemented in accordance with RFC4226 TOTP was implemented in accordance with RFC62

A small collection of procedural dungeon generation algorithms.

mapgen A small collection of procedural dungeon generation algorithms. Built with Rust & macroquad. WebAssembly build deployed here. Animated version

Genetic Algorithm library in Rust

RsGenetic Summary and Features RsGenetic is a framework for executing genetic algorithms in Rust. It is designed to have a simple but modular API. Exa

Comments
  • Associated Edge Data

    Associated Edge Data

    I'm looking at graph for backing a RVSDG implementation which is centered around edge "kinds" that hold various data, ex a value edge or a control flow edge. The ability to store data within edges and to query against it effectively (sometimes you just want to see state nodes from a given source to destination) is essential for that, so that'd be a really great addition. This also requires the ability to have multiple (possibly identical) edges going between nodes and the multiplicity of the edges being retained, if that's a concern. Thanks!

    opened by Kixiron 2
  • Provide stable fallback for maybe_uninit_write_slice

    Provide stable fallback for maybe_uninit_write_slice

    This acts also as a scaffold for how to maybe get rid of other feature requirements.

    The idea is that we can probe if we need to fallback, which is not the case for nightly or when that features has been stabilized. If we need to fallback, we provide a compat impl using current stable code.

    opened by knutwalker 1
  • Allow relabeling and changing layout when calling to_undirected

    Allow relabeling and changing layout when calling to_undirected

    • to_undirected in the Rust API accepts an optional layout, which is not exposed in the Python API
    • Additionally, allow relabelling in the same step
    • Maybe we can extend the Layout enum to smth like { Unsorted, SortedById, SortedByDegree, DeduplicatedById, DeduplicatedByDegree } ?
    opened by knutwalker 0
Owner
Martin Junghanns
Martin Junghanns
Genetic Algorithms Library

genx genx provides modular building blocks to run simulations of optimization and search problems using Genetic Algorithms (GA). The vision for genx i

Lakshya Singh 29 Aug 9, 2022
This library provides implementations of many algorithms and data structures that are useful for bioinformatics.

This library provides implementations of many algorithms and data structures that are useful for bioinformatics. All provided implementations are rigorously tested via continuous integration.

Rust-Bio 1.2k Dec 26, 2022
Fast, parallel, extensible and adaptable genetic algorithms framework written in Rust

oxigen Oxigen is a parallel genetic algorithm framework implemented in Rust. The name comes from the merge of OXIdación (Rust translated to Spanish) a

Martín Pozo 146 Dec 18, 2022
darwin-rs, evolutionary algorithms with rust

darwin-rs This library allows you to write evolutionary algorithms (EA) using the Rust programming language. Written by Willi Kappler, License: MIT -

Willi Kappler 95 Jan 1, 2023
Radiate is a parallel genetic programming engine capable of evolving solutions to many problems as well as training learning algorithms.

Radiate Coming from Evolutionary Radiation. Evolutionary radiation is a rapid increase in the number of species with a common ancestor, characterized

kalivas 109 Dec 18, 2022
Compare binary files using alignment algorithms

biodiff Compare binary files using alignment algorithms. What is this This is a tool for binary diffing. The tool is able to show two binary files sid

null 483 Dec 22, 2022
This crate implements fast route planning algorithms in Rust.

This crate implements fast route planning algorithms in Rust. Algorithms Currently implemented: Contraction Hierarchies: The implementat

Payas Rajan 4 Aug 15, 2021
A browser app that evolves vehicles using genetic algorithms, written in Rust and Bevy

Vehicle Evolver Deluxe This is a simulation that uses AI (to be specific: genetic algorithms) to try to build better and better vehicles. The vehicles

null 95 Dec 26, 2022
DSP algorithms for embedded. Often integer math.

This crate contains some tuned DSP algorithms for general and especially embedded use.

QUARTIQ 12 Nov 3, 2022
ECFFT algorithms on the BN254 base field

ECFFT algorithms on the BN254 base field This crate implements structs and traits for the ECFFT algorithms from the paper Elliptic Curve Fast Fourier

null 36 Nov 28, 2022