Skip to content

GFQL polars chain: undirected bounded varlen (-[:T*1..k]-) silently diverges from pandas — missing backtrack avoidance includes the seed #1741

Description

@lmeyerov

Summary

On master (c355660), the native polars chain executes undirected bounded variable-length hops (`-[:KNOWS*1..2]-`) natively but with wrong results: it includes nodes reachable only by immediately re-traversing the same undirected edge (seed bounce-back), which pandas (the parity oracle) correctly excludes via relationship-uniqueness (trail) semantics. This violates the parity-or-honest-NIE contract — the shape should either match pandas or decline.

Repro (master c355660, polars 1.42)

import polars as pl, graphistry
nodes = pl.DataFrame({"id": [f"p{i}" for i in range(6)], "label__Person": [True]*6})
edges = pl.DataFrame({"s": ["p0","p1","p2","p0","p3"], "d": ["p1","p2","p3","p4","p5"], "type": ["KNOWS"]*5})
g  = graphistry.nodes(nodes, "id").edges(edges, "s", "d")
gp = graphistry.nodes(nodes.to_pandas(), "id").edges(edges.to_pandas(), "s", "d")
q = "MATCH (p:Person {id: 'p0'})-[:KNOWS*1..2]-(f:Person) RETURN f.id AS fid ORDER BY fid"
print(gp.gfql(q, engine="pandas")._nodes.to_dict("records"))
# [{'fid': 'p1'}, {'fid': 'p2'}, {'fid': 'p4'}]
print(g.gfql(q, engine="polars")._nodes.to_pandas().to_dict("records"))
# [{'fid': 'p0'}, {'fid': 'p1'}, {'fid': 'p2'}, {'fid': 'p4'}]   <-- p0 = seed via edge backtrack

The path p0-[e]-p1-[same e]-p0 reuses one undirected edge, so p0 must not appear at *1..2 (pandas agrees; Cypher trail semantics).

Impact

  • LDBC IC6/IC11 shapes (`-[:KNOWS*1..2]-`) — the official texts currently decline later at the rows op, so benchmark numbers are honest NIE, but any user query of the bare shape returns silently wrong rows on engine="polars"/"polars-gpu".
  • The undirected multihop path is marked native in `_is_native_multihop` (lazy/engine/polars/chain.py); the forward re-exec recompute does not exclude same-edge backtracking for undirected traversal.

Fix directions

Either port pandas' backtrack-avoidance to the polars undirected multihop recompute, or narrow `_is_native_multihop` to decline undirected bounded varlen until ported (honest NIE). Differential fuzz over undirected varlen shapes should gate the port.

Found while probing IC6/IC11 coverage for the GFQL benchmark campaign (plans/gfql-benchmark-numbers/plan.md).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions