Backends#

NetworkX can hand an algorithm to a backend, a separately installed package such as nx-parallel (multicore CPU) or nx-cugraph (NVIDIA GPU), through its dispatch mechanism (nx._dispatchable). See NetworkX’s backends guide for how backends are installed and configured.

What is dispatchable#

Every function that takes a graph and returns a scored copy of it is dispatchable, as NetworkX’s own algorithms are:

  • statistical scorers (disparity_filter, noise_corrected_filter, marginal_likelihood_filter, ecm_filter, lans_filter, multiple_linkage_analysis, polya_filter, gloss_filter);

  • every structural method (global_threshold_filter, metric_backbone, h_backbone, maximum_spanning_tree_backbone, …);

  • proximity scores, glab_filter, and the unweighted sparsifiers (sparsify, lspar, local_degree);

  • multigraph_to_weighted, threshold_filter, fraction_filter, boolean_filter, and transform_weights.

These functions accept the backend= keyword and follow nx.config.backend_priority. They are registered under the dispatch name "backbone_" + name (disparity_filter is "backbone_disparity_filter"), because NetworkX keeps one registry of names for all packages: adamic_adar_index and resource_allocation_index are already NetworkX link-prediction functions, which nx-parallel implements.

The other functions are not dispatchable. The bipartite functions accept incidence matrices as well as graphs, the hypergraph functions take lists of hyperedges, the evaluation measures return numbers, consensus_backbone takes any number of graphs, and the temporal functions take snapshots (several graphs) or a multigraph of events or spans.

Using a backend#

No backend implements a backbone_* function yet, so backend="parallel" raises NotImplementedError. backend="networkx" (the default) always works:

import networkx as nx
import nx_backbone as nb

G = nx.les_miserables_graph()
H = nb.metric_backbone(G, backend="networkx")

A backend can still speed up the NetworkX algorithms that the backbone methods call, such as all_pairs_dijkstra_path_length (metric backbone) and edge_betweenness_centrality (edge_betweenness_filter, h_backbone). List the backend in nx.config.backend_priority; the backbone function runs its NetworkX code, and each NetworkX algorithm that the backend implements runs on the backend:

# pip install nx-parallel
with nx.config.backend_priority(algos=["parallel"]):
    H = nb.edge_betweenness_filter(G)

# or for the whole session
nx.config.backend_priority.algos = ["parallel"]

Setting the environment variable NETWORKX_BACKEND_PRIORITY=parallel before importing NetworkX does the same. nx-parallel’s own settings, such as the number of jobs, are under nx.config.backends.parallel.

NetworkX caches the converted graph on the input graph (G.__networkx_cache__), so a second call on the same graph skips the conversion and warns that the cache is being used. The cache is only correct if the graph has not been modified in place since; see nx.config.cache_converted_graphs and nx.config.warnings_to_ignore.

Measured timings#

scripts/benchmark_backends.py times the shortest-path methods on a Barabási-Albert graph with 1,000 nodes and 2,991 integer-weighted edges (the seeded graph in benchmarks/benchmarks/_data.py), with and without nx-parallel 0.4 in backend_priority. Best of 3 runs, Python 3.13, NetworkX 3.7, 4 CPUs, nx-parallel’s default n_jobs=-1:

Method

NetworkX (s)

parallel (s)

Ratio

Max diff

metric_backbone

2.23

2.13

1.05

0.0e+00

edge_betweenness_filter

4.29

1.13

3.79

3.5e-18

h_backbone

1.82

0.54

3.38

1.4e-14

high_salience_skeleton

3.16

3.40

0.93

0.0e+00

glab_filter

3.50

3.84

0.91

0.0e+00

Ratio is the NetworkX time divided by the nx-parallel time. Max diff is the largest difference between any score the two runs return. nx-parallel adds up edge betweenness in a different order, so those scores can differ in the last bits; on this graph every *_keep flag was the same. These timings are from one machine. Measure on your own graphs and hardware before relying on them.

high_salience_skeleton and glab_filter run one single-source search per node (dijkstra_predecessor_and_distance), which nx-parallel 0.4 does not implement, so they gain nothing. metric_backbone calls all_pairs_dijkstra_path_length, which nx-parallel implements, but it was not faster here.

Testing with a backend#

The test suite can run under NetworkX’s dispatch test harness, as NetworkX’s own tests do. With nx_loopback, the test backend that ships with NetworkX, every dispatchable call converts its input graphs, runs, and checks that the result equals the plain NetworkX result:

NETWORKX_TEST_BACKEND=nx_loopback pytest --doctest-modules nx_backbone tests

Add NETWORKX_FALLBACK_TO_NX=1 to run with NetworkX the functions a backend does not implement, instead of marking their tests as expected failures.

The narrative guide Scaling up to large networks puts these timings next to run times measured at build time and the other ways to handle large networks.