Expand description
§Weisfeiler-Leman Graph Isomorphism
This crate provides an implementation of the Weisfeiler-Leman (WL) graph isomorphism algorithm for petgraph graphs.
WL is a sound but incomplete isomorphism test, that because of its speed is often used as a subroutine in complete tests and feature extraction for graph kernels. Additionally, it includes an implementation of the two-dimensional version of the algorithm, which offers greater distinguishing power—particularly for regular graphs—at the cost of a significant runtime penalty.
§Example
The crate’s most basic usage is to compare two graphs for isomorphism using the invariant function.
The function will return the same graph hash for isomorphic graphs (hence it is called an “invariant”), and in most cases different hashes for non-isomorphic graphs.
use petgraph::graph::{UnGraph, DiGraph};
let g1 = UnGraph::<u64, ()>::from_edges([(0,1), (1,2), (2,0), (2,3)]);
let g2 = UnGraph::<u64, ()>::from_edges([(0,1), (1,2), (2,0), (0,3)]);
let g3 = UnGraph::<u64, ()>::from_edges([(0,1), (1,2), (2,3), (0,3)]);
let g4 = DiGraph::<u64, ()>::from_edges([(0,1), (1,2), (2,0), (2,3)]);
let hash1 = wl_isomorphism::invariant(g1);
let hash2 = wl_isomorphism::invariant(g2);
let hash3 = wl_isomorphism::invariant(g3);
let hash4 = wl_isomorphism::invariant(g4);
println!("The final hashes (u64) are:");
println!("1: {}, 2: {}, 3: {}, and: {}", hash1, hash2, hash3, hash4);
// 1: 16339153988175251892, 2: 16339153988175251892, 3: 14961629621624962419, and: 15573326168912649736§IMPORTANT
- The WL algorithm is not a complete isomorphism test. This means that when the algorithm returns the same hash for two graphs, they are possibly isomorphic, but not guaranteed. On certain classes of graphs (such as random graphs) this is almost always a good indicator of isomorphism, but it is for example not trustworthy on regular graphs. It is, however, a sound test, meaning that if the algorithm returns different hashes, the graphs are guaranteed to be non-isomorphic.
- Hash values depend on the number of iterations. For algorithms with a fixed iteration count, even the same graph will yield different hashes for different iteration counts.
- Hash values depend on device endianness. The same graph will produce different hashes on little-endian and big-endian systems. Compare hashes only on the same device or verify results using example graphs.
§Features
- Isomorphism testing.
- Calculate a graph’s hash to compare it with other graphs’ hashes to determine if they are isomorphic.
- Use
invariant, or if you want the algorithm to run for a specific number of iterations, useinvariant_iters. - Alternatively, use the two-dimensional versions of these,
invariant_2wlanditer_2wl, which offer greater distinguishing power—particularly for regular graphs—at the cost of a significant runtime penalty.
- Subgraph hashing .
- Obtain subgraph hashes for each node at each iteration for tasks like feature extraction for graph kernels.
- Use
neighbourhood_hashfor a fixed number of iterations orneighbourhood_stableto run until stabilisation.
- Dot file output.
- Write the graph to a dot file, where the colour class of each node is visualised.
- Use
invariant_dotoriter_dot.
- Read from NetworkX edgelist file
- Load graphs from text files in the NetworkX edgelist format.
- Use
ungraph_from_edgelistordigraph_from_edgelist.
Functions§
- digraph_
from_ edgelist - Read a directed graph from a text file, as produced by
Networkx.write_edgelist. Note that this does not support weights and that if the edgelist skips certain indices, petgraph will infer an unconnected node at that index. - invariant
- Calculate the graph invariant using 1-dimensional WL. Automatically stabilises. On graph classes like regular graphs, it is better to use
invariant_2wl, which is more expressive but slower. - invariant_
2wl - Calculate the graph invariant using 2-dimensional WL. Automatically stabilises. This is an implementation of ‘2-FWL’. This is more expressive than 1-dimensional WL, but much slower. Therefore only use this on graph classes where our default
invariantdoes not work well. - invariant_
dot - Like
invariant, but it additionally writes the graph with the final colouring in dot format topath. - invariant_
iters - Calculate the graph invariant using 1-dimensional WL. Runs for
n_iters. Regular graphs tend to need at most 3 iterations for stabilisation, but for example random trees significantly more. We recommend usinginvariantfor optimal results, if you don’t require a specific number of iterations. - iter_
2wl - Calculate the graph invariant using 2-dimensional WL. Runs for
n_iters. We recommend usinginvariant_2wlfor optimal results if you don’t require a specific number of iterations. - iter_
dot - Like
invariant_iters, but it additionally writes the graph with the final colouring in dot format topath. - neighbourhood_
hash - Generate the subgraph hashes per node per iteration. Can, for example, be used for feature extraction for graph kernels. The computed hash values give some information on the i-hop neighbourhood. The first hash, for example, gives some information on the neighbourhood of each node reachable within one hop.
- neighbourhood_
stable - Like
neighbourhood_hash, but instead calculated until stability is achieved. (Note that we do not return the last calulated hashes, as these do not provide any new information: they are stable with respect to the last ones that áre returned.) - ungraph_
from_ edgelist - Read an undirected graph from a text file, as produced by
Networkx.write_edgelist. Note that this does not support weights and that if the edgelist skips certain indices, petgraph will infer unconnected nodes at said indices.