-
Notifications
You must be signed in to change notification settings - Fork 2
VLDB Experiments
Complete reference for reproducing the GraphBrew AdaptiveOrder-ML experiments.
This document explains every number, every ML model, every feature, and every
pipeline phase so you can run the full experiment from an empty results/
folder and understand every output file produced.
- Background & Motivation
- Numbers at a Glance
- The 7-Phase Training Pipeline
- The 8 VLDB Experiments
- ML Models Explained
- The 22-Feature Vector
- Running from Scratch
- Interpreting Results
- Variant System
Graph algorithms (PageRank, BFS, SSSP, CC, …) access vertices in irregular patterns that defeat hardware prefetchers and caches. Vertex reordering relabels the graph so that frequently co-accessed vertices sit close in memory, dramatically improving cache hit rates and execution time.
The catch: no single reordering algorithm wins on every graph.
- Gorder excels on dense social networks but is too slow for billion-edge web graphs.
- RabbitOrder is fast but loses to simpler methods on road networks.
- GraphBrewOrder (Leiden + per-community reordering) adapts well to community-heavy graphs but is overkill for uniform meshes.
This is the oracle gap — the difference between always using a fixed algorithm and always picking the best one per graph. Our VLDB experiments quantify this gap across hundreds of real-world graphs from the SuiteSparse Matrix Collection and show that AdaptiveOrder (algorithm 14), an ML-powered selector, closes it.
- Train — Run all 13 reordering algorithms on a diverse corpus of graphs, benchmark 7 kernels, collect execution times + graph properties.
- Learn — Train a perceptron (and auxiliary models) to predict the fastest algorithm for a new, unseen graph based on 22 topological features.
- Deploy — At runtime, AdaptiveOrder extracts features from the input graph in ≈0.1 s, scores each algorithm, and picks the one with the highest predicted speedup — all inside the C++ binary, zero Python dependency.
We evaluate on real-world sparse matrices from SuiteSparse (up to 603
graph-like matrices), use a fully automated pipeline
(graphbrew_experiment.py) that handles downloads, builds, benchmarks, and ML
evaluation, and report reproducible numbers via Leave-One-Graph-Out (LOGO)
cross-validation.
| What | Count | Details |
|---|---|---|
| Algorithm IDs | 17 | IDs 0–16 |
| Benchmark-eligible | 15 | All except MAP (13) and AdaptiveOrder (14) |
| Reorder-producing | 13 | Eligible minus ORIGINAL (0) and RANDOM (1) |
| Benchmarks available | 8 | PR, PR_SPMV, BFS, CC, CC_SV, SSSP, BC, TC |
| Default benchmarks | 7 | TC excluded (combinatorial, not cache-sensitive) |
| Features (linear) | 16 | Topology, locality, convergence |
| Features (quadratic) | 5 | Cross-terms for non-linear interactions |
| Features (total) | 22 | Fed to perceptron; DT uses the same 22 features |
| ML models | 6 | Perceptron, DT, Hybrid, RF, XGBoost, Database kNN |
| Size categories | 4 | SMALL, MEDIUM, LARGE, XLARGE |
| SuiteSparse graphs | ~603 | Square, graph-like (kind ∈ {graph, network, multigraph}) |
| Auto-discovered | ~466 | Captured by current size bounds |
| LOGO CV folds | N | One fold per graph (leave-one-out) |
| Perceptron restarts | 5 | Random restarts for escaping local optima |
| Perceptron epochs | 800 | Per restart |
| Default trials | 3 | Benchmark repetitions per (graph, algorithm, kernel) |
| Category | Edge Range | Approx. Available | Download Size |
|---|---|---|---|
| SMALL | 10 K – 500 K | ~225 | ~100 MB |
| MEDIUM | 500 K – 5 M | ~134 | ~1.1 GB |
| LARGE | 5 M – 50 M | ~70 | ~25 GB |
| XLARGE | 50 M – 500 M | ~37 | ~63 GB |
Running python3 scripts/graphbrew_experiment.py --target-graphs 150 --size small
executes all 7 phases sequentially (unless you use --phase to select
specific ones):
┌──────────┐ ┌───────┐ ┌──────────┐ ┌──────────┐
│ Download │───▶│ Build │───▶│ Convert │───▶│ Reorder │
└──────────┘ └───────┘ └──────────┘ └──────────┘
│
▼
┌───────────┐ ┌──────────┐
│ Cache Sim │◀─│Benchmark │
└───────────┘ └──────────┘
│
▼
┌──────────┐
│ Evaluate │
└──────────┘
| # | Phase | What Happens | Key Output | Timeout |
|---|---|---|---|---|
| 0 | Download | Fetches .mtx files from SuiteSparse. 16 hardcoded SMALL graphs + auto-discovered extras via ssgetpy. Enforces --max-memory and --max-disk limits. |
results/graphs/<name>/<name>.mtx |
— |
| 1 | Build | Runs make in bench/ to compile standard binaries (bench/bin/) and cache-simulation binaries (bench/bin_sim/). |
bench/bin/pr, bench/bin/bfs, … |
600 s |
| 2 | Convert | Converts .mtx → .sg with RANDOM vertex ordering (algorithm 1). This is the baseline — all benchmark times measure improvement relative to worst-case random. |
results/graphs/<name>/<name>.sg |
— |
| 3 | Reorder | For each graph × each algorithm: runs the converter binary to produce a .lo (label-order mapping) file and records the reorder wall-clock time in a .time file. Pre-generates reordered .sg files if disk allows. |
results/mappings/<name>/<ALGO>.lo |
43 200 s (12 h) |
| 4 | Benchmark | Runs 7 kernels (pr, pr_spmv, bfs, cc, cc_sv, sssp, bc) × all orderings × N trials. Results appended to the centralized JSON datastore. At benchmark time, pre-generated .sg is loaded with -o 0 so there is no reorder overhead in the timing. |
results/data/benchmarks.json |
600 s |
| 5 | Cache Sim | Runs instrumented binaries (bench/bin_sim/) that simulate a 3-level cache hierarchy (L1 32 KB 8-way LRU, L2, L3) for PR and BFS. Reports hit/miss rates per cache level. |
Cache fields in benchmarks.json
|
1 200 s |
| 6 | Evaluate | LOGO cross-validation on all ML models. For each graph G: trains on all graphs except G, predicts best algorithm for G, compares to oracle. Reports top-1/top-3 accuracy, mean/median/p95 regret, within-5% rate. | results/data/evaluation_summary.json |
— |
If the original .mtx file already has a "good" ordering (e.g., BFS
numbering from the dataset author), benchmarking algorithms against it
conflates the quality of the dataset ordering with the quality of the
reordering algorithm. Converting to RANDOM first means every algorithm
starts from the same worst-case baseline, so speedup numbers are comparable
across graphs.
Reordering algorithms can take minutes (Gorder) or hours (COrder on large
graphs). Pre-computing the mapping once and storing it in a .lo file means:
- Reproducible benchmarks — the same mapping is reused across all trials and kernels.
-
Fair timing — benchmark time measures only kernel execution, not
reorder overhead (reorder cost is tracked separately in
.timefiles). -
MAP mode — at benchmark time, the binary loads the mapping with
-o 13:<path>.lo(algorithm 13 = MAP = "load from file").
| Parameter | Default | Description |
|---|---|---|
--target-graphs N |
— | Auto-sets --full, --catalog-size N, --auto, --all-variants
|
--size |
all |
Size category: small, medium, large, xlarge, all
|
--trials |
3 | Benchmark repetitions per (graph, algo, kernel) |
--benchmarks |
7 default | Space-separated list of kernels |
--skip-slow |
off | Skip Gorder (9), COrder (10), RCM (11) |
--skip-cache |
off | Skip cache simulation phase |
--skip-eval |
off | Skip LOGO evaluation phase |
--dry-run |
off | Print pipeline plan without executing |
--max-memory |
auto | Maximum RAM in GB (auto = 60% of physical) |
--max-disk |
auto | Maximum disk in GB (auto = 80% of free) |
--timeout-reorder |
43 200 | Per-algorithm reorder timeout (seconds) |
--timeout-benchmark |
600 | Per-benchmark timeout (seconds) |
All experiments are orchestrated by scripts/experiments/vldb_experiments.py.
Run them individually or all at once:
# All 8 experiments on LARGE graphs
python scripts/experiments/vldb_experiments.py --all --size large
# Specific experiments only
python scripts/experiments/vldb_experiments.py --exp 1 3 --size large
# Preview commands without executing
python scripts/experiments/vldb_experiments.py --all --dry-run
# Lightweight local preview (fewer graphs, 1 trial, 2 benchmarks)
python scripts/experiments/vldb_experiments_small.py --allWhat it proves: No single reordering algorithm dominates across all graphs.
Method: Run all 15 eligible algorithms (every ID except 13 MAP and 14 AdaptiveOrder) on every graph in the corpus. For each graph, identify the oracle (fastest algorithm). Plot the distribution of oracle choices — if every graph had the same winner, adaptive selection would be pointless.
python scripts/experiments/vldb_experiments.py --exp 1 --size largeExpected output: results/vldb_experiments/exp1_oracle_gap/ — benchmark
JSON + per-graph oracle mapping. Expect 4–6 different algorithms appearing as
oracle across the corpus.
What it proves: AdaptiveOrder matches or beats every static baseline on aggregate.
Method: Run AdaptiveOrder (algorithm 14) in three selection modes on the same graph set used in Experiment 1:
| Mode | CLI Flag | Optimizes For |
|---|---|---|
| 1 | fastest_exec |
Minimize kernel execution time |
| 2 | best_e2e |
Minimize reorder + execution |
| 3 | best_amort |
Minimize amortized cost over repeated runs |
python scripts/experiments/vldb_experiments.py --exp 2 --size largeExpected output: results/vldb_experiments/exp2_adaptive/ — one sub-dir
per mode. Compare geometric mean speedup vs ORIGINAL across modes.
What it proves: The ML models generalize — they correctly predict the best algorithm for graphs not seen during training.
Method: Leave-One-Graph-Out cross-validation. For N graphs, run N folds. In each fold, train on N−1 graphs, evaluate on the held-out graph. Report:
| Metric | Meaning |
|---|---|
| Top-1 accuracy | Predicted best = actual best |
| Top-3 accuracy | Actual best is in top 3 predictions |
| Mean regret | Average % slowdown vs oracle |
| Within-5% | Fraction of graphs where predicted is ≤ 5% slower than oracle |
python scripts/experiments/vldb_experiments.py --exp 3
# Or directly:
python scripts/evaluate_all_modes.py --all --jsonExpected output: results/vldb_experiments/exp3_logo_cv/logo_cv_results.log
Minimum: ≥ 3 graphs (≥ 10 recommended for stable metrics).
What it proves: Which features (packing factor, FEF, WSR, quadratic cross-terms) contribute most to selection accuracy.
Method: For each feature group, zero the corresponding weights in AdaptiveOrder and re-run the full benchmark. Compare accuracy to the all-features baseline.
| Ablation | Env Variable | Target Feature |
|---|---|---|
no_packing |
ADAPTIVE_ZERO_FEATURES=packing |
Packing factor (IISWC'18) |
no_fef |
ADAPTIVE_ZERO_FEATURES=fef |
Forward edge fraction (GoGraph) |
no_wsr |
ADAPTIVE_ZERO_FEATURES=wsr |
Working set ratio (P-OPT) |
no_quadratic |
ADAPTIVE_ZERO_FEATURES=quadratic |
All 5 cross-terms |
no_types |
ADAPTIVE_NO_TYPES=1 |
Graph type clustering |
no_ood |
ADAPTIVE_NO_OOD=1 |
Out-of-distribution guardrail |
no_margin |
ADAPTIVE_NO_MARGIN=1 |
Margin-based fallback |
no_leiden |
ADAPTIVE_NO_LEIDEN=1 |
Leiden community features |
all_features |
(none) | Baseline — everything enabled |
python scripts/experiments/vldb_experiments.py --exp 4 --size mediumExpected output: results/vldb_experiments/exp4_feature_ablation/<group>/
What it proves: AdaptiveOrder's streaming database reaches near-full accuracy after observing only 10–15 graphs.
Method: Simulate the streaming scenario:
- Start with an empty knowledge base.
- Process graphs one at a time (random order).
- After each graph, retrain the perceptron on accumulated data.
- Evaluate selection accuracy on the remaining unseen graphs.
- Repeat for multiple random permutations to reduce variance.
python scripts/experiments/vldb_experiments.py --exp 5 --size medium
# Then generate the learning curve:
python -m scripts.lib.analysis.cold_start_sim \
--benchmark-db results/data/benchmarks.json \
--output results/vldb_experiments/exp5_cold_start/learning_curve.json \
--permutations 10Expected output: x-axis = graphs seen, y-axis = top-1 accuracy on unseen graphs. Accuracy should plateau around 10–15 graphs.
What it proves: Reordering improves cache hit rates, and AdaptiveOrder selects orderings with near-optimal cache behavior.
Method:
-
Part A (Simulation): Run instrumented
bin_sim/binaries that simulate L1/L2/L3 cache hierarchies for PR and BFS. -
Part B (HW Counters): Run with
perfhardware counters on representative graphs (requiresperf stataccess).
python scripts/experiments/vldb_experiments.py --exp 6Expected output: results/vldb_experiments/exp6_cache/ — per-graph,
per-algorithm cache hit rates + optional perf counter data.
What it proves: GoGraph's forward-edge-fraction (FEF) maximization reduces the number of PageRank iterations needed for convergence.
Method: Run PageRank on representative graphs with ORIGINAL, Gorder, GraphBrewOrder, and GoGraphOrder. Parse iteration counts from stdout.
python scripts/experiments/vldb_experiments.py --exp 7Expected output: results/vldb_experiments/exp7_convergence/convergence_*.json
— per-graph iteration counts + average times.
What it proves: AdaptiveOrder's overhead is near-constant (feature extraction only) while Gorder/COrder scale super-linearly.
Method: Measure reorder wall-clock time across graph sizes spanning 4 orders of magnitude (10 K → 1 B+ edges).
python scripts/experiments/vldb_experiments.py --exp 8Expected output: results/vldb_experiments/exp8_scalability/ — reorder
time logs per graph × algorithm combination.
GraphBrew trains and evaluates six ML models. All are trained on the same
data (benchmarks.json + graph_properties.json) and evaluated via
LOGO cross-validation. The perceptron is the primary production model
because it can be fully embedded in C++ with zero runtime dependencies.
What it does: One perceptron per candidate algorithm. For a given graph, each perceptron scores "how good is my algorithm for this graph?" The algorithm with the highest score wins.
Score formula:
Where:
-
$f_0 \ldots f_{15}$ are the 16 linear features (see Section 6) -
$f_{\text{cross},0} \ldots f_{\text{cross},4}$ are the 5 quadratic cross-terms -
$\Delta_{\text{cache}}$ = cache impact (L1/L2/L3 improvement) -
$\Delta_{\text{fef}}$ = convergence bonus (GoGraph FEF gain) - Multiply by per-benchmark weight multiplier
Training:
-
Margin-based update (Jimenez, MICRO 2016): update only when the margin
between correct and incorrect is below threshold
$\theta$ - Averaged perceptron (Freund & Schapire 1999): final weights = average over all training steps (smooths noise)
-
Adaptive theta:
$\theta = \lfloor (1.93 \times n_{\text{feat}} + 14) \times W_{\max} / 127 \rfloor \approx 5$ for 22 features -
Hyperparameters: 5 random restarts × 800 epochs, learning rate 0.05
decayed by 0.997/epoch, weight cap
$W_{\max} = 16.0$ -
Seed:
42 + restart × 1000 + bench_idx × 100(deterministic)
Storage: results/models/perceptron/type_0/weights.json (generic weights),
results/models/perceptron/type_0/pr.json (per-benchmark specialization)
What: CART classifier (Gini impurity, max depth 6). Uses a 12-feature
subset matching the C++ ModelTree::extract_features() layout so the tree can
be exported and evaluated inside C++ without Python.
Advantage: Fully interpretable — you can print the tree and trace each split decision.
What: DT does initial algorithm selection. Within each leaf node, a per-leaf perceptron refines the choice using the full 22-feature vector. This combines the DT's coarse partitioning with the perceptron's fine-grained scoring.
What: Gradient-boosted ensemble. Family-based variants (community / bandwidth / cache algorithm groups) allow structured multi-class classification. Serves as a strong upper-bound on achievable accuracy.
What: Bagged ensemble of decision trees (100 estimators by default). Reduces variance vs a single DT, at the cost of losing interpretability.
What: Oracle lookup for graphs already in the database (benchmarks.json).
For unknown graphs, extract features and find the k nearest neighbors by
normalized feature distance. Use the best algorithm from the closest neighbor.
Advantage: No training — just needs a populated benchmark database. Disadvantage: Accuracy depends on having similar-looking graphs in the DB.
| File | Contents |
|---|---|
results/data/adaptive_models.json |
Unified model store (perceptron + DT + hybrid) |
results/models/perceptron/type_0/weights.json |
Type-0 (generic) perceptron weights |
results/models/perceptron/type_0/<benchmark>.json |
Per-benchmark specialized weights |
results/models/perceptron/registry.json |
Graph-type cluster registry (centroids) |
results/data/benchmarks.json |
Centralized benchmark database (append-only) |
results/data/graph_properties.json |
Per-graph 22-element feature vectors |
results/data/evaluation_summary.json |
LOGO CV results for all models |
The perceptron ingests a 22-element feature vector per graph, designed to capture topology, locality, and convergence properties. All features are computed in the C++ binary at runtime (no Python needed for inference).
| # | Name | Transform | What It Measures | Source |
|---|---|---|---|---|
| 0 | modularity |
raw | Leiden/Louvain quality Q. High → strong community structure. CC-count × 1.5 fallback if Leiden unavailable | — |
| 1 | degree_variance |
raw | Coefficient of variation of degree distribution. High → power-law (hubs) | — |
| 2 | hub_concentration |
raw | Edge fraction from top 10% highest-degree vertices. High → hub-dominated | — |
| 3 | log_nodes |
log₁₀(N+1) | Graph scale (vertices) | — |
| 4 | log_edges |
log₁₀(E+1) | Graph scale (edges) | — |
| 5 | density |
E/(N·(N−1)/2) | Edge density. Very small for large real-world graphs | — |
| 6 | avg_degree |
÷100 | Mean vertex degree, normalized | — |
| 7 | clustering_coeff |
raw | Local clustering coefficient (sampled, 1000 nodes) | — |
| 8 | avg_path_length |
÷10 | Multi-source BFS (5 sources, ≤ min(100 K, N/10) nodes each) | — |
| 9 | diameter |
÷50 | Max BFS depth (lower bound from sampled sources) | — |
| 10 | community_count |
log₁₀(count+1) | Connected component count (or Leiden community count) | — |
| 11 | packing_factor |
raw | Cache-line utilization for neighbors. High → good existing locality | IISWC'18 |
| 12 | forward_edge_fraction |
raw | Fraction of edges (u,v) where u < v. Measures natural topological sort quality | GoGraph |
| 13 | working_set_ratio |
log₂(WSR+1) |
graph_bytes / LLC_size. High → graph overflows last-level cache |
P-OPT |
| 14 | vertex_significance_skew |
raw | CV of per-vertex locality scores. Measures ordering inequality | DON-RL |
| 15 | window_neighbor_overlap |
raw | Mean fraction of neighbors within a sliding window of vertex IDs | DON-RL |
These capture non-linear interactions that individual features miss:
| # | Formula | Intuition |
|---|---|---|
| 16 | degree_variance × hub_concentration |
Power-law indicator: both high → aggressive hub-sorting helps |
| 17 | modularity × log₁₀(N) |
Scalable community structure: high modularity matters more on large graphs |
| 18 | packing_factor × log₂(WSR+1) |
Locality-vs-capacity trade-off: good packing + LLC overflow → reordering is critical |
| 19 | vertex_significance_skew × hub_concentration |
DON-RL cross-term: skewed locality + hubs → hub-aware methods win |
| 20 | window_neighbor_overlap × packing_factor |
DON-RL cross-term: existing locality quality interaction |
| # | Name | Transform | What It Measures | Source |
|---|---|---|---|---|
| 21 | packing_factor_cl |
raw | Fraction of neighbors on the same 64-byte cache line as the hub vertex. Faithful IISWC'18 definition using CL_VERTS=16 | IISWC'18 |
Feature extraction must be fast (< 0.5 s even on billion-edge graphs), so all features are sampled:
| Feature Group | Sample Size |
|---|---|
| Degree stats (1, 2, 6) | max(5000, min(√N, 50000)) — strided |
| Clustering coefficient (7) | 1000 random nodes |
| BFS diameter / path length (8, 9) | 5 sources, each visiting ≤ min(100 K, N/10) nodes |
| Packing factor (11) | max(16, N/1000) cache-line windows |
| DON-RL locality (14, 15) | max(64, N/100) vertex-ID windows |
| FEF (12) | 2000 sampled vertices |
A lightweight decision tree on features 0–2 and 6 classifies each graph:
| Type | Triggers |
|---|---|
road |
degree_variance < 0.5, avg_degree < 5 |
social |
high hub_concentration (> 0.4), high modularity |
web |
high degree_variance, moderate modularity |
powerlaw |
extreme degree_variance (> 3.0) |
uniform |
low degree_variance, low modularity |
generic |
everything else |
Type-specific perceptron weights are stored in
results/models/perceptron/type_<id>/. If the graph's type matches a known
cluster (distance < 0.15), type-specific weights are used; otherwise the
generic type_0 weights serve as fallback.
# System dependencies
sudo apt install g++ make wget # or brew install on macOS
# Python dependencies
python3 -m venv .venv && source .venv/bin/activate
pip install -r scripts/requirements.txt # ssgetpy, numpy, scikit-learn, xgboost, ...# Delete all previous results (graphs, mappings, models, benchmarks)
rm -rf results/
# Verify the script boots cleanly
python3 scripts/graphbrew_experiment.py --target-graphs 3 --size small --dry-runExpected output:
[INFO] --target-graphs 3: enabled --full, --catalog-size 3, --auto, --all-variants, --size small
[INFO] Using --size small: graphs=small, download=SMALL
[INFO] Auto-detected memory limit: ...
============================================================
GRAPHBREW DRY RUN — planned pipeline stages
============================================================
1. Download size=SMALL, catalog-size=3
2. Build compile C++ benchmark binaries
3. Convert .mtx → .sg (RANDOM baseline)
4. Reorder generate .lo mappings, variants=ALL
5. Benchmark benchmarks=pr, pr_spmv, bfs, cc, cc_sv, sssp, bc, trials=2
6. Cache Sim pr, bfs
7. Evaluate LOGO CV on all ML models
...
============================================================
(Remove --dry-run to execute)
python3 scripts/graphbrew_experiment.py \
--full --size small --auto --skip-cache \
--graph-list ca-GrQc email-Enron soc-Slashdot0902 \
--benchmarks pr bfs \
--trials 2This downloads 3 tiny graphs (< 10 MB each), builds C++ binaries, runs 2 benchmarks × 2 trials, and verifies the pipeline end-to-end.
python3 scripts/graphbrew_experiment.py --target-graphs 50 --size smallDownloads up to 50 small graphs (10 K – 500 K edges), runs all 7 phases
including cache simulation and LOGO evaluation. Produces
results/data/evaluation_summary.json with ML accuracy metrics.
python scripts/experiments/vldb_experiments_small.py --allLightweight version of all 8 experiments using 5 representative graphs, 1 trial, 2 benchmarks. Good for verifying experiment scripts work before a multi-hour run.
python scripts/experiments/vldb_experiments.py --all --size largeAll 8 experiments on the LARGE corpus (~37 graphs, ~25 GB download). Expect 6–12 hours depending on hardware. First run downloads graphs; subsequent runs reuse cached data.
The pipeline is interrupt-safe:
-
benchmarks.jsonis append-only with per-(graph, algorithm, benchmark) deduplication. If interrupted, re-running the same command skips completed entries. -
.lomapping files persist inresults/mappings/. Already-generated mappings are reused. -
.sgfiles persist inresults/graphs/. Already-downloaded graphs are not re-downloaded. - Atomic saves: JSON files are written via temp-file + rename to prevent corruption on crash.
Simply re-run the same command after an interruption.
results/
├── data/
│ ├── benchmarks.json # All benchmark results (append-only)
│ ├── graph_properties.json # Per-graph feature vectors
│ ├── evaluation_summary.json # LOGO CV metrics
│ └── adaptive_models.json # Unified model store
├── graphs/
│ ├── email-Enron/
│ │ ├── email-Enron.mtx # Original Matrix Market file
│ │ └── email-Enron.sg # Serialized graph (RANDOM baseline)
│ └── ...
├── mappings/
│ ├── email-Enron/
│ │ ├── SORT.lo # Sort mapping (vertex permutation)
│ │ ├── SORT.time # Sort reorder wall-clock time
│ │ ├── RABBITORDER_csr.lo # RabbitOrder CSR variant mapping
│ │ ├── GraphBrewOrder_leiden.lo
│ │ └── ...
│ └── ...
├── models/
│ └── perceptron/
│ ├── type_0/
│ │ ├── weights.json # Generic perceptron weights
│ │ ├── pr.json # PR-specialized weights
│ │ └── ...
│ └── registry.json # Type cluster centroids
├── logs/
│ └── run_<timestamp>/ # Per-run logs
└── vldb_experiments/ # Per-experiment output (Exp 1–8)
├── exp1_oracle_gap/
├── exp2_adaptive/
├── exp3_logo_cv/
├── exp4_feature_ablation/
├── exp5_cold_start/
├── exp6_cache/
├── exp7_convergence/
└── exp8_scalability/
Each entry represents one (graph, algorithm, benchmark) measurement:
{
"graph": "email-Enron",
"algorithm": "GraphBrewOrder_leiden",
"algorithm_id": 12,
"benchmark": "pr",
"avg_time": 0.0342,
"reorder_time": 0.085,
"trials": [0.0351, 0.0338, 0.0337],
"nodes": 36692,
"edges": 367662,
"timestamp": "2026-03-04T10:15:00"
}Deduplication: If the same (graph, algorithm, benchmark) tuple already
exists, the entry with the faster avg_time wins (best-time-wins policy).
Per-graph feature vectors:
{
"email-Enron": {
"nodes": 36692,
"edges": 367662,
"modularity": 0.573,
"degree_variance": 3.21,
"hub_concentration": 0.38,
"avg_degree": 10.02,
"clustering_coefficient": 0.497,
"avg_path_length": 4.03,
"diameter": 11,
"community_count": 234,
"packing_factor": 0.12,
"forward_edge_fraction": 0.51,
"working_set_ratio": 0.8
}
}LOGO CV results per model × criterion:
| Field | Meaning |
|---|---|
top1_accuracy |
Fraction of graphs where predicted best = actual best |
top3_accuracy |
Fraction where actual best is in top 3 predictions |
mean_regret |
Average % slowdown vs oracle across all graphs |
median_regret |
Median % slowdown (less sensitive to outliers) |
p95_regret |
95th percentile slowdown (tail risk) |
within_5pct |
Fraction of graphs ≤ 5% slower than oracle |
Criteria evaluated:
-
FASTEST_REORDER— minimize reorder time -
FASTEST_EXECUTION— minimize kernel execution time -
BEST_ENDTOEND— minimize (reorder + execution) -
BEST_AMORTIZATION— minimize iterations to amortize reorder cost
| Verdict | Meaning | |
|---|---|---|
| INSTANT | < 1 | Reorder cost negligible |
| FAST | 1–10 | Pays off within 10 kernel runs |
| OK | 10–100 | Worth it for repeated analytics workloads |
| SLOW | > 100 | Only viable for many iterations |
| NEVER | ∞ | Kernel is slower after reordering — never pays off |
| Speedup Range | Interpretation |
|---|---|
| 1.0–1.2× | Marginal — within noise for < 5 trials |
| 1.2–2.0× | Solid improvement, reliable with 3+ trials |
| 2.0–5.0× | Typical for well-matched reorderings (e.g., Leiden on social graphs) |
| 5.0–10× | Exceptional — verify with --graph-list <name> --trials 10
|
| > 10× | Suspicious — re-run with 10+ trials to confirm |
Trial count guidelines:
| Trials | Sufficient For |
|---|---|
| 2 | Crash detection only |
| 3 | Trend detection |
| 5 | Trustworthy geometric means |
| 10+ | Confirming or debunking extreme speedups |
The same algorithm ID can produce different orderings depending on its variant (sub-strategy). Variants are the SSOT for "which sub-configuration of an algorithm do we train/benchmark?"
Some algorithms have multiple internal strategies that produce different output orderings:
-
RabbitOrder can build its hierarchy from a CSR scan (
csr) or via Boost's community detection (boost). - GraphBrewOrder is a multi-layer pipeline — varying presets (leiden, rabbit, hubcluster) and ordering strategies (hrab, tqr, hcache, streaming) changes the final vertex permutation.
- GoGraphOrder has three FEF optimization algorithms (default, fast, naive).
Defined in scripts/lib/core/utils.py → _VARIANT_ALGO_REGISTRY:
| Algo ID | Name | Variants | Default | Why Different |
|---|---|---|---|---|
| 8 | RabbitOrder |
csr, boost
|
csr |
Different hierarchy construction |
| 11 | RCM |
default, bnf
|
default |
Different starting vertex heuristic |
| 12 | GraphBrewOrder |
leiden, rabbit, hubcluster, hrab, tqr, hcache, streaming
|
leiden |
Different community + ordering strategies |
| 16 | GoGraphOrder |
default, fast, naive
|
default |
Different FEF optimization algorithms |
Not in registry: GOrder (9) has variants (default, csr, fast) but
they produce equivalent orderings (same output, different speed) — only
reorder time differs, not quality. So they share a single set of weights.
| Variant | Strategy | Best For |
|---|---|---|
leiden |
Leiden partition + per-community reorder | General-purpose default |
rabbit |
RabbitOrder-based community hierarchy | Fast social networks |
hubcluster |
Hub-aware clustering | Hub-dominated graphs |
hrab |
Hub-Rabbit hybrid with Gorder refinement | Best cache locality overall |
tqr |
Cache-line-aligned tiling | Regular/mesh topologies |
hcache |
Hierarchical cache-aware partitioning | Deep cache hierarchies |
streaming |
Single-pass streaming aggregation | Fast, low-memory |
When --all-variants is set (auto-enabled by --target-graphs), the pipeline
expands each varianted algorithm into all its sub-variants:
15 total configs when fully expanded:
0: ORIGINAL (baseline)
2: SORT (simple)
8: RABBITORDER_csr (community)
8: RABBITORDER_boost (community)
9: GORDER (cache-aware)
12: GraphBrewOrder_leiden (multi-layer)
12: GraphBrewOrder_rabbit
12: GraphBrewOrder_hubcluster
12: GraphBrewOrder_hrab
12: GraphBrewOrder_tqr
12: GraphBrewOrder_hcache
12: GraphBrewOrder_streaming
16: GOGRAPHORDER_default (FEF)
16: GOGRAPHORDER_fast
16: GOGRAPHORDER_naive
Two orderings can be composed — apply the first, then the second on the reordered graph:
| Chain | CLI Flags | Idea |
|---|---|---|
SORT+RABBITORDER_csr |
-o 2 -o 8:csr |
Degree-sort then community |
SORT+RABBITORDER_boost |
-o 2 -o 8:boost |
Degree-sort then Boost community |
HUBCLUSTERDBG+RABBITORDER_csr |
-o 7 -o 8:csr |
Hub clustering then community |
SORT+GraphBrewOrder_leiden |
-o 2 -o 12:leiden:flat |
Degree-sort then Leiden pipeline |
DBG+GraphBrewOrder_leiden |
-o 5 -o 12:leiden:flat |
DBG then Leiden pipeline |
# Dry-run (preview only, no execution)
python3 scripts/graphbrew_experiment.py --target-graphs 150 --size small --dry-run
# Small training run
python3 scripts/graphbrew_experiment.py --target-graphs 50 --size small
# Full training with all sizes
python3 scripts/graphbrew_experiment.py --target-graphs 150 --size all
# VLDB preview (all 8 experiments, lightweight)
python scripts/experiments/vldb_experiments_small.py --all
# VLDB full suite
python scripts/experiments/vldb_experiments.py --all --size large
# Evaluate ML models (LOGO CV)
python scripts/evaluate_all_modes.py --all --json
# Feature ablation (Experiment 4)
ADAPTIVE_ZERO_FEATURES=packing python scripts/experiments/vldb_experiments.py --exp 4
# Manual single benchmark
./bench/bin/pr -f results/graphs/email-Enron/email-Enron.sg -s -o 14 -n 3See also: AdaptiveOrder-ML, Running-Benchmarks, Command-Line-Reference