Zog.ResourceGraph (Zog v0.3.0)
View SourceNative graph resource backed by Zog (Zig) via Zigler.
Unlike the Copy-In/Copy-Out pattern, ResourceGraph keeps the Zig
ArrayGraph or GraphMap alive as a NIF resource between calls. Build once,
run many algorithms, destroy when done.
Backends
Zog supports two native graph backends, selectable via the :backend option:
:soa(default) - Structure of Arrays (ArrayGraph).- Structure: Stores nodes and edges in flat, contiguous memory slices.
- Performance: Provides maximum execution speed and optimal cache locality.
- Use Case: Recommended for read-heavy, build-once-run-many query workloads where the topology does not change between NIF calls.
:hash_graph- Hash Map Graph (GraphMap).- Structure: Stores nodes and edges using standard hash tables with buckets and dynamic resizing.
- Performance: Incurs significant overhead due to pointer-heavy hashing, collision resolution, and lack of cache locality.
- Use Case: Use only if your workload relies on dynamic graph mutation (adding or deleting nodes/edges natively) between algorithm executions.
Examples
Create a resource graph using the high-performance :soa backend:
graph = Zog.directed() |> Zog.add_edge("A", "B", 1.0)
res = Zog.ResourceGraph.new(graph, backend: :soa)
# compute centralities...
Zog.ResourceGraph.destroy(res)Create a resource graph using the :hash_graph backend:
res = Zog.ResourceGraph.read_edgelist("edges.txt", backend: :hash_graph)
# compute centralities...
Zog.ResourceGraph.destroy(res)
Summary
Functions
Alpha centrality.
Analyzes an undirected ResourceGraph natively to find all bridges and articulation points.
Computes the Approximate Neighborhood Function (ANF) and effective diameter.
Returns {:ok, %{neighborhood_sizes: [float()], effective_diameter: float()}} or {:error, any()}.
Degree assortativity.
Computes the shortest path and its weight between two nodes using A* algorithm directly on the native graph resource.
Average clustering coefficient.
Computes the shortest path and its weight between two nodes using Bellman-Ford algorithm directly on the native graph resource.
Weighted betweenness centrality.
Unweighted betweenness centrality.
Checks whether a ResourceGraph is bipartite (2-colourable) natively.
Returns the bipartite partition of a ResourceGraph as two MapSets of
node labels, or {:error, :not_bipartite} if the graph is not 2-colourable.
Closeness centrality.
Contracts two nodes in a ResourceGraph into a single node.
Calculates all core numbers for all nodes in the ResourceGraph.
Explicitly destroys a native graph resource, freeing its memory.
Computes the shortest path and its weight between two nodes using Dijkstra's algorithm directly on the native graph resource.
Returns the ego graph of center from a ResourceGraph.
Eigenvector centrality.
Floyd-Warshall all-pairs shortest paths.
Builds a native graph resource directly from a Graph (from libgraph).
Builds a native graph resource directly from a Yog.Graph.
Computes the global minimum cut of the undirected network using the Stoer-Wagner algorithm.
Harmonic centrality.
Johnson's Algorithm for all-pairs shortest paths.
Katz centrality.
Label Propagation community detection.
Leiden community detection.
Leiden hierarchical community detection.
Local clustering coefficient for each node.
Louvain community detection.
Computes the maximum flow and minimum cut natively on a ResourceGraph.
Computes a maximum bipartite matching on a ResourceGraph using the
Hopcroft-Karp algorithm.
Computes modularity for a given community partition.
Builds a native graph resource from a SoA.
Graph density.
Returns a list of node degrees directly corresponding to internal u32 node IDs.
PageRank centrality.
Checks if a target node is reachable from a start node using BFS traversal directly on the native graph resource.
Reads a graph from an adjacency list file directly in native memory.
Reads a graph from an edge list file directly in native memory.
Reads a graph from a Trivial Graph Format (TGF) file directly in native memory.
Finds strongly connected components in the ResourceGraph natively. Returns a list of lists of node labels.
Extracts an induced subgraph from a ResourceGraph containing only the
specified node labels and the edges between them.
Converts a native graph resource back to a Graph (from libgraph).
Converts a native graph resource back to a Yog.Graph.
Computes the transitive closure of a ResourceGraph.
Computes the transitive reduction of a ResourceGraph.
Triangle count.
Finds weakly connected components in the ResourceGraph natively. Returns a list of lists of node labels.
Types
Functions
@spec alpha_centrality( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Alpha centrality.
Options
:alpha- Attenuation factor (defaults to0.5).:initial- Initial values (defaults to1.0).:max_iterations- Maximum iteration steps (defaults to100).:tolerance- Convergence tolerance (defaults to0.0001).:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec analyze( t(), keyword() ) :: %{ bridges: [{Zog.SoA.label(), Zog.SoA.label()}], articulation_points: [Zog.SoA.label()] }
Analyzes an undirected ResourceGraph natively to find all bridges and articulation points.
@spec anf( t(), keyword() ) :: {:ok, %{neighborhood_sizes: [float()], effective_diameter: float()}} | {:error, any()}
Computes the Approximate Neighborhood Function (ANF) and effective diameter.
Returns {:ok, %{neighborhood_sizes: [float()], effective_diameter: float()}} or {:error, any()}.
Options
:max_steps- Maximum number of steps to traverse (defaults to30).:m- Number of registers (trials) per node (defaults to64).
Degree assortativity.
@spec astar( t(), Zog.SoA.label(), Zog.SoA.label(), map() | list(), map() | list(), atom(), keyword() ) :: {:ok, {[Zog.SoA.label()], float()}} | {:error, :no_path}
Computes the shortest path and its weight between two nodes using A* algorithm directly on the native graph resource.
Average clustering coefficient.
@spec bellman_ford(t(), Zog.SoA.label(), Zog.SoA.label(), keyword()) :: {:ok, {[Zog.SoA.label()], float()}} | {:error, :no_path} | {:error, :negative_cycle}
Computes the shortest path and its weight between two nodes using Bellman-Ford algorithm directly on the native graph resource.
@spec betweenness_f64( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Weighted betweenness centrality.
Options
:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec betweenness_unweighted( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Unweighted betweenness centrality.
Options
:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
Checks whether a ResourceGraph is bipartite (2-colourable) natively.
Returns true when the graph is bipartite, false otherwise.
@spec bipartite_partition( t(), keyword() ) :: {:ok, MapSet.t(Zog.SoA.label()), MapSet.t(Zog.SoA.label())} | {:error, :not_bipartite}
Returns the bipartite partition of a ResourceGraph as two MapSets of
node labels, or {:error, :not_bipartite} if the graph is not 2-colourable.
Returns {:ok, set_a, set_b}.
@spec closeness_f64( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Closeness centrality.
Options
:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec contract(t(), Zog.SoA.label(), Zog.SoA.label(), keyword()) :: t()
Contracts two nodes in a ResourceGraph into a single node.
See Zog.Transform.contract/4 for options.
@spec core_numbers( t(), keyword() ) :: %{required(Zog.SoA.label()) => integer()} | [integer()]
Calculates all core numbers for all nodes in the ResourceGraph.
Options
:raw- If true, returns a list of core numbers directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec destroy(t()) :: :ok
Explicitly destroys a native graph resource, freeing its memory.
@spec dijkstra(t(), Zog.SoA.label(), Zog.SoA.label(), keyword()) :: {:ok, {[Zog.SoA.label()], float()}} | {:error, :no_path}
Computes the shortest path and its weight between two nodes using Dijkstra's algorithm directly on the native graph resource.
@spec edge_count(t()) :: non_neg_integer()
@spec ego_graph(t(), Zog.SoA.label(), keyword()) :: t()
Returns the ego graph of center from a ResourceGraph.
The returned ResourceGraph contains the center node, all nodes within
:radius hops (default 1), and all edges between those nodes. Edges are
treated as undirected when expanding the neighbourhood.
Options
:radius- number of hops to include (default 1)
@spec eigenvector( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Eigenvector centrality.
Options
:max_iterations- Maximum iteration steps (defaults to100).:tolerance- Convergence tolerance (defaults to0.0001).:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
Floyd-Warshall all-pairs shortest paths.
Builds a native graph resource directly from a Graph (from libgraph).
Builds a native graph resource directly from a Yog.Graph.
@spec global_min_cut( t(), keyword() ) :: %{ cut_value: float(), source_side: [Zog.SoA.label()], sink_side: [Zog.SoA.label()] }
Computes the global minimum cut of the undirected network using the Stoer-Wagner algorithm.
@spec harmonic_centrality_f64( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Harmonic centrality.
Options
:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
Johnson's Algorithm for all-pairs shortest paths.
@spec katz( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Katz centrality.
Options
:alpha- Attenuation factor (defaults to0.1).:beta- Weight parameter (defaults to1.0).:max_iterations- Maximum iteration steps (defaults to100).:tolerance- Convergence tolerance (defaults to0.0001).:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec kruskal( t(), keyword() ) :: {:ok, [Yog.MST.edge()]}
@spec label_propagation( t(), keyword() ) :: %{required(Zog.SoA.label()) => non_neg_integer()} | [non_neg_integer()]
Label Propagation community detection.
Options
:max_iterations- Maximum iteration steps (defaults to100).:seed- Random seed (defaults to0).:raw- If true, returns a list of community IDs directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec label_propagation( reference(), 0..18_446_744_073_709_551_615, 0..18_446_744_073_709_551_615 ) :: [ 0..18_446_744_073_709_551_615 ]
@spec leiden( t(), keyword() ) :: %{required(Zog.SoA.label()) => non_neg_integer()} | [non_neg_integer()]
Leiden community detection.
Options
:min_modularity_gain- Minimum modularity gain to stop iterations (defaults to0.000001).:max_iterations- Maximum iteration steps (defaults to100).:seed- Random seed for execution (defaults to42).:theta- Resolution parameter theta (defaults to1.0).:raw- If true, returns a list of community IDs directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec leiden_hierarchical( t(), keyword() ) :: Zog.Community.Dendrogram.t() | [[non_neg_integer()]]
Leiden hierarchical community detection.
Options
:min_modularity_gain- Minimum modularity gain to stop iterations (defaults to0.000001).:max_iterations- Maximum iteration steps (defaults to100).:seed- Random seed for execution (defaults to42).:theta- Resolution parameter theta (defaults to1.0).:raw- If true, returns a raw list of lists of community assignments for each level instead of aDendrogramstruct.
@spec local_clustering_coefficient( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
Local clustering coefficient for each node.
Options
:raw- If true, returns a list of coefficients directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec louvain( t(), keyword() ) :: %{required(Zog.SoA.label()) => non_neg_integer()} | [non_neg_integer()]
Louvain community detection.
Options
:min_modularity_gain- Minimum modularity gain to stop iterations (defaults to0.000001).:max_iterations- Maximum iteration steps (defaults to100).:seed- Random seed for execution (defaults to42).:raw- If true, returns a list of community IDs directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec max_flow(t(), Zog.SoA.label(), Zog.SoA.label(), atom() | keyword(), keyword()) :: %{ max_flow: float(), residual_graph: Zog.SoA.t(), source_side: [Zog.SoA.label()], sink_side: [Zog.SoA.label()] }
Computes the maximum flow and minimum cut natively on a ResourceGraph.
@spec maximum_bipartite_matching( t(), keyword() ) :: {:ok, [{Zog.SoA.label(), Zog.SoA.label()}]} | {:error, :not_bipartite}
Computes a maximum bipartite matching on a ResourceGraph using the
Hopcroft-Karp algorithm.
Returns {:ok, pairs} where pairs is a list of {left_label, right_label}
tuples. Returns {:error, :not_bipartite} if the graph is not bipartite.
@spec modularity(t(), %{required(Zog.SoA.label()) => non_neg_integer()}) :: float()
Computes modularity for a given community partition.
Builds a native graph resource from a SoA.
Options
:backend- Choose the native graph backend, either:soaor:hash_graph(defaults to:soa).
@spec nif_core_numbers(reference()) :: [0..4_294_967_295]
@spec nif_destroy(reference()) :: :ok
@spec nif_edge_count(reference()) :: 0..18_446_744_073_709_551_615
@spec nif_node_count(reference()) :: 0..18_446_744_073_709_551_615
@spec nif_node_degrees(reference()) :: [0..4_294_967_295]
@spec nif_strongly_connected_components(reference()) :: [0..4_294_967_295]
@spec nif_triangle_count(reference()) :: 0..18_446_744_073_709_551_615
@spec nif_weakly_connected_components(reference()) :: [0..4_294_967_295]
@spec node_count(t()) :: non_neg_integer()
Graph density.
Returns a list of node degrees directly corresponding to internal u32 node IDs.
@spec pagerank( t(), keyword() ) :: %{required(Zog.SoA.label()) => float()} | [float()]
PageRank centrality.
Options
:damping- PageRank damping factor (defaults to0.85).:max_iterations- Maximum iteration steps (defaults to100).:tolerance- Convergence tolerance (defaults to0.0001).:raw- If true, returns a list of scores directly corresponding to internalu32node IDs instead of mapping to Elixir labels.
@spec reachable?(t(), Zog.SoA.label(), Zog.SoA.label(), keyword()) :: boolean()
Checks if a target node is reachable from a start node using BFS traversal directly on the native graph resource.
Reads a graph from an adjacency list file directly in native memory.
Options
:directed- Boolean flag representing if the graph is directed (defaults totrue).:backend- Choose the native graph backend, either:soaor:hash_graph(defaults to:soa).:integer_labels- If true, parses labels as integers directly in Zig, bypassing string hash-map lookups (defaults tofalse). Note that sparse ID spaces will result in placeholder nodes being created up tomax_id, meaningnode_countwill returnmax_id + 1rather than the count of unique active nodes.
Reads a graph from an edge list file directly in native memory.
Options
:directed- Boolean flag representing if the graph is directed (defaults totrue).:backend- Choose the native graph backend, either:soaor:hash_graph(defaults to:soa).:integer_labels- If true, parses labels as integers directly in Zig, bypassing string hash-map lookups (defaults tofalse). Note that sparse ID spaces will result in placeholder nodes being created up tomax_id, meaningnode_countwill returnmax_id + 1rather than the count of unique active nodes.
Reads a graph from a Trivial Graph Format (TGF) file directly in native memory.
Options
:directed- Boolean flag representing if the graph is directed (defaults totrue).:backend- Choose the native graph backend, either:soaor:hash_graph(defaults to:soa).:integer_labels- If true, parses labels as integers directly in Zig, bypassing string hash-map lookups (defaults tofalse). Note that sparse ID spaces will result in placeholder nodes being created up tomax_id, meaningnode_countwill returnmax_id + 1rather than the count of unique active nodes.
Finds strongly connected components in the ResourceGraph natively. Returns a list of lists of node labels.
Options
:raw- If true, returns a list of component IDs directly corresponding to internalu32node IDs instead of grouping and mapping to Elixir labels.
@spec subgraph(t(), [Zog.SoA.label()] | MapSet.t(Zog.SoA.label()), keyword()) :: t()
Extracts an induced subgraph from a ResourceGraph containing only the
specified node labels and the edges between them.
Returns a new ResourceGraph holding both the native Zig resource and the
corresponding Elixir SoA metadata. Call ResourceGraph.destroy/1 on the
returned graph when it is no longer needed to release native memory.
Converts a native graph resource back to a Graph (from libgraph).
Converts a native graph resource back to a Yog.Graph.
Computes the transitive closure of a ResourceGraph.
Returns a new directed ResourceGraph with an edge (u, v) for every node
v reachable from u in the original graph, including self-loops.
Raises ArgumentError if the input graph is undirected.
Computes the transitive reduction of a ResourceGraph.
Returns a new directed ResourceGraph containing the minimal set of edges
that preserves the same reachability as the original DAG.
Raises ArgumentError if the graph is undirected or contains cycles.
@spec triangle_count(t()) :: non_neg_integer()
Triangle count.
@spec weakly_connected_components( t(), keyword() ) :: [[Zog.SoA.label()]] | [non_neg_integer()]
Finds weakly connected components in the ResourceGraph natively. Returns a list of lists of node labels.
Options
:raw- If true, returns a list of component IDs directly corresponding to internalu32node IDs instead of grouping and mapping to Elixir labels.