Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
195 commits
Select commit Hold shift + click to select a range
c22e0f9
feat(gfql): add WHERE clause and df_executor (stacked PR)
lmeyerov Jan 9, 2026
5f1e9d9
fix(tests): skip oracle tests for multi-hop + WHERE limitations
lmeyerov Jan 9, 2026
d68496c
docs(changelog): add WHERE feature and bugfix entries for PR 886
lmeyerov Jan 9, 2026
9afda91
test(gfql): restore df_executor profiling scripts
lmeyerov Jan 9, 2026
0c9739c
fix(enumerator): restore source/destination_node_match filter support
lmeyerov Jan 9, 2026
528783b
fix(enumerator): restore full pre-split functionality and remove test…
lmeyerov Jan 9, 2026
472d672
docs(changelog): restore missing cuDF same-path and test entries
lmeyerov Jan 9, 2026
a0b00bb
docs(changelog): restore from_json where validation fix entry
lmeyerov Jan 9, 2026
2f69034
docs(changelog): move WHERE entries to Development section
lmeyerov Jan 9, 2026
17765cd
fix(df_executor): fix off-by-one in _bfs_reachability max_hops
lmeyerov Jan 10, 2026
b234063
test(gfql): add requires_gpu decorator for proper GPU test skipping
lmeyerov Jan 10, 2026
67b6aae
refactor(gfql): extract ChainMeta for O(1) chain lookups
lmeyerov Jan 10, 2026
3688ddc
refactor(gfql): extract EdgeSemantics for direction handling
lmeyerov Jan 10, 2026
7c121f8
refactor(gfql): extract df_utils for DataFrame operations
lmeyerov Jan 10, 2026
e7d0924
refactor(gfql): use EdgeSemantics in multihop methods, remove depreca…
lmeyerov Jan 10, 2026
bdcb667
refactor(gfql): use EdgeSemantics in _filter_edges_by_clauses
lmeyerov Jan 10, 2026
b4d594c
refactor(gfql): extract BFS functions to same_path/bfs.py
lmeyerov Jan 10, 2026
68315ac
refactor(gfql): remove redundant _is_single_hop, use EdgeSemantics.is…
lmeyerov Jan 10, 2026
c825918
refactor(gfql): extract post-prune methods to same_path/post_prune.py
lmeyerov Jan 10, 2026
4b64cc8
refactor(gfql): extract multihop methods to same_path/multihop.py
lmeyerov Jan 10, 2026
abb3a45
refactor(gfql): extract _re_propagate_backward to post_prune module
lmeyerov Jan 10, 2026
b1b63b9
refactor(gfql): extract WHERE edge filtering to same_path/where_filte…
lmeyerov Jan 10, 2026
9b9bbcf
refactor(gfql): delete dead code and unused optimizations
lmeyerov Jan 10, 2026
70275ca
fix(gfql): add forward WHERE pruning to df_executor
lmeyerov Jan 10, 2026
25b280f
refactor(gfql): remove unused imports from df_executor
lmeyerov Jan 10, 2026
d7218bc
refactor(gfql): unify NULL semantics in evaluate_clause()
lmeyerov Jan 10, 2026
99334ce
refactor(gfql): move re_propagate_backward to executor method
lmeyerov Jan 11, 2026
3018a40
fix(cudf): comprehensive cuDF compatibility fixes for GFQL executor
lmeyerov Jan 11, 2026
8db9f11
refactor(cudf): consolidate DataFrame construction helpers in df_utils
lmeyerov Jan 11, 2026
d8d40b1
fix(cudf): fix cuDF compatibility in chain backward pass and cross-en…
lmeyerov Jan 11, 2026
e5df51a
docs(changelog): add WHERE clause feature entries
lmeyerov Jan 11, 2026
2750990
fix(tests): cuDF compatibility for tolist() calls in chain optimizati…
lmeyerov Jan 11, 2026
841e329
fix(cudf): use module string checks for cross-engine coercion
lmeyerov Jan 11, 2026
62f5d28
refactor(gfql): remove dead SamePathPlan code (~80 LOC)
lmeyerov Jan 12, 2026
64b0e56
refactor(gfql): remove unused same_path/__init__.py (~35 LOC)
lmeyerov Jan 12, 2026
400a5bc
refactor(gfql): add immutable PathState type (Phase 1)
lmeyerov Jan 12, 2026
c1e42d7
refactor(gfql): _backward_prune tracks pruned edges separately (Phase…
lmeyerov Jan 12, 2026
dc3a85c
refactor(gfql): backward_propagate_constraints uses local state (Phas…
lmeyerov Jan 12, 2026
74fe617
refactor(gfql): post_prune.py uses local state copies (Phase 2c)
lmeyerov Jan 12, 2026
5d95f13
refactor(gfql): add edges_df_for_step accessor (Phase 2d)
lmeyerov Jan 12, 2026
5a4f509
test(gfql): add PathState immutability unit tests (Phase 3)
lmeyerov Jan 12, 2026
bd47ba2
refactor(gfql): Phase 4 - convert to pure PathState API
lmeyerov Jan 12, 2026
2441e6c
refactor(gfql): Phase 5 - remove old _PathState class and update docs…
lmeyerov Jan 12, 2026
2aa801c
test(gfql): Phase 6 - add PathState immutability contract tests
lmeyerov Jan 12, 2026
c72bede
fix(cudf): use series_values helper instead of .tolist() in backward_…
lmeyerov Jan 12, 2026
2251716
chore: remove redundant comments from post_prune.py
lmeyerov Jan 12, 2026
bdfa72c
perf(gfql): replace Set with pd.Index for 7x faster ID operations
lmeyerov Jan 12, 2026
af81ab6
perf(chain): use .isin() instead of merge for endpoint filtering
lmeyerov Jan 12, 2026
41fccdc
revert: remove cuDF dtype coercion from safe_merge
lmeyerov Jan 12, 2026
607fa71
perf(hop): use .isin() instead of merge for wavefront->edges join (8x…
lmeyerov Jan 12, 2026
3001d54
refactor(hop): remove unused prepare_merge_dataframe function
lmeyerov Jan 12, 2026
8f32b95
perf(hop): precompute node predicate domains
lmeyerov Jan 12, 2026
251f83e
perf(hop): unify direction pairs; modest CPU gains
lmeyerov Jan 12, 2026
b6ec416
perf(hop): mask target/dest filters with isin
lmeyerov Jan 12, 2026
f201041
perf(hop): precompute target wavefront domains
lmeyerov Jan 12, 2026
75c9180
perf(hop): use merge for EDGE_ID joins
lmeyerov Jan 12, 2026
515ad7e
perf(df_executor): DF-native cuDF forward prune
lmeyerov Jan 12, 2026
1c80ef9
perf(hop): undirected single-pass expansion
lmeyerov Jan 12, 2026
e1c5347
perf(hop): domain-based fast path traversal
lmeyerov Jan 13, 2026
dc6125e
fix(hop): undirected single-pass frontier
lmeyerov Jan 13, 2026
073f9a4
fix(gfql): use domain helpers for same-path ids
lmeyerov Jan 16, 2026
6883f84
fix(docs): include gfql same_path package in build
lmeyerov Jan 16, 2026
174d600
fix(lint): clean unused imports and f-string
lmeyerov Jan 16, 2026
0a80346
fix(mypy): narrow optional frames in hop/gfql
lmeyerov Jan 16, 2026
79afdbf
fix(mypy): drop dataclass slots for py3.9
lmeyerov Jan 16, 2026
cb92e68
fix(mypy): avoid optional node cols in hop/bfs
lmeyerov Jan 16, 2026
c82f901
Fix hop pair typing without asserts
lmeyerov Jan 16, 2026
519bc40
Re-export col/compare in reference enumerator
lmeyerov Jan 16, 2026
9cd16e7
Expose col/compare without flake8 shadowing
lmeyerov Jan 17, 2026
a71213c
DRY hop edge expansion helpers
lmeyerov Jan 17, 2026
c3e95a4
Avoid re-deduping matches in hop
lmeyerov Jan 17, 2026
acf3568
Revert hop undirected fast path and match anti-join
lmeyerov Jan 17, 2026
8b30023
Add tracked benchmark scripts and docs
lmeyerov Jan 17, 2026
5dabfd0
Expand real-data benchmark coverage
lmeyerov Jan 17, 2026
fada9ea
Add benchmark results log
lmeyerov Jan 17, 2026
7f581dd
Add real-data WHERE benchmark scenarios
lmeyerov Jan 17, 2026
c4d4290
Log real-data WHERE benchmark run
lmeyerov Jan 17, 2026
984442d
Add scores to real-data benchmark output
lmeyerov Jan 17, 2026
3876abf
Log real-data benchmark scores
lmeyerov Jan 17, 2026
1e38bbd
Log redteam benchmark rerun
lmeyerov Jan 17, 2026
4c9e908
Add redteam categorical benchmark option
lmeyerov Jan 17, 2026
d3af7d1
Add optional df_executor OTel spans
lmeyerov Jan 18, 2026
c74bb9c
Add OTel detail stats for df_executor
lmeyerov Jan 18, 2026
a64ddda
Add non-adjacent OTel detail stats
lmeyerov Jan 18, 2026
7330896
benchmarks: add optional otel setup
lmeyerov Jan 18, 2026
ed0bdfe
otel: core helper, spans, trace headers
lmeyerov Jan 18, 2026
2b1ba36
tests: assert traceparent headers
lmeyerov Jan 18, 2026
d757293
tests: behavior-level trace headers
lmeyerov Jan 18, 2026
7aff2cc
benchmarks: log fast-path A/B; hop: clarify toggle
lmeyerov Jan 19, 2026
a6f12ce
experiments: add non-adjacent WHERE modes
lmeyerov Jan 19, 2026
8aac3b8
experiments: add non-adj ordering/bounds
lmeyerov Jan 19, 2026
1e65099
benchmarks: log non-adj experiment
lmeyerov Jan 19, 2026
eb31425
gfql: limit value-mode to equality; log phase-18 runs
lmeyerov Jan 19, 2026
cf99bc8
fix(gfql): honor node-id WHERE in adjacent filters
lmeyerov Jan 20, 2026
2788bc0
bench: log phase-19 where opt results
lmeyerov Jan 21, 2026
e5eebf4
bench: add low-card nonadj stress cases
lmeyerov Jan 21, 2026
7dd85db
bench: log low-card nonadj stress results
lmeyerov Jan 21, 2026
8e5076a
bench: add realdata where stress cases and timeouts
lmeyerov Jan 21, 2026
4c31419
bench: log realdata timeout stress results
lmeyerov Jan 21, 2026
8b8e520
fix(gfql): null-safe where + singleton prefilter
lmeyerov Jan 21, 2026
d808476
bench: log phase-22 timeout results
lmeyerov Jan 21, 2026
7686293
feat(gfql): allow value-mode on selected ops
lmeyerov Jan 21, 2026
f825bba
docs(bench): log phase-23 value-mode ops results
lmeyerov Jan 21, 2026
13c29ee
docs(bench): log phase-24 realdata baseline
lmeyerov Jan 21, 2026
f0cee3b
feat(gfql): dynamic non-adj clause ordering
lmeyerov Jan 21, 2026
a28942f
docs(bench): log phase-25 ordering results
lmeyerov Jan 21, 2026
112447e
revert(gfql): drop dynamic non-adj ordering
lmeyerov Jan 22, 2026
eca3028
feat(gfql): group non-adj clauses by endpoints
lmeyerov Jan 22, 2026
3b71dd8
docs(bench): log phase-26 grouping results
lmeyerov Jan 22, 2026
90dc129
feat(gfql): add pair-gated non-adj clause option
lmeyerov Jan 22, 2026
f917ac2
docs(bench): log phase 27 pair-gate results
lmeyerov Jan 22, 2026
25ae226
Revert "feat(gfql): add pair-gated non-adj clause option"
lmeyerov Jan 22, 2026
5169804
feat(gfql): prefilter multi-eq non-adj clauses
lmeyerov Jan 22, 2026
9289fd8
docs(bench): log phase 28 multi-eq prefilter results
lmeyerov Jan 22, 2026
b80e329
Revert "feat(gfql): prefilter multi-eq non-adj clauses"
lmeyerov Jan 22, 2026
38fc2b8
feat(gfql): composite value-mode for multi-eq non-adj
lmeyerov Jan 22, 2026
30a0acf
docs(bench): log phase 29 composite value-mode
lmeyerov Jan 22, 2026
28ff887
feat(gfql): add capped vector non-adj strategy
lmeyerov Jan 22, 2026
d07c983
chore(bench): log phase 30 vector results
lmeyerov Jan 22, 2026
9035c60
feat(gfql): intersect vector clauses by adjacency
lmeyerov Jan 22, 2026
b0412c7
chore(bench): log phase 31 vector results
lmeyerov Jan 22, 2026
cf6790a
test(gfql): add vector parity coverage
lmeyerov Jan 22, 2026
9a0d06c
feat(gfql): gate vector paths on mid intersection
lmeyerov Jan 22, 2026
294e5ea
feat(gfql): add value-aware vector path join
lmeyerov Jan 22, 2026
5b16b21
chore(bench): log phase 33.1 vector results
lmeyerov Jan 22, 2026
d6ac7fa
Revert "feat(gfql): add value-aware vector path join"
lmeyerov Jan 22, 2026
aa05e39
checkpoint: auto mode + edge fast path benchmarks
lmeyerov Jan 24, 2026
8c9c259
benchmarks: add optional kuzu comparisons
lmeyerov Jan 24, 2026
4c1d47b
benchmarks: add graph/scenario filters
lmeyerov Jan 24, 2026
4f30a6e
benchmarks: handle kuzu db path variants
lmeyerov Jan 24, 2026
7ab8652
benchmarks: add WHERE opt matrix runner
lmeyerov Jan 24, 2026
620d9a1
benchmarks: seed support + multi-eq semijoin flag
lmeyerov Jan 25, 2026
55454b4
feat(gfql): default non-adj WHERE auto mode
lmeyerov Jan 25, 2026
7393994
bench: add timeout repro harness
lmeyerov Jan 25, 2026
cdca910
feat(gfql): guard auto value mode on multi-clause
lmeyerov Jan 25, 2026
def5ad2
feat(gfql): add opt-in inequality aggregation
lmeyerov Jan 25, 2026
32fe264
feat(gfql): gate ineq aggregation by label
lmeyerov Jan 25, 2026
2f1d51f
feat(gfql): gate ineq aggregation on label eq
lmeyerov Jan 25, 2026
2e40f30
perf(gfql): avoid semijoin pair build when inactive
lmeyerov Jan 25, 2026
4d4e9ba
chore(gfql): add otel size counters
lmeyerov Jan 25, 2026
bea8067
fix(gfql): init vector guard domains
lmeyerov Jan 25, 2026
762d37c
perf(gfql): reduce semijoin dedup overhead
lmeyerov Jan 25, 2026
c483a6c
perf(gfql): cache edge pairs for semijoins
lmeyerov Jan 25, 2026
91baa3d
docs(changelog): note WHERE perf + otel updates
lmeyerov Jan 25, 2026
865d9f4
style: fix flake8 spacing
lmeyerov Jan 25, 2026
7acf5de
chore: tidy hop/df_executor imports
lmeyerov Jan 25, 2026
026295f
chore: tighten gfql typing
lmeyerov Jan 25, 2026
2411334
chore: reuse cudf checks
lmeyerov Jan 25, 2026
d29e074
chore: simplify gfql where parsing
lmeyerov Jan 25, 2026
d9254c1
chore: drop stale hop TODOs
lmeyerov Jan 25, 2026
f8f56c2
chore: tighten domain helpers
lmeyerov Jan 25, 2026
889c0a0
style: fix test_str spacing
lmeyerov Jan 25, 2026
e5f96ad
chore: fix post_prune typing
lmeyerov Jan 25, 2026
bde816c
benchmarks: add graph-benchmark q1-q9 harness
lmeyerov Jan 26, 2026
53343e6
benchmarks: fix interest edge filename
lmeyerov Jan 26, 2026
7e0d890
benchmarks: log graph-benchmark q1-q9 baseline
lmeyerov Jan 26, 2026
fd112f4
benchmarks: add preindexed graph-benchmark mode
lmeyerov Jan 26, 2026
d4b9843
benchmarks: add presorted graph-benchmark mode
lmeyerov Jan 26, 2026
341f294
benchmarks: add preindex timing for graph-benchmark
lmeyerov Jan 26, 2026
d1ed642
benchmarks: log preindex timing results
lmeyerov Jan 26, 2026
59a7ffd
refactor: trim same_path slop
lmeyerov Jan 26, 2026
31a2f2d
test: trim df_executor core slop
lmeyerov Jan 26, 2026
f1c14e0
test: trim df_executor pattern slop
lmeyerov Jan 26, 2026
4cf89b3
test: trim df_executor dimension slop
lmeyerov Jan 26, 2026
f74924c
test: trim df_executor amplify slop
lmeyerov Jan 26, 2026
364bff8
test: trim path_state slop
lmeyerov Jan 26, 2026
35b2391
test: drop df_executor core docstrings
lmeyerov Jan 26, 2026
3065324
test: drop df_executor pattern docstrings
lmeyerov Jan 26, 2026
9c3fa05
refactor: drop df_executor docstrings
lmeyerov Jan 26, 2026
2b24622
refactor: drop same_path docstrings
lmeyerov Jan 26, 2026
872c89b
Trim gfql ref test slop
lmeyerov Jan 26, 2026
9a01918
Trim compute test docstrings
lmeyerov Jan 26, 2026
e5ddc90
Trim gfql_unified comments
lmeyerov Jan 26, 2026
dfbc36c
Trim remote helper comments
lmeyerov Jan 26, 2026
9d9e946
Trim chain/hop comment slop
lmeyerov Jan 27, 2026
2cb7ba1
Trim df_executor comments
lmeyerov Jan 27, 2026
d148f79
Trim where_filter comments
lmeyerov Jan 27, 2026
a5d7027
Trim df_utils/multihop comments
lmeyerov Jan 27, 2026
05f0463
Trim redundant ArrowFileUploader comment
lmeyerov Jan 27, 2026
0064361
Deduplicate edge semantics endpoint cols
lmeyerov Jan 27, 2026
aea0c44
Tighten same-path domain typing
lmeyerov Jan 27, 2026
6ac6a3a
Tighten PathState sync typing
lmeyerov Jan 27, 2026
2095de2
Tighten multihop domain typing
lmeyerov Jan 27, 2026
9d44df5
Type post-prune allowed_edges as DomainT
lmeyerov Jan 27, 2026
fb6e129
Remove unused multihop visited tracking
lmeyerov Jan 27, 2026
7c88702
Reduce post-prune duplication and fix typing
lmeyerov Jan 27, 2026
34fa13e
Simplify same-path pruning helpers
lmeyerov Jan 27, 2026
982b763
Compact post-prune tracing and helpers
lmeyerov Jan 27, 2026
2002828
Reduce post-prune and where-filter duplication
lmeyerov Jan 27, 2026
12a6249
Collapse post-prune pruning patterns
lmeyerov Jan 27, 2026
e0895c8
Consolidate post-prune allowed-node updates
lmeyerov Jan 27, 2026
ecaefc6
Refine post-prune allowed updates
lmeyerov Jan 27, 2026
4c14280
Reduce post-prune inequality duplication
lmeyerov Jan 27, 2026
1aee0a3
Reduce post_prune duplication
lmeyerov Jan 27, 2026
66337e0
Reduce post_prune duplication further
lmeyerov Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,38 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Development]
<!-- Do Not Erase This Section - Used for tracking unreleased changes -->

### Added
- **GFQL / WHERE** (experimental): Added `Chain.where` field for same-path WHERE clause constraints. New modules: `same_path_types.py`, `same_path_plan.py`, `df_executor.py` implementing Yannakakis-style semijoin reduction for efficient WHERE filtering. Supports equality, inequality, and comparison operators on named alias columns.
- **GFQL / cuDF same-path**: Added execution-mode gate `GRAPHISTRY_CUDF_SAME_PATH_MODE` (auto/oracle/strict) for GFQL cuDF same-path executor. Auto falls back to oracle when GPU unavailable; strict requires cuDF or raises.
- **Compute / hop**: Added `GRAPHISTRY_HOP_FAST_PATH` (set to `0`/`false`/`off`) to disable fast-path traversal for benchmarking or compatibility checks.
- **GFQL / WHERE**: Added opt-in `GRAPHISTRY_NON_ADJ_WHERE_MULTI_EQ_SEMIJOIN` for multi-equality semijoin pruning (2-hop, experimental).
- **GFQL / WHERE**: Added opt-in `GRAPHISTRY_NON_ADJ_WHERE_INEQ_AGG` for aggregated inequality pruning on 2-hop non-adj clauses (experimental).

### Performance
- **Compute / hop**: Refactored hop traversal to precompute node predicate domains and unify direction handling; synthetic CPU benchmarks show modest median improvements with some regressions on undirected/range scenarios.
- **GFQL / WHERE**: Use DF-native forward pruning for cuDF equality constraints to avoid host syncs (pandas path unchanged).
- **GFQL / WHERE**: Default non-adjacent WHERE mode now `auto`, enabling value-mode + domain semijoin auto, with edge semijoin auto for edge clauses (opt-out via env).
- **GFQL / WHERE**: Auto mode skips value-mode on multi-clause non-adjacent WHERE when pair estimates exceed the semijoin threshold (guardrail against blowups).
- **GFQL / WHERE**: Avoid building semijoin pair tables when AUTO semijoin stays inactive; uses cheap pair estimates to gate work.
- **GFQL / WHERE**: Reduce semijoin dedup overhead and reuse cached edge pairs per edge when `allowed_edges` is unset.
- **Compute / hop**: Undirected traversal skips oriented-pair expansion when no destination filters; modest CPU gains in undirected benchmarks.
- **Compute / hop**: Fast-path traversal uses domain-based visited/frontier tracking to avoid per-hop concat+dedupe overhead; modest CPU improvements in synthetic benchmarks.

### Fixed
- **GFQL / chain**: Fixed `from_json` to validate `where` field type before casting, preventing type errors on malformed input.
- **GFQL / WHERE**: Fixed undirected edge handling in WHERE clause filtering to check both src→dst and dst→src directions.
- **GFQL / WHERE**: Fixed multi-hop path edge retention to keep all edges in valid paths, not just terminal edges.
- **GFQL / WHERE**: Fixed unfiltered start node handling with multi-hop edges in native path executor.
- **GFQL / WHERE**: Fixed vector-strategy guard to initialize start/end domains before pair-est gating (prevents UnboundLocalError).

### Infra
- **GFQL / same_path**: Modular architecture for WHERE execution: `same_path_types.py` (types), `same_path_plan.py` (planning), `df_executor.py` (execution), plus `same_path/` submodules for BFS, edge semantics, multihop, post-pruning, and WHERE filtering.
- **Benchmarks**: Added manual hop microbench + frontier sweep scripts under `benchmarks/` (not wired into CI).
- **GFQL / WHERE**: Added OTel detail counters for semijoin pair sizes and mid-intersection sizes to help diagnose dense multi-clause blowups.

### Tests
- **GFQL / df_executor**: Added comprehensive test suite (core, amplify, patterns, dimension) with 200+ tests covering Yannakakis semijoin, WHERE clause filtering, multi-hop paths, and pandas/cuDF parity.
- **GFQL / cuDF same-path**: Added strict/auto mode coverage for cuDF executor fallback behavior.
- **Temporal**: Added datetime unit parity coverage (ms/us/ns) for ring layouts, GFQL time ring layouts, and temporal comparison predicates; relaxed honeypot hypergraph datetime unit expectations.

## [0.50.5 - 2026-01-25]
Expand Down
35 changes: 27 additions & 8 deletions ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,19 +184,38 @@ WITH_BUILD=0 WITH_TEST=0 ./test-cpu-local.sh

### GPU Testing - Fast (Reuse Base Image)

Docker containers include: **pytest, mypy, ruff** (preinstalled)
Docker containers include: **pytest, mypy, ruff, cudf** (preinstalled)

```bash
# Reuse existing graphistry image (no rebuild)
IMAGE="graphistry/graphistry-nvidia:${APP_BUILD_TAG:-latest}-${CUDA_SHORT_VERSION:-12.8}"

# Container with cuDF available (cudf 25.10)
IMAGE="graphistry/graphistry-nvidia:v2.50.0-13.0"

# Run compute + GFQL tests with cuDF fallback (491 tests)
# Uses CUDA_VISIBLE_DEVICES="" to avoid GPU driver issues
docker run --rm -v /home/lmeyerov/Work/pygraphistry:/app -w /app \
-e CUDA_VISIBLE_DEVICES="" \
$IMAGE \
python -m pytest graphistry/tests/test_compute*.py tests/gfql/ref/ -q \
--ignore=tests/gfql/ref/test_ref_enumerator.py \
-k "not cudf_gpu_path"

# Run GFQL ref tests only (372 tests)
docker run --rm -v /home/lmeyerov/Work/pygraphistry:/app -w /app \
-e CUDA_VISIBLE_DEVICES="" \
$IMAGE \
python -m pytest tests/gfql/ref/ -q \
--ignore=tests/gfql/ref/test_ref_enumerator.py

# With full GPU access (requires nvidia-container-toolkit)
docker run --rm --gpus all \
-v "$(pwd):/workspace:ro" \
-w /workspace -e PYTHONPATH=/workspace \
$IMAGE pytest graphistry/tests/test_file.py -v
-v /home/lmeyerov/Work/pygraphistry:/app -w /app \
$IMAGE python -m pytest graphistry/tests/compute/ -q
```

**Fast iteration**: Use this during development
**Note**: Tests in `graphistry/tests/compute/predicates/` require real GPU access.
Use `CUDA_VISIBLE_DEVICES=""` for cuDF import-path testing without GPU.

**Fast iteration**: Use cuDF container during development
**Full rebuild**: Use `./docker/test-gpu-local.sh` before merge

### Environment Control
Expand Down
234 changes: 234 additions & 0 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
# Benchmarks

Manual-only scripts for local performance checks. Not wired into CI.

Summary results go into `benchmarks/RESULTS.md` (raw outputs stay in `plans/`).

## Hop microbench

Run a small set of hop() scenarios across synthetic graphs.

```bash
uv run python benchmarks/run_hop_microbench.py --runs 5 --output /tmp/hop-microbench.md
```

## Frontier sweep

Sweep seed sizes on a fixed linear graph.

```bash
uv run python benchmarks/run_hop_frontier_sweep.py --runs 5 --nodes 100000 --edges 200000 --output /tmp/hop-frontier.md
```

Notes:
- Use `--engine cudf` for GPU runs when cuDF is available.
- Scripts print a table to stdout; `--output` writes Markdown results.

## Chain vs Yannakakis

Compare regular `chain()` against the Yannakakis same-path executor on synthetic graphs.

```bash
uv run python benchmarks/run_chain_vs_samepath.py --runs 7 --warmup 1 --output /tmp/chain-vs-samepath.md
```

By default, WHERE uses auto mode (value-mode + domain semijoin auto for non-adj clauses, edge semijoin auto for edge clauses).
To compare against baseline behavior, set `--non-adj-mode baseline`.
Use `--max-scenario-seconds 20` to fail fast on synthetic timeouts (best-effort).

To focus on dense multi-clause scenarios:

```bash
uv run python benchmarks/run_chain_vs_samepath.py \
--graph-filter medium_dense,large_dense \
--scenario-filter nonadj_multi \
--runs 5 --warmup 1
```

Use `--seed` to make synthetic graph generation repeatable across runs.

To toggle non-adjacent WHERE experiments on synthetic scenarios:

```bash
uv run python benchmarks/run_chain_vs_samepath.py \
--non-adj-mode value_prefilter \
--non-adj-value-card-max 500 \
--non-adj-order selectivity \
--non-adj-bounds \
--runs 7 --warmup 1
```

## Real-data GFQL

Run GFQL chain scenarios on demo datasets plus WHERE scenarios (df_executor), with separate sections and a per-section score.

```bash
uv run python benchmarks/run_realdata_benchmarks.py --runs 7 --warmup 1 --output /tmp/realdata-gfql.md
```

To force baseline WHERE behavior for comparisons:

```bash
uv run python benchmarks/run_realdata_benchmarks.py \
--non-adj-mode baseline \
--runs 7 --warmup 1 --output /tmp/realdata-baseline.md
```

To test categorical domains for redteam:

```bash
uv run python benchmarks/run_realdata_benchmarks.py --datasets redteam50k --redteam-domain-categorical --runs 9 --warmup 2
```

To experiment with non-adjacent WHERE modes:

```bash
uv run python benchmarks/run_realdata_benchmarks.py \
--datasets redteam50k \
--non-adj-mode value_prefilter \
--non-adj-value-card-max 500 \
--non-adj-order selectivity \
--non-adj-bounds \
--runs 7 --warmup 1
```

Auto mode (value for low NDV, domain semijoin for the rest):

```bash
GRAPHISTRY_NON_ADJ_WHERE_DOMAIN_SEMIJOIN_AUTO=1 \
uv run python benchmarks/run_realdata_benchmarks.py \
--datasets redteam50k,transactions \
--non-adj-mode auto \
--non-adj-value-ops "==,!=" \
--non-adj-value-card-max 10 \
--runs 3 --warmup 1 --opt-max-call-ms 0
```

To experiment with aggregated inequality pruning for 2-hop non-adj clauses:

```bash
GRAPHISTRY_NON_ADJ_WHERE_INEQ_AGG=1 \
uv run python benchmarks/run_realdata_benchmarks.py --datasets redteam50k --runs 3 --warmup 1
```

Auto mode defaults to `==,!=` with a value-cardinality cap of 300 when no explicit value ops/card max are provided.

To add NDV probe columns (high/low cardinality) and extra WHERE scenarios:

```bash
uv run python benchmarks/run_realdata_benchmarks.py \
--datasets redteam50k,transactions \
--ndv-probes --ndv-probe-buckets 3 --ndv-log \
--runs 3 --warmup 1
```

To enable OpenTelemetry spans for df_executor:

```bash
GRAPHISTRY_OTEL=1 \
GRAPHISTRY_OTEL_DETAIL=1 \
uv run --with opentelemetry-api --with opentelemetry-sdk \
python benchmarks/run_realdata_benchmarks.py --datasets redteam50k --runs 3 --warmup 1
```

To export spans to OTLP (optional):

```bash
GRAPHISTRY_OTEL=1 \
GRAPHISTRY_OTEL_EXPORTER=otlp \
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
uv run --with opentelemetry-api --with opentelemetry-sdk --with opentelemetry-exporter-otlp \
python benchmarks/run_realdata_benchmarks.py --datasets redteam50k --runs 3 --warmup 1
```

To limit datasets:

```bash
uv run python benchmarks/run_realdata_benchmarks.py --datasets redteam50k,transactions --runs 7 --warmup 1
```

To focus on a subset of scenarios:

```bash
uv run python benchmarks/run_realdata_benchmarks.py \
--datasets transactions,redteam50k \
--skip-chain --where-filter ndv_ \
--ndv-probes --ndv-probe-buckets 3 --ndv-log \
--runs 3 --warmup 1 --max-scenario-seconds 5 --opt-max-call-ms 0
```

Available datasets: `redteam50k`, `transactions`, `facebook_combined`, `honeypot`, `twitter_demo`, `lesmiserables`, `twitter_congress`, `all`.

## Optional Kuzu comparisons

If the `kuzu` Python package is installed, you can run optional Kuzu comparisons (currently redteam-only):

```bash
uv run python benchmarks/run_realdata_benchmarks.py \
--datasets redteam50k \
--kuzu --kuzu-db-root /tmp/kuzu_bench \
--runs 3 --warmup 1
```

Use `--kuzu-rebuild` to recreate the Kuzu database from CSVs when needed.

## Graph-benchmark q1-q9

Replay the q1-q9 queries from https://github.com/prrao87/graph-benchmark against Graphistry.
See `benchmarks/graph_benchmark.md` for setup details.

```bash
uv run python benchmarks/graph_benchmark_q1_q9.py \
--graph-benchmark-root /home/lmeyerov/Work/graph-benchmark \
--runs 5 --warmup 1 \
--output-json /tmp/graph-benchmark-q1-q9.json
```

Preindexed variant (relation/type split per query):

```bash
uv run python benchmarks/graph_benchmark_q1_q9.py \
--graph-benchmark-root /home/lmeyerov/Work/graph-benchmark \
--mode preindexed \
--runs 5 --warmup 1 \
--output-json /tmp/graph-benchmark-q1-q9-preindexed.json
```

Include preindex build time in per-query medians (adds `preindex_ms` and `median_ms_with_preindex`):

```bash
uv run python benchmarks/graph_benchmark_q1_q9.py \
--graph-benchmark-root /home/lmeyerov/Work/graph-benchmark \
--mode preindexed \
--include-preindex \
--runs 5 --warmup 1 \
--output-json /tmp/graph-benchmark-q1-q9-preindexed-with-preindex.json
```

Presorted variant (global sort by rel/src/dst and node_type/node_id):

```bash
uv run python benchmarks/graph_benchmark_q1_q9.py \
--graph-benchmark-root /home/lmeyerov/Work/graph-benchmark \
--mode presorted \
--runs 5 --warmup 1 \
--output-json /tmp/graph-benchmark-q1-q9-presorted.json
```

## WHERE opt matrix (comparative)

Run a focused matrix of WHERE scenarios across opt profiles (value mode, domain semijoin, auto, edge semijoin, etc).
Outputs are grouped by profile + scenario group, with defaults targeting dense multi-clause and real-data stress cases.

```bash
uv run python benchmarks/run_where_opt_matrix.py --runs 3 --warmup 1
```

To target only dense multi-clause synthetic cases:

```bash
uv run python benchmarks/run_where_opt_matrix.py \
--groups synthetic_multi_clause \
--profiles baseline,auto,vector \
--runs 5 --warmup 1
```
Loading
Loading