Skip to content

hydra: score any target grouping; per-group error output - #199

Merged
zzylol merged 2 commits into
mainfrom
hydra/target-grouping
Oct 11, 2026
Merged

zzylol merged 2 commits into
mainfrom
hydra/target-grouping

Conversation

@zzylol

@zzylol zzylol commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Implements PR 2 of the Hydra spec (design doc #193 §5.1): every Hydra row can be scored at any target grouping, and reports error per group, not only a mean.

What changed

  • --group-columns J,K,... (default 0, which is today's behavior) replaces the hardcoded SCORED_LABEL_COLUMN. It applies to every hydra-* row (lib and polars, all five variants and hydra-univmon's four statistics) and accepts any non-empty subset of the label columns. A column at or past the value column is refused by name.
  • Positioned probes. A subpopulation key is now Vec<Option<String>>, with Some at the grouped columns. hydra_shared::query passes it to query_key as is, so {1} is asked as [None, Some(v)] rather than as column 0. The polars baselines look the group up with subset_key(parts, mask) over the same mask (group_key, which generalizes prefix_key).
  • Per-group summary, added to the accuracy fields of every subpopulation comparator: err_mean, err_p50, err_p90, err_max over the scored groups, plus groups_scored, schema_width (d), records (N) and fanned_mass (N·(2^d−1)). Each family uses its own metric, lower is better:
    • CMS and CS: a group's error is the mean relative error over its (group, value) pairs.
    • HLL and UnivMon (cardinality, L1, L2, entropy): relative error. Groups whose true value is 0 are not scored, the same rule are_all uses (they are still listed in --per-group-out, with an empty error).
    • KLL: the group's mean rank error over the 101-point grid.
    • The existing metrics (are_all, mean_rank_err, ...) are unchanged.
  • --per-group-out PATH writes group_key,n_q,error, one row per group, heaviest group first. Unscored groups (zero true value, e.g. zero entropy) have an empty error, so n_q sums to N and a later coverage step sees every group. group_key is the tagged labels, e.g. label0:a;label1:x, with \, : and ; escaped as polars_shared::subset_key does. The flag is refused for non-Hydra rows, when no accuracy measurement is requested, and when both query and merge accuracy are requested (the file holds a single measurement).
  • The README and the configs/datagen/hydra_*.yaml comments now document both flags.

Tests

  • aqpbm-cli/tests/hydra_grouping.rs: runs hydra-cms, cs, hll, kll and univmon-l1-norm, lib on a large grid and polars, at --group-columns 1 and 0,1. The label values overlap across columns. Polars scores err_max = 0 and lib scores ≤ 0.01. The test also checks schema_width, records and fanned_mass, that the CSV's n_q sum to N, and that the CSV keys name the asked columns. A second test refuses a group column past the labels; a third refuses --per-group-out with no accuracy measurement and checks no file is left.
  • entropy unit test: over both columns, three zero-entropy groups are listed with no error, n_q sums to 6, groups_scored = 1.
  • subpopulation unit test: a label holding :, ; and \ renders escaped (label1:x\:y\;z\\;label2:).
  • Mutation checks, each run against this test:
    • query compacting the Somes to a prefix: lib err_max 0.69 at --group-columns 1, test fails.
    • group_key using a prefix mask: the polars row fails the same way.
  • l1_norm unit test on a fixed 4-group case checks err_mean 0.5, p50 0.5, p90 1, max 1, groups_scored, fanned_mass and the per-group rows and their order. Removing the sort fails it. A second unit test covers column 1 alone ([None, Some], keys label1:*).
  • frequency unit test: a group's error is the mean over its own pairs (err_mean 0.125 vs are_all 0.5/3).
  • cargo fmt --check, cargo clippy --workspace --all-targets -D warnings and cargo test --workspace all pass.

Evidence (release build)

approxbench sketchbench --variant hydra-cms --library {lib,polars} --spec configs/datagen/hydra_columns.yaml --dtype i64 \
  --config "rows=3 cols=1024 cell_rows=3 cell_cols=1024" --group-columns {0,1,0,1} --per-group-out g.csv \
  --operations query --metrics accuracy --runs 1 --warmup-runs 0
approxbench sketchbench --variant hydra-kll ... --spec configs/datagen/hydra_columns_f64.yaml --dtype f64 --config "rows=3 cols=1024 cell_k=200"

N = 200000, d = 2, fanned_mass = 600000 in every row. Polars scores 0 on every field at every grouping.

row groups groups_scored err_mean err_p50 err_p90 err_max
hydra-cms lib 0 200 0.167 0.109 0.384 1.13
hydra-cms lib 1 50 0.157 0.092 0.410 0.700
hydra-cms lib 0,1 9950 11.95 5.83 27.5 293
hydra-kll lib 0 200 0.00120 0.00089 0.00205 0.00678
hydra-kll lib 1 50 0.00106 0.00080 0.00161 0.00457
hydra-kll lib 0,1 9950 0.0901 0.0711 0.190 0.490

At {0,1} the groups are small against M/W, and their error is far larger than the coarser groupings' (§2.1).

Round-1 review fixes: key escaping, every group listed (empty error when unscored), and refusal of --per-group-out without accuracy. The CSV still recomputes the per-group rows separately from score (not reused; it would need Score to return them).

🤖 Generated with Claude Code

https://claude.ai/code/session_01FhcWJExZcmVqS6r6rEtjis

zzylol and others added 2 commits October 11, 2026 16:35
Every hydra-* row (lib and polars, all five variants and hydra-univmon's
four statistics) takes `--group-columns J,K,...` (default `0`, today's
behavior) in place of the hardcoded SCORED_LABEL_COLUMN. A subpopulation
probe is now positioned (`Vec<Option<String>>`, Some at the grouped
columns), so `hydra_shared::query` asks any non-empty subset of the key
columns and the polars baselines look up `subset_key` with that subset's
mask (`group_key`, generalizing `prefix_key`).

Each grouped comparator reports its per-group error in its own metric
(relative error; mean rank error for hydra-kll) and summarises it as
err_mean, err_p50, err_p90, err_max, groups_scored, plus schema_width,
records and fanned_mass. `--per-group-out PATH` writes the rows as
`group_key,n_q,error`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhcWJExZcmVqS6r6rEtjis
…curacy

- Group keys escape `\`, `:` and `;` as polars_shared::subset_key does.
- Groups that cannot be scored (zero true statistic, e.g. zero entropy) are
  written with an empty `error`, so n_q sums to the stream's records.
- --per-group-out with no accuracy measurement is refused instead of
  writing an empty file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhcWJExZcmVqS6r6rEtjis
@zzylol
zzylol force-pushed the hydra/target-grouping branch from 8f73ed3 to bc770e3 Compare October 11, 2026 16:36
@zzylol
zzylol changed the base branch from 74-polars-tagged-subkeys to main October 11, 2026 16:36
@zzylol
zzylol merged commit 5e2c91e into main Oct 11, 2026
zzylol added a commit that referenced this pull request Oct 11, 2026
# Conflicts:
#	README.md
#	aqpbm-cli/src/rows/mod.rs
#	aqpbm-cli/src/rows/statistic.rs
#	aqpbm-cli/tests/hydra_grouping.rs
#	aqpbm-core/src/accuracy/subpopulation/frequency_vector.rs
#	aqpbm-core/src/accuracy/subpopulation/rank_error.rs
#	sketch-bench/src/wrappers/hydra_univmon/sketchlib.rs
zzylol added a commit that referenced this pull request Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant