Skip to content

Core Concepts in Graphina

Graphina is designed to be fast, memory-efficient, and easy to use, but coming from dynamic libraries like NetworkX, some concepts might be new.

Graph Types

Graphina provides two primary graph structures, both of which are generic over node attributes (A) and edge weights (W).

  • Graph<A, W>: An undirected graph. Edges have no direction; add_edge(a, b, w) effectively connects \(a \leftrightarrow b\).
  • Digraph<A, W>: A directed graph. Edges go from source to target. neighbors(u) returns only outgoing neighbors (successors).

Strongly Typed Data

Unlike Python where a graph can hold mixed types (like strings, ints, objects), Graphina graphs are strongly typed.

// A social network: Nodes are people (String), Edges are relationship strength (f64)
let g = Graph::<String, f64>::new();

// A road map: Nodes are intersections (Point struct), Edges are distances (u32)
let g = Graph::<Point, u32>::new();

This design allows Graphina to optimize memory layout and guarantee data consistency at compile time.

References via NodeId

In NetworkX, the node value (like "Alice") is often the identifier. In Graphina, adding a node transfers ownership of the data to the graph and returns a NodeId.

let id = graph.add_node("Data");

This NodeId is a lightweight handle (essentially an integer index) that permits \(O(1)\) access to the node. You use this ID for all subsequent graph operations:

  • Creating edges (graph.add_edge(id1, id2, ...))
  • Querying neighbors (graph.neighbors(id1))
  • Algorithms (pagerank(&graph, ...))

The try_ API vs Panicking API

Graphina offers two styles of interaction:

Use the try_ variants or Option/Result returning methods for robustness:

  • graph.add_node(...) -> matches NetworkX behavior (panics or updates).
  • graph.try_add_node(...) -> Returns Result.<_, GraphinaError>. Recommended for production applications where you need to handle missing nodes or invalid operations gracefully.

Performance

Graphina wraps petgraph's StableGraph, meaning:

  • Fast Lookups: Nodes and edges are stored in vectors.
  • Stability: Removing a node does not invalidate the NodeIds of other nodes.