diff --git a/CHANGELOG.md b/CHANGELOG.md index b19c177230..fdbd5b8cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - **GFQL execution context is declared rather than attached at runtime**: the private `_gfql_*` per-execution fields (index policy and registry, row-pipeline base graph, carried seed nodes, edge aliases, shortest-path backend, and the indexed-bindings handoff) are now declared on `Plottable` with defaults on `PlotterBase`, instead of being set with `setattr` and read back with `getattr(..., default)`. No public API or behaviour change; internal call sites are typed, and hand-rolled `Plottable` stand-ins must now construct the full context. ### Fixed +- **`group_in_a_box_layout()` crashed on cuDF graphs**: the vectorized normalize converted per-partition stats to pandas before merging them into the engine frame, and cuDF's merge rejects a pandas right operand (`TypeError: right must be a Series or DataFrame`). Stats now stay in-engine; pandas path unchanged. (#1876) - **Degree facts now build on real graphs: the density requirement was mine, not the math's.** The builder refused any gapped id space, and real node spaces are gapped (the benchmark's own is), so degree facts built on every test fixture and on zero real graphs — answers stayed correct via the scan, making the dead path invisible until an engagement probe caught it. Density is not required for the arrays: ids absent from the span contribute zero to the dot, so degrees now build over each edge partition's own endpoint span (bounded by the existing span cap), and only the kernel's separate domain proof requires density — as it already did. The obsolete pin asserting the opposite is flipped, fixtures now use interleaved ids by default, and the gapped-space case pins both fact construction and exactness. - **Timing magnitudes move out of GFQL product code into pyg-bench, and the semi-join no-dedup argument becomes a test.** Perf numbers in a public repo double as an optimization roadmap, so eight magnitude claims across five modules now state the SHAPE of each constraint (the dedup pass dominates at multi-million-key scale; the zero-row join compounds once per node step; streaming loses at interactive sizes) without the figures. Where a comment carried a claim NO test covered, the test was added rather than the prose kept: `_semi` skips a `.unique()` on its key frame, and that is now pinned both ways — duplicate keys select exactly what one copy selects (eager and lazy), a semi-join cannot fan out where an inner join demonstrably does, non-matching keys actually drop rows, and an empty key frame selects nothing while keeping the schema. No product behavior changes; the five non-test files are AST-identical, verified by `bin/ci_docs_only_check.py`. - **cudf 26.02 removed `Series.dt.date` / `Series.dt.time`**, which the temporal comparison predicates called unguarded. They now fall back to equivalent formulations — a day-truncated datetime compares against a midnight `Timestamp` exactly as a date does, and a time-of-day timedelta against a `Timedelta` exactly as a time does — with the scalar paired to the dtype the truncation produces, so no comparison silently changes meaning. Pinned by simulating the accessor removal, so the regression is caught without a GPU. diff --git a/graphistry/layout/gib/partitioned_layout.py b/graphistry/layout/gib/partitioned_layout.py index accbadba7a..0bc87db5fd 100644 --- a/graphistry/layout/gib/partitioned_layout.py +++ b/graphistry/layout/gib/partitioned_layout.py @@ -2,7 +2,7 @@ import numpy as np, pandas as pd from timeit import default_timer as timer -from graphistry.Engine import Engine, df_concat, df_to_pdf, df_cons +from graphistry.Engine import Engine, df_concat, df_cons from graphistry.Plottable import Plottable from graphistry.util import setup_logger @@ -196,10 +196,10 @@ def partitioned_layout( 'min': 1 }).max(axis=1) - # Vectorized normalize: merge per-partition stats once, no per-row dict lookups - node_stats_pdf = df_to_pdf(node_stats, engine) + # Vectorized normalize: merge per-partition stats once, no per-row dict lookups. + # Stats stay in-engine: cudf's merge rejects a pandas right operand. combined_with_stats = combined_nodes.merge( - node_stats_pdf[['x_min', 'dx', 'y_min', 'dy']], + node_stats[['x_min', 'dx', 'y_min', 'dy']], left_on=partition_key, right_index=True, how='left',