vf3 — Pure Rust VF3/VF3L Implementation
A pure Rust implementation of the VF3/VF3L subgraph isomorphism algorithms, inspired by the canonical C++ implementation from MIVIA Lab.
Features
- Pure Rust: No C++ dependencies for the core algorithm
- VF3L Algorithm: Lightweight variant without look-ahead heuristics
- Flexible Matching: Both node-induced and edge-induced (monomorphism) modes
- Graph Labels: Optional node and edge label matching
- Undirected Support: Can treat directed graphs as undirected
- Incremental Terminal Sets: Core VF3 pruning mechanism with in/out/union sets
Status
This is a functional implementation that works well on small to medium graphs. It implements:
- Edge-induced (monomorphism) and node-induced subgraph isomorphism
- Incremental terminal sets with VF3L pruning
- Degree/signature-based pattern ordering heuristic
- Node and edge label support
Not yet implemented:
- Full VF3 look-ahead pruning
- VF3P parallel variant
Installation
Add this to your Cargo.toml:
[]
= "0.1"
Quick Start
use ;
// Create a pattern graph (triangle)
let mut pattern = new;
pattern.add_edge?;
pattern.add_edge?;
pattern.add_edge?;
// Create a target graph (square)
let mut target = new;
target.add_edge?;
target.add_edge?;
target.add_edge?;
target.add_edge?;
// Find all matches (node-induced by default)
let opts = default;
let matches = find_subgraph_matches_with_options;
println!;
Options
Working with Labels
// Node labels
let mut g = new;
g.set_label; // Node 0 has label 1
g.set_label; // Node 1 has label 2
// Edge labels
g.add_edge_with_label?; // Edge with label 42
g.add_edge?; // Edge with default label 0
// Enable label matching
let opts = VF3Options ;
Performance
For best performance, compile with release optimizations:
# With CPU-specific optimizations
RUSTFLAGS="-C target-cpu=native"
Performance and Safety
This crate uses unsafe code in performance-critical sections to achieve competitive performance with C++ implementations. The unsafe code is:
- Limited to hot paths: Primarily in the
lookahead_neighbor_capacityfunction which is called millions of times during graph matching - Well-documented: Every unsafe block includes SAFETY comments explaining the invariants
- Bounds-check elimination: Removes redundant bounds checks where indices are already validated by the algorithm's invariants
- Performance-justified: Subgraph isomorphism is NP-complete; these optimizations provide significant speedup (typically 2-3x) on real workloads
The unsafe optimizations include:
- Using
get_uncheckedfor array access where bounds are guaranteed by construction - Stack-allocated arrays for small label domains to avoid heap allocation
- Direct bitset access for O(1) edge existence checks
All unsafe code follows Rust's safety guidelines and the invariants are maintained by the VF3State structure. The codebase has been thoroughly tested and follows patterns used in other high-performance Rust graph libraries.
Comparison with C++ Implementation
This crate includes an optional feature to compare against the C++ VF3 implementation via FFI:
# Run comparison tests
# Run benchmarks comparing both implementations
Examples
# Basic usage example
# Performance testing harness
CLI Tool
The crate includes a command-line tool for running VF3 on JSON graph files:
# Install the CLI tool
# Run on graph files
# With options
Algorithm Details
This implementation follows the VF3L (lightweight) variant which:
- Uses terminal sets (Tin, Tout, Tunion) for pruning the search space
- Orders pattern nodes by rarity (degree and optional label frequency)
- Performs feasibility checks for each candidate mapping
- Backtracks efficiently when no valid mapping exists
The algorithm is particularly effective on sparse graphs and when the pattern is much smaller than the target.
License
MIT OR Apache-2.0
References
- VF3: A New Algorithm for Subgraph Isomorphism (Carletti et al., 2018)
- Original C++ VF3lib