Skip to content

hop: two implementations of one 23-parameter contract (rename the stale file + widen the cross-engine pin matrix now; unification as a tracked follow-up) #1917

Description

@lmeyerov

Raised by the owner reviewing the stack: "do we have both eager hop.py and polars/hop_eager.py? that seems problematic." Investigated; the instinct is right, though the naming hides what is actually going on.

What is actually there

file lines role
graphistry/compute/hop.py 1165 pandas/cuDF implementation
graphistry/compute/gfql/lazy/engine/polars/hop_eager.py 502 the polars implementation
graphistry/compute/gfql/lazy/engine/polars/hop.py 55 entry point only — eagerness normalization (#1740) + the #1658 index hook, then delegates

So it is not eager-vs-eager duplication. polars/hop.py is a dispatcher, and hop_eager.py is the polars kernel — which per its own docstring now contains both the lazy collect-once single-hop plan (the GPU path) and the eager BFS loop, after a separate lazy twin was consolidated into it.

Problem 1 (cheap, do now): the filename is stale and misleading

hop_eager.py has not been eager-only since that consolidation. Anyone auditing the tree reads the pair hop.py + hop_eager.py as redundant implementations — exactly what happened here. Rename to hop_impl.py or hop_polars.py (the exported symbol is already hop_polars).

Problem 2 (the real one): one semantic contract, two implementations, nothing forcing agreement

Both must implement the same 23 parameters identically: min_hops, max_hops, output_min_hops, output_max_hops, label_node_hops, label_edge_hops, label_seeds, to_fixed_point, direction, edge_match, source_node_match, destination_node_match, source_node_query, destination_node_query, edge_query, return_as_wave_front, include_zero_hop_seed, target_wave_front, plus the hop/seed basics.

This campaign is the empirical case that it drifts. Both hop umbrellas had to patch both files — #1892 (filter-domain invariant, 2a2911221) and #1888 (endpoint closure, 5ddbd666d) — and #1888 needed three kernels, because the polars chain fast path is a third home for the same rule. The pattern recurs beyond hop: #1913's stale-index fix hit two chain call sites, #1911's edge-identity fix hit three. One rule, N implementations, and the probes keep finding the site somebody missed.

Problem 3: the mitigation is thinner than it looks

graphistry/tests/compute/gfql/test_hop_semantics_pins.py is cross-engine parameterized — the right design — but it is 13 test functions against a 23-parameter surface, and the polars arm is polars_only-marked, so it silently vanishes on a pandas-only install (the #1898 skipped-lane class). Single flags are the well-covered part; combinations are the gap (bounds × to_fixed_point, output-window vs traversal-window, filters at hop k>1 — note #1892's bug was precisely a filter-DOMAIN invariant — direction × self-loops/parallel edges, target_wave_front × filters).

Proposed sequencing

  1. Now: rename the stale file (mechanical, zero risk).
  2. Now: widen the cross-engine pin matrix toward the parameter surface, prioritizing combinations. This is what actually catches drift, and it is cheap and safe. A round-011 re-probe of exactly these combinations is running and will feed it.
  3. Tracked follow-up, NOT this release: unifying the implementations. They differ for legitimate reasons — polars wants a single lazy collect-once plan so the GPU path reads/transfers the edge table once; pandas/cuDF want an eager BFS loop whose early-break and revisit bookkeeping need per-hop materialization. A naive merge either loses the GPU plan or bolts a lazy abstraction onto the pandas path. This is a project with its own design review, and it should not start while twelve PRs are stacked on top of hop.py.

Deliberately not attempting (3) mid-release.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions