Summary
Sibling of #1993 (polars hop() de-dups its output node table like pandas). The polars chain path still returns a duplicated node row for the unnamed, untyped single-hop shape; every other shape — named steps, a typed edge, hops=2, undirected, hop() itself — collapses the duplicate, as pandas and cuDF do on every shape.
Repro
import pandas as pd, polars as pl, graphistry
from graphistry.compute.ast import n, e_forward
nodes = pd.DataFrame({"key": [1, 2, 3, 4, 5], "id": [10, 20, 30, 40, 50]})
nodes = pd.concat([nodes, nodes.iloc[[0]]], ignore_index=True) # key 1 twice
edges = pd.DataFrame({"s": [1, 1, 2, 3, 3, 4], "d": [2, 3, 3, 1, 1, 5], "eid": range(6)})
g = graphistry.nodes(pl.from_pandas(nodes), "key").edges(pl.from_pandas(edges), "s", "d", "eid")
g.gfql([n({"key": 1}), e_forward(), n()], engine="polars")._nodes["key"].to_list() # [1, 1, 2, 3]
g.gfql([n({"key": 1}, name="a"), e_forward(name="e"), n(name="b")], engine="polars")._nodes["key"].to_list() # [1, 2, 3]
g.gfql([n({"key": 1}), e_forward({"type": "KNOWS"}), n()], engine="polars") # [1, 2, 3] with a typed edge column
pandas gives [1, 2, 3] for all three. Same with index_policy="off" and with the seeded polars lane and the chain fast path forced to decline, so it is the general _chain_traversal_polars route for the simple single-hop shape.
Found by the sibling-specialization sweep run after #2046 (plans/gfql-benchmark-numbers/spec-sweep/).
Expected
The polars chain collapses duplicate node rows on every shape, matching pandas' combine (the contract test_fast_path_dedups_duplicate_node_ids_on_hop states for pandas/cuDF).
Pins
A strict-xfail pin lives in graphistry/tests/compute/gfql/lazy/engine/polars/ next to the #2039 pins and flips when this is fixed.
Summary
Sibling of #1993 (polars
hop()de-dups its output node table like pandas). The polars chain path still returns a duplicated node row for the unnamed, untyped single-hop shape; every other shape — named steps, a typed edge,hops=2, undirected,hop()itself — collapses the duplicate, as pandas and cuDF do on every shape.Repro
pandas gives
[1, 2, 3]for all three. Same withindex_policy="off"and with the seeded polars lane and the chain fast path forced to decline, so it is the general_chain_traversal_polarsroute for the simple single-hop shape.Found by the sibling-specialization sweep run after #2046 (
plans/gfql-benchmark-numbers/spec-sweep/).Expected
The polars chain collapses duplicate node rows on every shape, matching pandas' combine (the contract
test_fast_path_dedups_duplicate_node_ids_on_hopstates for pandas/cuDF).Pins
A strict-xfail pin lives in
graphistry/tests/compute/gfql/lazy/engine/polars/next to the #2039 pins and flips when this is fixed.