feat(accuracy): propagate end-to-end accuracy guarantees for approximate-over-approximate plans (#172, PR 1+2) - #299
Open
zzylol wants to merge 1 commit into
Open
Conversation
…ummaries (#172) PR 1 + PR 2 of the stacked plan in #172. Represent guarantees and fail closed: - asap-types: `post_asap::guarantee` — `ErrorMetric` (#[non_exhaustive]), symbolic `BoundExpr`/`ProbabilityExpr` expression vocabularies (evaluate to `None`, never 0, on an unknown statistic), `GuaranteeSource` provenance, `ResultGuarantee`, `CompositionOperator`, and typed `AccuracyError::{UnsupportedComposition, MissingInputGuarantee, TargetNotSatisfied, NoLegalAllocation}`. - `SummaryNode.guarantee: Option<ResultGuarantee>` on every finalized value (readouts, exact accumulators, kept pre-ASAP subtrees); raw sketch state carries none. Exact values are zero-error; sketch readouts get a family-specific local guarantee by inverting `default_size_params`. - `construct_summary_agg` detects approximate-child -> approximate-parent composition and rejects it unless the `AccuracyModel` has a rule — never treating the child as exact. Rejections are typed `RejectedCandidate`s on `MemoGroup::rejected`, via a new `ReplacementStrategy::propose` hook (default delegates to `replacements`). - DAG export: `SummaryDagNode.guarantee`, guarantee in merged-graph `detail`, and `NamedGraph.rejections` — all additive/omitted when empty. Conservative same-metric propagation and budget allocation: - `asap_aware_mapping::accuracy` — `AccuracyModel` trait (`local_guarantee`/`propagate`/`satisfies`) and `DefaultAccuracyModel`: exact-input, additive absolute (B_in + B_out, delta by union bound), relative with cross term (needs known sign), explicitly registered L-Lipschitz, exact sum (sum of bounds) and max/min over approximate inputs; incompatible metrics -> `UnsupportedComposition`. No independence assumptions anywhere. - `AccuracyBudgetAllocator` trait + `EqualSplitAllocator` (eps_i = eps/n, delta_i = delta/n; (1+eps)^(1/n)-1 for relative); each allocation re-sizes the outer layer through the existing `CostModel::size_params` path and re-enumerates the child under its share. Only legal allocations become candidates. - `search_workload_with_targets` checks a root `QueryRequirements` target against the root group's bound candidates before any cost ranking; `CostModel` never sees a rejected candidate. - Precedence between root and per-node targets documented in `accuracy.rs` and the design doc. Deferred to PR 3: TopK margin certificate and #239 posterior refinement. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements PR 1 (represent guarantees and fail closed) and PR 2 (conservative same-metric propagation + budget allocation) of the stacked plan in #172. PR 3 (TopK margin certificate, #239 posterior-bound integration) is deferred —
CompositionOperator::TopKSelectionexists and is always rejected by the default model, andGuaranteeSource::RuntimeObservationis reserved in the vocabulary, so PR 3 slots in without a schema change.Refs #172.
What changed
asap-types—post_asap::guarantee(new)ErrorMetric(#[non_exhaustive]: AbsoluteValue, RelativeValue, Rank, Cardinality, Frequency, TopKMembership), each variant documenting its normalization — metrics are not interchangeable.BoundExpr/ProbabilityExpr: small serializable expression trees (Zero,Constant,Sum,Product,Scaled,Max,Unknown{statistic}/UnionBound,Scaled{count}), not prose.evaluate()returnsNone, never0, when anUnknownleaf is reachable.GuaranteeSourceprovenance (exact, accuracy target, selected sketch params, child guarantee, composition step + rule name, budget allocation, unavailable statistic, runtime observation — reserved for Add posterior (query-time) error estimation for CMS/CountSketch, per Chen et al. IMC'21 #239).ResultGuarantee { metric, bound, failure_probability, provenance }withis_exact()/approximate_layer_count().CompositionOperatorand typedAccuracyError::{UnsupportedComposition, MissingInputGuarantee, TargetNotSatisfied, NoLegalAllocation}(Serialize/Deserialize,thiserror).SummaryNode.guarantee: Option<ResultGuarantee>—Someon finalized values (SummaryEstimatereadouts,ExactAggregatestate,KeepPreAsap),Noneon raw sketch state and on families with no error model (unknown ≠ exact).SketchAlgorithm/SketchParamsnow deriveSerialize/Deserialize(needed for structural provenance).asap-aware-mapping—accuracy(new)AccuracyModeltrait (local_guarantee/propagate/satisfies) andDefaultAccuracyModel:2/k, HLL1.04/√2^p, KMV/Theta1/√k, CMS-familye/wwithδ = e^{-d}, DDSketchα);B_in + B_outwith union-bound δ; relativeε_in + ε_out + ε_in·ε_out(requiresPropagationStats::values_non_negative == Some(true)); explicitly registeredLipschitz{L}; exact sum (Σ B_i, scaled by an unknown-unless-supplied row count); exact max/min (max B_i); everything else — including every cross-metric case and same-metric Rank/Cardinality/Frequency-over-itself —UnsupportedComposition. No independence is ever assumed; unknown statistics stay unknown.AccuracyBudgetAllocatortrait +EqualSplitAllocator(ε_i = ε/n,δ_i = δ/n;(1+ε)^{1/n} − 1for multiplicative metrics; no allocation forExact).asap-aware-mapping—replacementSketchAlgorithmStrategy::with_models(cost, accuracy, allocator);new/default_cost_modelkeep the defaults.construct_summary_aggcomputes the guarantee before the node exists, viapropagateunder the operator the family applies (ApproximateAggregate,ExactSumforSum,ExactExtremumforMinMax, exact forCount, no finite Lipschitz constant forRate/Increase). Approximate-over-approximate must alsosatisfiesthe outer node's own target; failure isImplementError::Accuracy.ReplacementStrategy::propose(default =replacements+ no rejections). The sketch strategy proposes (a) the as-declared composition and (b) one candidate per allocator split, re-sizing the outer layer throughCostModel::size_paramsand re-enumerating the child under its budget share (realize_child_with). Illegal attempts becomeRejectedCandidates on the newMemoGroup::rejected.search_workload_with_targets(roots_with_targets, strategies, accuracy_model)checks a rootQueryRequirements.accuracyagainst the root group's bound candidates and moves misses torejectedbeforecost_sorted/global_selectionrun. ACostModelnever sees a rejected candidate and cannot resurrect one.DAG export (additive, backward compatible)
SummaryDagNode.guarantee(omitted whenNone), guarantee underdetail.guaranteein merged post-ASAP graphs,NamedGraph.rejections: Vec<TargetRejection>(omitted when empty); thedag_exportdevtool populates rejections by the same hash-then-structural-equality matching used for winners.Precedence: root
QueryRequirements.accuracyvs per-nodeAggIntent.accuracysearch_workload_with_targetsis the end-to-end requirement for that query's root value; candidates whose guarantee is unknown or misses it are rejected before ranking.KeepPreAsap(exact) always survives, so an unsatisfiable root keeps the raw/pre-ASAP plan.AggIntent.accuracysizes its sketch exactly as before; the readout's guarantee is that sketch's local guarantee. (Single-layer behavior is unchanged and not re-checked against its own target, so saturated/clamped sizings keep behaving as today.)AggIntent.accuracyis the end-to-end target for that value. The inner node's target is only a declared local requirement — the as-declared composition is kept only if the composed guarantee satisfies the outer target, and the allocator additionally proposes re-sized splits. Front-end-copied per-node targets are therefore never assumed to constitute a valid allocation.AccuracyTarget::Exactadmits only exact realizations; an allocation never overrides a child declaredExact.Design decisions worth reviewing
SummaryAggnodes carryNone; theSummaryEstimatecarries the guarantee. Hydra grouping candidates copy the per-subpopulation guarantee (the shared-grid noise term from post-asap: GroupingStrategy axis - PerSubpopulationInstance vs SharedMultiSubpopulation (Hydra) summary types #256 is not folded in — flagged below).k = 2/εis attributed the 99%-confidence convention (δ = 0.01); HLL/KMV/Theta's standard-error sizing is attributed the 1σ level (δ ≈ 0.3173). This only bites when anEpsilonDeltatarget is checked end-to-end (root check or nested composition) — anEpsilontarget is unaffected.TopKreadouts carry aFrequencyguarantee for each reported key's count plus anUnavailableStatistic{topk_membership_margin_certificate}provenance note; nothing claimsTopKMembershipuntil PR 3.enumerating_the_targets_candidates_does_not_leak_into_a_nested_aggregateasserted the old unsafe behavior (KLL quantile composed over a KLL quantile with no check). It now injects a test-only permissiveAccuracyModelso the property it is actually about still holds; a new test pins that the default rejects that composition.Tests
cargo build --workspace,cargo test --workspace(all green, 165 inasap-aware-mapping),cargo clippy --workspace --all-targets -- -D warnings,cargo fmt --all -- --check.From the issue's list: approximate-under-approximate rejected by default (not treated as exact, cross-metric and same-metric); exact child contributes zero error; additive bounds + delta union bound; relative error includes the cross term (and is rejected without sign knowledge); incompatible metrics rejected; Lipschitz; exact sum keeps an unknown row count unknown; equal budget allocation respects root ε/δ (additive and multiplicative); a candidate whose composed bound exceeds the target is absent before cost ranking and recorded as rejected; a legal tighter/more-expensive candidate (k=40) beats the illegal cheaper one (k=20) in
global_selection; root target check removes candidates before ranking (Epsilon,Exact); DAG export contains metric, bound expr, failure probability, provenance, allocation and rejection reason. Deferred: TopK margin fixtures; shared-nested-summary costing (#172 cost-model section is out of this PR's scope).Open questions for reviewers
failure_probabilitybeUnknown(which would make everyEpsilonDeltaend-to-end check fail for them)?RelativeValuerule requiresPropagationStats::values_non_negative == Some(true); the planner has no source for that statistic yet, so DDSketch-over-DDSketch is rejected by default until a deployment supplies it. Is that the right conservative stance for now?SharedMultiSubpopulation) candidates inherit the per-subpopulation guarantee verbatim; folding Theorem 2's collision term in is left to post-asap: GroupingStrategy axis - PerSubpopulationInstance vs SharedMultiSubpopulation (Hydra) summary types #256/Support accuracy-aware approximate Count roll-ups #278 follow-up.search_workload_with_targetsleaves logicalRewritecandidates (CSE/rollup/avg) untouched at the root check because they are not bound values; the targets inside a rewrite are their own groups. Worth confirming this matches the intended semantics for Support accuracy-aware approximate Count roll-ups #278.🤖 Generated with Claude Code