Conversation
This was referenced Oct 3, 2026
zzylol
marked this pull request as draft
October 3, 2026 19:28
Contributor
Author
|
Parked as draft: PR priorities changed (see #528). Order is now (A) finish #511 operator sharing, (B) the #572 crate/module reorganization, (C) #509 end-to-end stages. This PR sits on the old 🤖 Generated with Claude Code |
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.
Problem: the exact L2 and entropy candidates of #509 Example 2 cannot execute
#509 §Pass 1 (local candidate generation) lists an exact candidate next to the summary candidates for both frequency statistics:
Entropy(x)L2(x)#509 §Example 2 uses these for Q2 and Q3: "each gets its local candidates from the Pass 1 table: exact, a specialized summary, or UnivMon". The independent candidates "are kept as well" after Pass 2, so selection can always fall back to the exact plan. #509 §Physical operator implementation must then turn every node, including the exact one, into a physical operator.
Before this PR, the IR already has
AggIntent::FrequencyL2andAggIntent::FrequencyEntropy, but no exact physical implementation exists:The only way to answer these queries is a manually built UnivMon state (#557). That is an approximation, not the exact fallback #509 assumes.
Scope. This PR supplies the exact physical operator for the
L2(x)andEntropy(x)rows of the #509 §Pass 1 table, and makes the raw cost path accept them. It does not add SQL recognition of the Q2/Q3 idioms (#509 §Example 2 TODO), Pass 2 sharing, or UnivMon accuracy. It also adds a developer status note that audits #557 against #509 and lists the remaining scopes in order.Proposed method
Physical runtime and raw costing only. Logical planning is unchanged.
bind_operationmapsAggIntent::FrequencyL2 { col, .. }toReduction::FrequencyL2(column)andAggIntent::FrequencyEntropy { col, .. }toReduction::FrequencyEntropy(column). As for other intents,col: Noneresolves to the sample-value column.Operator::aggregateaccepts these reductions only over a plainBool,Int64,Float64orUtf8column. The output column is non-nullableFloat64.reduce_one:NULL;Value::key()(so-0.0and0.0are one key, and Int64 keys above 2^53 stay distinct);BTreeMap<Vec<u8>, u64>and tracks the total;hypotof all counts, or entropy as-Σ p·log2(p)withp = count / total.An empty population (no rows or only NULL) returns
0.0.64 + size_of::<Vec<u8>>() + key.len() + size_of::<u64>()bytes in aWorkspacetied to theRunContext. The reservation fails withError::MemoryLimitwhen over budget and is released afterward. Each row and each count passeswork.checkpoint(), so long reductions yield and can be cancelled.reduce_onenow receives theRunContextfor this.supports_hash_aggregatelistsFrequencyL2andFrequencyEntropy, so a raw plan with these intents lowers toPhysicalOperator::HashAggregateinstead of failing.Entropy is in bits, matching the
AggIntent::FrequencyEntropydoc ("Shannon entropy in bits").Key code interfaces
crates/asap-physical-operators/src/operators/aggregate/mod.rsExisting IR intents now bound natively (
crates/types/src/pre_asap/agg_intent.rs, unchanged):Binding (
crates/asap-physical-operators/src/physical_planner/mod.rs) and raw costing (crates/asap-aware-mapping/src/query_physical_lowering.rs):Usage (
tests/physical_semantics.rs::exact_frequency_grouping_and_entropy_bits):Fields
Reduction(new variants)FrequencyL2(usize)Bool,Int64,Float64orUtf8. Output:sqrt(Σ count_k²)over distinct non-NULL keyskin the group, as non-nullableFloat64.0.0for an empty population.FrequencyEntropy(usize)-Σ p_k·log2(p_k)in bits,p_k = count_k / total.0.0for an empty or single-key population.Both: NULL identities are skipped; non-finite Float64 identities are an error at execution; each row counts once (unit update).
Operator::aggregateinputSchemaRefgroupsVec<usize>measuresVec<(String, Reduction)>AggIntent::FrequencyL2/FrequencyEntropy(as used by binding)colOption<usize>Noneresolves toColumnRef::SampleValuelike other intents.accuracyAccuracyTargetsupports_hash_aggregatereductionReduction::Reduce(_).measuresExamples
End to end through binding (
tests/physical_semantics.rs::exact_frequency_intents_execute_typed_keys_and_empty_input). APostAsapDAGNodewithAggregate { measures: [FrequencyL2 | FrequencyEntropy { col: Some(0), accuracy: Exact }] }is compiled withcompile_nodeand run. Input is two keys, each twice, then one NULL (a,a,b,b,NULL):Utf8"a","b"Int649_007_199_254_740_992,9_007_199_254_740_993Boolfalse,trueFloat64-0.0,1.0Empty input and NULL-only input both return
Float64(0.0)for both intents. Results are checked to 1e-12.Grouping (
exact_frequency_grouping_and_entropy_bits).-0.0, 0.0, 0.0, 1.0(zero ×3, one ×1)-0.75·log2(0.75) - 0.25·log2(0.25)2.0, NULLNULLGrouped aggregation over no input rows returns no rows.
Memory (
tests/blocking_resources.rs::frequency_dictionary_enforces_memory_budget). 64 distinct Int64 rows under a 12,000-byte budget:CountFrequencyL2(0)Err(Error::MemoryLimit)FrequencyEntropy(0)Err(Error::MemoryLimit)In every case
retained_bytes()is 0 afterward.Accepted vs rejected
Bool/Int64/Float64/Utf8Operator::aggregateStatus note.
docs/develop_docs/planner-layering-status.md(new) audits #557 against #509 per contract (frontends, local alternatives, summary-capability sharing, window composition, materialization, whole-workload selection, deployment inputs, TODOs) and lists seven ordered follow-up scopes. Step 1, exact frequency execution, is this PR.Out of scope
Cardinality) binding (feat(runtime): execute exact distinct identity counts #563).Stack and validation
Stacked on #557 · Next: #562 · Reference/tracker: #528
Validation: native binding regression failed before the implementation and passes afterward; native runtime suite; focused grouping and dictionary-memory tests; formatting; native/runtime and mapping all-target Clippy with warnings denied.
🤖 Generated with Claude Code