Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
8b70f6a
feat: scaffold cudf executor skeleton
lmeyerov Nov 19, 2025
d94ebc2
feat: wire same-path plan into cudf executor
lmeyerov Nov 19, 2025
f51a645
feat: add gfql where metadata and planner
lmeyerov Nov 19, 2025
3df9157
feat: implement cudf executor forward pass
lmeyerov Nov 19, 2025
3935227
test: add cudf forward parity cases
lmeyerov Nov 19, 2025
1ea8e58
docs: copy issue 837 plan into impl folder
lmeyerov Nov 19, 2025
d429803
chore: remove tracked cudf executor plan
lmeyerov Nov 20, 2025
afcd35a
feat: add oracle fallback for cudf same-path executor
lmeyerov Nov 20, 2025
7197a43
chore: gate cudf same-path executor and add strict-mode test
lmeyerov Nov 20, 2025
604337b
chore: document cuDF same-path fallback gating
lmeyerov Nov 20, 2025
3361c57
feat: add same-path pruning for cudf executor
lmeyerov Nov 20, 2025
9e80984
feat: route cudf chains with WHERE to same-path executor
lmeyerov Nov 20, 2025
9d2bafe
feat: enforce same-path summaries in cudf executor
lmeyerov Nov 20, 2025
4f3b191
fix(gfql): preserve edge filters in cudf same-path
lmeyerov Nov 22, 2025
fc8e72b
chore(gfql): fix same-path typing and mypy config
lmeyerov Nov 22, 2025
1499503
chore(gfql): clean chain typing imports
lmeyerov Nov 22, 2025
b277955
chore(gfql): silence dtype comparisons for mypy 3.8
lmeyerov Nov 22, 2025
880c173
test(gfql): cover same-path cycles, branches, edge filters, cudf
lmeyerov Nov 23, 2025
ef25a42
test(gfql): compress same-path topology coverage
lmeyerov Nov 23, 2025
157c580
chore(gfql): tighten inequality mask
lmeyerov Nov 23, 2025
2a169d8
test(gfql): add dispatch same-path dict case
lmeyerov Nov 23, 2025
6afa4df
test(gfql): add chain/list dispatch same-path parity
lmeyerov Nov 23, 2025
fffd5e6
fix(gfql): import same_path_types from gfql
lmeyerov Dec 24, 2025
9605165
fix(gfql): add package init and clean mypy config
lmeyerov Dec 24, 2025
ef3c224
fix(gfql): add ref package init
lmeyerov Dec 24, 2025
e6899d2
fix: align same-path hop slicing with oracle
lmeyerov Dec 24, 2025
40bd1dd
test(gfql): add 8 feature composition tests for hop ranges + WHERE
lmeyerov Dec 26, 2025
17febff
fix(gfql): support WHERE clauses for multi-hop edges in same-path exe…
lmeyerov Dec 26, 2025
06629c0
refactor(gfql): rename CuDFSamePathExecutor to DFSamePathExecutor
lmeyerov Dec 26, 2025
ea76c29
fix(gfql): comprehensive WHERE + multi-hop bug fixes and test amplifi…
lmeyerov Dec 27, 2025
ed0ef22
refactor(gfql): vectorize df_executor for GPU compatibility
lmeyerov Dec 28, 2025
f601e84
test(gfql): add df_executor profiling script
lmeyerov Dec 28, 2025
e4bfbf0
test(gfql): add cProfile analysis and extended profiling
lmeyerov Dec 28, 2025
adfdbf6
fix(gfql): multiple bug fixes for native vectorized path
lmeyerov Dec 28, 2025
cd54d06
fix(gfql): resolve flake8 lint errors (F841, W504)
lmeyerov Dec 28, 2025
cd5b5a1
docs(plan): add Session 9 summary for CI fixes and verification update
lmeyerov Dec 28, 2025
b8b4b16
chore: remove plan.md from repo
lmeyerov Dec 28, 2025
a31f9bd
fix(gfql): resolve mypy type errors
lmeyerov Dec 28, 2025
687d8a2
fix(gfql): correct mypy ignore codes for iterrows
lmeyerov Dec 28, 2025
6af4398
fix(gfql): use pd.Index for column assignment to satisfy py38 mypy
lmeyerov Dec 28, 2025
d62b563
fix(executor): keep all edges in valid multi-hop paths, not just term…
lmeyerov Dec 29, 2025
66ea298
test(executor): add predicate type tests with data type coverage
lmeyerov Dec 29, 2025
09a840f
fix(hop): use edge endpoints for min_hops goal nodes, not lossy node …
lmeyerov Dec 30, 2025
2d8c665
test(executor): add TestMultiplePathLengths + fix oracle min_hops bug
lmeyerov Dec 30, 2025
c20a508
test(executor): add Yannakakis principle and hop labeling tests
lmeyerov Dec 30, 2025
1e6ff46
test(executor): add dual-engine testing (pandas + cudf)
lmeyerov Dec 30, 2025
78dd240
fix(gfql): handle undirected edges in WHERE clause filtering
lmeyerov Dec 31, 2025
94048d3
feat(gfql): oracle supports source/destination_node_match filters
lmeyerov Dec 31, 2025
2364e04
refactor(gfql): clean up df_executor comments and add dimension cover…
lmeyerov Jan 1, 2026
3be6d16
refactor(tests): split df_executor tests into 4 focused modules
lmeyerov Jan 2, 2026
bf565a1
fix(gfql): use safe_concat instead of non-existent compute.concat
lmeyerov Jan 2, 2026
749f5fa
fix(tests): inline helper functions to fix import errors in CI
lmeyerov Jan 2, 2026
f628564
fix(enumerator): correct hop labeling for paths outside min_hops range
lmeyerov Jan 2, 2026
c344c2c
test(enumerator): add regression test for hop label shortest path bug
lmeyerov Jan 2, 2026
567701e
test(enumerator): add edge and reverse hop label regression tests
lmeyerov Jan 2, 2026
9fef636
chore: add /plan.md to .gitignore and remove from PR
lmeyerov Jan 2, 2026
8fa6fe4
test(TDD): add failing tests for pandas Yannakakis entrypoint
lmeyerov Jan 2, 2026
ffbd68d
fix(executor): route pandas+WHERE to Yannakakis, use _run_native for all
lmeyerov Jan 2, 2026
d211996
refactor(tests): extract shared helpers to conftest.py
lmeyerov Jan 2, 2026
acdd53a
refactor: move same_path_*.py to graphistry/compute/gfql/
lmeyerov Jan 2, 2026
5f0f370
perf(hop): avoid GPU->CPU transfers in backtracking
lmeyerov Jan 2, 2026
aa57152
fix(executor): oracle fallback for unfiltered start + multihop + WHERE
lmeyerov Jan 2, 2026
e8d98eb
Revert "fix(executor): oracle fallback for unfiltered start + multiho…
lmeyerov Jan 2, 2026
87b9152
refactor(executor): rename _run_oracle to _run_test_only_oracle
lmeyerov Jan 2, 2026
f985dbd
fix(executor): handle unfiltered start + multihop in native path
lmeyerov Jan 2, 2026
4009160
test(executor): amplify coverage for unfiltered start + direction var…
lmeyerov Jan 2, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ docs/source/demos
# Legacy - kept for backward compatibility
AI_PROGRESS/
/PLAN.md
/plan.md
plans/
tmp/
test_env/
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- **Docs / hop**: Added bounded-hop walkthrough notebook (`docs/source/gfql/hop_bounds.ipynb`), cheatsheet and GFQL spec updates, and examples showing how to combine hop ranges, labels, and output slicing.
- **GFQL / reference**: Extended the pandas reference enumerator and parity tests to cover hop ranges, labeling, and slicing so GFQL correctness checks include the new traversal shapes.
- **Docs / GFQL**: Documented the external `tck-gfql` conformance harness and local run instructions in GFQL docs.
- **GFQL / Oracle**: Introduced `graphistry.gfql.ref.enumerator`, a pandas-only reference implementation that enumerates fixed-length chains, enforces local + same-path predicates, applies strict null semantics, enforces safety caps, and emits alias tags/optional path bindings for use as a correctness oracle.
- **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. Oracle path retains safety caps and alias-tag propagation.
- **GFQL / cuDF executor**: Implemented same-path pruning path (wavefront backward filtering, min/max summaries for inequalities, value-aware equality filters) with oracle fallback. CUDF chains with WHERE now dispatch through the same-path executor.

### Fixed
- **Compute / hop**: Exact-hop traversals now prune branches that do not reach `min_hops`, avoid reapplying min-hop pruning in reverse passes, keep seeds in wavefront outputs, and reuse forward wavefronts when recomputing labels so edge/node hop labels stay aligned (fixes 3-hop branch inclusion issues and mislabeled slices).

### Tests
- **GFQL / hop**: Expanded `test_compute_hops.py` and GFQL parity suites to assert branch pruning, bounded outputs, label collision handling, and forward/reverse slice behavior.
- **Reference enumerator**: Added oracle parity tests for hop ranges and output slices to guard GFQL integrations.
- **GFQL**: Added deterministic + property-based oracle tests (triangles, alias reuse, cuDF conversions, Hypothesis) plus parity checks ensuring pandas GFQL chains match the oracle outputs.
- **GFQL / cuDF same-path**: Added strict/auto mode coverage for cuDF executor fallback behavior to keep CI stable while GPU kernels are wired up.
- **GFQL / cuDF same-path**: Added GPU-path parity tests (equality/inequality) over CPU data to guard semantics while GPU CI remains unavailable.
- **Layouts**: Added comprehensive test coverage for `circle_layout()` and `group_in_a_box_layout()` with partition support (CPU/GPU)

### Infra
- **Tooling**: `bin/flake8.sh` / `bin/mypy.sh` now require installed tools (no auto-install), honor `FLAKE8_CMD` / `MYPY_CMD` and optional `MYPY_EXTRA_ARGS`; `bin/lint.sh` / `bin/typecheck.sh` resolve via uvx → python -m → bare.
Expand Down Expand Up @@ -109,6 +116,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Tests
- **CI / Python**: Expand GitHub Actions coverage to Python 3.13 + 3.13/3.14 for CPU lint/type/test jobs, while pinning RAPIDS-dependent CPU/GPU suites to <=3.13 until NVIDIA publishes 3.14 wheels (ensures lint/mypy/pytest signal on the latest interpreter without breaking RAPIDS installs).
- **GFQL**: Added deterministic + property-based oracle tests (triangles, alias reuse, cuDF conversions, Hypothesis) plus parity checks ensuring pandas GFQL chains match the oracle outputs.
- **GFQL / cuDF same-path**: Added strict/auto mode coverage for cuDF executor fallback behavior to keep CI stable while GPU kernels are wired up.
- **GFQL / cuDF same-path**: Added GPU-path parity tests (equality/inequality) over CPU data to guard semantics while GPU CI remains unavailable.
- **Layouts**: Added comprehensive test coverage for `circle_layout()` and `group_in_a_box_layout()` with partition support (CPU/GPU)

### Infra
Expand Down
30 changes: 26 additions & 4 deletions graphistry/compute/chain.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
import pandas as pd
from typing import Dict, Union, cast, List, Tuple, Optional, TYPE_CHECKING
from typing import Dict, Union, cast, List, Tuple, Sequence, Optional, TYPE_CHECKING
from graphistry.Engine import Engine, EngineAbstract, df_concat, df_to_engine, resolve_engine

from graphistry.Plottable import Plottable
Expand All @@ -12,6 +12,11 @@
from .typing import DataFrameT
from .util import generate_safe_column_name
from graphistry.compute.validate.validate_schema import validate_chain_schema
from graphistry.compute.gfql.same_path_types import (
WhereComparison,
parse_where_json,
where_to_json,
)
from .gfql.policy import PolicyContext, PolicyException
from .gfql.policy.stats import extract_graph_stats

Expand All @@ -26,8 +31,14 @@

class Chain(ASTSerializable):

def __init__(self, chain: List[ASTObject], validate: bool = True) -> None:
def __init__(
self,
chain: List[ASTObject],
where: Optional[Sequence[WhereComparison]] = None,
validate: bool = True,
) -> None:
self.chain = chain
self.where = list(where or [])
if validate:
# Fail fast on invalid chains; matches documented automatic validation behavior
self.validate(collect_all=False)
Expand Down Expand Up @@ -120,7 +131,15 @@ def from_json(cls, d: Dict[str, JSONVal], validate: bool = True) -> 'Chain':
f"Chain field must be a list, got {type(d['chain']).__name__}"
)

out = cls([ASTObject_from_json(op, validate=validate) for op in d['chain']], validate=validate)
where_raw = d.get('where')
where = parse_where_json(
cast(Optional[Sequence[Dict[str, Dict[str, str]]]], where_raw)
)
out = cls(
[ASTObject_from_json(op, validate=validate) for op in d['chain']],
where=where,
validate=validate,
)
return out

def to_json(self, validate=True) -> Dict[str, JSONVal]:
Expand All @@ -129,10 +148,13 @@ def to_json(self, validate=True) -> Dict[str, JSONVal]:
"""
if validate:
self.validate()
return {
data: Dict[str, JSONVal] = {
'type': self.__class__.__name__,
'chain': [op.to_json() for op in self.chain]
}
if self.where:
data['where'] = where_to_json(self.where)
return data

def validate_schema(self, g: Plottable, collect_all: bool = False) -> Optional[List['GFQLSchemaError']]:
"""Validate this chain against a graph's schema without executing.
Expand Down
Loading
Loading