Skip to content

Commit 5b23746

Browse files
committed
feat(plan-selection)!: let the deployment's accuracy model decide outputs without a guarantee
- Move AccuracyEvidenceProvider and NoAccuracyEvidence to asap_plan_selection::accuracy, next to AccuracyModel; OperandDomain and PropagationStats stay in Stage 1. - Rename DefaultAccuracyModel to BuiltinAccuracyModel. AccuracyModel::propagate gets a default body (the built-in rules), so a deployment model implements only satisfies. - Add AccuracyModel::accepts_output_without_guarantee (default false). Stage 3 asks it only when neither Stage 1 nor the evidence supplies a guarantee; an output it accepts is recorded with AcceptedAccuracy::accepted_without_guarantee, and one it does not is rejected with the new RejectionCause::NoAccuracyGuarantee (was AccuracyTargetMissed). - Document accuracy::estimators::local_guarantee and accuracy::composition::propagate, and drop their duplicate re-exports. - stage_pipeline writes accepted_without_guarantee; the dag-viewer accepts the new cause; the example fixture is regenerated. BREAKING CHANGE: AccuracyEvidenceProvider/NoAccuracyEvidence move to asap_plan_selection; DefaultAccuracyModel is now BuiltinAccuracyModel; a candidate whose output has no guarantee is rejected as no_accuracy_guarantee instead of accuracy_target_missed; AcceptedAccuracy gains a field.
1 parent 71112c8 commit 5b23746

17 files changed

Lines changed: 466 additions & 220 deletions

File tree

‎crates/devtools/src/bin/stage_pipeline.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@
3131
// - stage3_plan_selection: the selected candidate, chosen among all candidates;
3232
// the shown candidates' costs and accepted accuracy (per query: the
3333
// target's metric or null when not set, the accepted guarantee's
34-
// metric or null when exact, the sketches read and a one-line
34+
// metric or null when exact or accepted without a guarantee, whether
35+
// the deployment's accuracy model accepted it without a guarantee
36+
// (`accepted_without_guarantee`), the sketches read and a one-line
3537
// summary), and every other shown candidate under `rejected` with
3638
// its `cause`: a failed check (`failure_probability_resize_failed`,
37-
// `accuracy_target_missed`, `raw_data_not_retained`,
39+
// `accuracy_target_missed`, `no_accuracy_guarantee`, `raw_data_not_retained`,
3840
// `latency_bound_exceeded`, `over_cluster_capacity`) or a loss under
3941
// the cost model (`costlier`, `slower`, `more_memory`,
4042
// `not_lowest_latency_on_pareto_front`, `dominated`,
@@ -617,6 +619,7 @@ fn plan_selection_json(
617619
json!({
618620
"target_metric": accepted.target_metric,
619621
"accepted_metric": accepted.accepted_metric,
622+
"accepted_without_guarantee": accepted.accepted_without_guarantee,
620623
"sketches": accepted.sketches,
621624
"summary": accepted.to_string(),
622625
})

‎crates/frontend-promql/tests/univmon_candidates.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::rc::Rc;
22

3-
use asap_logical_asap_optimization::accuracy::{local_guarantee, satisfies};
3+
use asap_logical_asap_optimization::accuracy::estimators::local_guarantee;
4+
use asap_logical_asap_optimization::accuracy::satisfies;
45
mod support;
56
use asap_types::ir::cse::share_common_sub_dags;
67
use asap_types::ir::properties::AccuracyMetric;

‎crates/integration-tests/tests/promql_to_post_asap.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use std::rc::Rc;
1111
use asap_integration_tests::fixtures::lower_promql;
1212
use asap_integration_tests::planning::logical_candidates;
1313
use asap_integration_tests::post_asap::{at_ingestion, at_ingestion_post_asap_dag, post_asap_dag};
14-
use asap_logical_asap_optimization::accuracy::{AccuracyEvidenceProvider, OperandDomain};
14+
use asap_logical_asap_optimization::accuracy::OperandDomain;
1515
use asap_physical_asap_optimization::PhysicalCandidate;
16+
use asap_plan_selection::AccuracyEvidenceProvider;
1617
use asap_plan_selection::PlanningModels;
1718
use asap_plan_selection::Selection;
1819
use asap_types::ir::operator::operator_properties::Reduction;

‎crates/logical-asap-optimization/src/accuracy/composition.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,12 @@ fn composed_provenance(
694694
provenance
695695
}
696696

697+
/// The built-in composition rule: `inputs`' guarantees (in the parent's
698+
/// child order) composed with the parent's own `local` guarantee under `op`,
699+
/// given the statistics in `stats` (all unknown in Stage 1; plan selection
700+
/// binds some). `Err` is the fail-closed answer: no registered rule, or a
701+
/// missing input guarantee. It means "no rule", not "infeasible": Pass 1
702+
/// keeps the candidate with `guarantee = None`.
697703
pub fn propagate(
698704
op: &CompositionOperator,
699705
inputs: &[AccuracyGuarantee],

‎crates/logical-asap-optimization/src/accuracy/estimators/mod.rs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ fn bounded_guarantee(
5454
)
5555
}
5656

57+
/// The built-in guarantee of reading `query` out of a summary of family
58+
/// `family` built over an **exact** input, derived from the family's
59+
/// committed parameters by inverting the same sizing formulas
60+
/// [`crate::realization::default_size_params`] uses. Exact for a plain value
61+
/// or an exact aggregate. `None` when the family has no error model
62+
/// (`Sample`, `Wavelet`, `StatModel`, and sketch evaluations without a
63+
/// certified bound): Pass 1 then leaves the guarantee `None` and keeps the
64+
/// candidate for plan selection to decide.
5765
pub fn local_guarantee(
5866
family: &FieldDataType,
5967
query: &SketchStatistic,

‎crates/logical-asap-optimization/src/accuracy/evidence.rs‎

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
//! Scoped source contracts and evidence required by accuracy rules.
1+
//! Scoped source contracts and statistics the accuracy rules consult.
22
use super::*;
3-
use asap_types::ir::QueryRoot;
43

54
/// An enforced domain for the true values of one operand of an exact
65
/// arithmetic operation, in every evaluation: they are finite and lie in
@@ -59,31 +58,3 @@ pub struct PropagationStats {
5958
/// certificate.
6059
pub topk_interval_failure_probability: Option<f64>,
6160
}
62-
63-
/// Supplies typed planning-time evidence required by propagation rules.
64-
pub trait AccuracyEvidenceProvider {
65-
/// Enforced domain of `operand`'s true values ([`OperandDomain`]), scoped
66-
/// to this complete expression, including its source, filters, grouping
67-
/// and window: a quantile ratio's operands, or the operands of a
68-
/// product or quotient of estimates. `None` means unknown, including
69-
/// emptiness.
70-
fn operand_domain(&self, _operand: &OperatorNode) -> Option<OperandDomain> {
71-
None
72-
}
73-
74-
/// The deployment's empirical accuracy for one candidate's whole query
75-
/// output, as a guarantee. Plan selection (#509 Stage 3) accepts a
76-
/// candidate whose output has no theoretical guarantee that meets the
77-
/// target (e.g. a difference of two quantile estimates) only when this
78-
/// shows the output meets it. Stage 1 composition never reads it: root
79-
/// guarantees there come from the built-in theoretical model. `None`
80-
/// means no evidence.
81-
fn output_guarantee(&self, _output: &QueryRoot) -> Option<AccuracyGuarantee> {
82-
None
83-
}
84-
}
85-
86-
#[derive(Debug, Default, Clone, Copy)]
87-
pub struct NoAccuracyEvidence;
88-
89-
impl AccuracyEvidenceProvider for NoAccuracyEvidence {}

‎crates/logical-asap-optimization/src/accuracy/mod.rs‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
//! Planner accuracy interfaces and model dispatch.
1+
//! The planner's built-in analytical accuracy rules: estimators, composition, budget split and target check.
22
//!
33
//! Estimator models derive local guarantees, composition propagates them,
44
//! the budget split sizes each approximate input of a composition for an
5-
//! equal share of its target, and evidence supplies scoped contracts.
6-
//! Unknown evidence may retain a candidate but does not authorize selection.
5+
//! equal share of its target, and `evidence` holds the scoped contracts and
6+
//! statistics the rules consult. The deployment's evidence provider and
7+
//! accuracy model live in plan selection (`asap_plan_selection::accuracy`).
78
//! See `docs/design_docs/concepts/accuracy-models.md` for the design.
89
910
pub mod budget;
@@ -12,18 +13,14 @@ pub mod estimators;
1213
pub mod evidence;
1314

1415
pub use budget::per_input_target;
15-
pub use evidence::{AccuracyEvidenceProvider, NoAccuracyEvidence, OperandDomain, PropagationStats};
16+
pub use evidence::{OperandDomain, PropagationStats};
1617

1718
use asap_types::ir::properties::{
1819
AccuracyError, AccuracyGuarantee, AccuracyMetric, BoundExpr, CompositionOperator,
1920
GuaranteeSource, ProbabilityExpr,
2021
};
2122
use asap_types::ir::properties::{AccuracyScope, AccuracyTarget};
2223
use asap_types::ir::schema::{FieldDataType, SketchAlgorithm, SketchParams, SketchStatistic};
23-
use asap_types::ir::OperatorNode;
24-
25-
pub use composition::propagate;
26-
pub use estimators::local_guarantee;
2724

2825
/// Small relative tolerance for comparing an evaluated bound against a
2926
/// target, so a parameter sized by `⌈·⌉` to *exactly* meet ε is not rejected
@@ -38,7 +35,7 @@ const SATISFACTION_TOLERANCE: f64 = 1e-9;
3835
/// another metric does not satisfy, however small. When it sets none, a
3936
/// bound in any metric does, each compared in its own metric. Unknown
4037
/// required dimensions fail. Plan selection's default accuracy model
41-
/// (`asap_plan_selection::DefaultAccuracyModel`) delegates to it.
38+
/// (`asap_plan_selection::BuiltinAccuracyModel`) delegates to it.
4239
pub fn satisfies(guarantee: &AccuracyGuarantee, target: &AccuracyTarget) -> bool {
4340
let within = |value: Option<f64>, limit: f64| {
4441
value.is_some_and(|v| v <= limit * (1.0 + SATISFACTION_TOLERANCE) + f64::EPSILON)

‎crates/logical-asap-optimization/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub mod realization;
5454
#[cfg(any(test, feature = "test-support"))]
5555
pub mod test_support;
5656

57-
pub use accuracy::{AccuracyEvidenceProvider, NoAccuracyEvidence, PropagationStats};
57+
pub use accuracy::PropagationStats;
5858
pub use deployment_capabilities::{
5959
DeploymentCapabilities, DeploymentCapabilitiesError, SupportedSummary,
6060
};

‎crates/logical-asap-optimization/src/per_computation_candidates.rs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,15 @@ use asap_types::ir::{
113113
use asap_types::physical::Materialization;
114114
use thiserror::Error;
115115

116+
use crate::accuracy::composition::propagate;
116117
use crate::accuracy::composition::samples_sign_statistic;
117118
use crate::accuracy::composition::{
118119
additive_as_absolute, StreamNorm, DIVISION_OPERAND_DOMAINS, GROUP_ROW_COUNT,
119120
PRODUCT_OPERAND_DOMAINS, QUOTIENT_OPERAND_DOMAINS,
120121
};
122+
use crate::accuracy::estimators::local_guarantee;
121123
use crate::accuracy::estimators::{hll, univmon};
122-
use crate::accuracy::{local_guarantee, per_input_target, propagate, PropagationStats};
124+
use crate::accuracy::{per_input_target, PropagationStats};
123125
use crate::deployment_capabilities::DeploymentCapabilities;
124126
use crate::function_rules::approximate_input_composition;
125127
use crate::realization::{accuracy_budget, default_size_params, sizing_target, summary_candidates};

‎crates/plan-selection/src/accuracy.rs‎

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,40 @@
44
//! Stage 1 composes each candidate's guarantee with the planner's built-in
55
//! analytical rules (`asap_logical_asap_optimization::accuracy`) and keeps a
66
//! candidate it has no rule for with `guarantee = None`. This stage decides,
7-
//! with the model here, whether a guarantee meets its query's target and
8-
//! how guarantees compose once the data workload and the deployment's
9-
//! evidence bind the statistics Stage 1 left unknown.
7+
//! with the model here, whether a guarantee meets its query's target, how
8+
//! guarantees compose once the data workload and the deployment's evidence
9+
//! ([`AccuracyEvidenceProvider`]) bind the statistics Stage 1 left unknown,
10+
//! and whether an output with no guarantee at all is accepted.
1011
11-
use asap_logical_asap_optimization::accuracy::{self as analytical, PropagationStats};
12+
use asap_logical_asap_optimization::accuracy::{
13+
self as analytical, OperandDomain, PropagationStats,
14+
};
1215
use asap_types::ir::properties::{
1316
AccuracyError, AccuracyGuarantee, AccuracyTarget, CompositionOperator,
1417
};
18+
use asap_types::ir::{OperatorNode, QueryRoot};
1519

1620
/// The deployment-extensible accuracy algebra plan selection uses. This
17-
/// crate ships [`DefaultAccuracyModel`]; a deployment with a proof for a
21+
/// crate ships [`BuiltinAccuracyModel`]; a deployment with a proof for a
1822
/// composition the default rejects (a registered cross-metric conversion,
1923
/// say) implements this trait and passes it in
2024
/// [`PlanningModels::accuracy`](crate::PlanningModels::accuracy).
2125
pub trait AccuracyModel {
2226
/// Compose `inputs`' guarantees (in the parent's child order) with the
2327
/// parent's own `local` guarantee under `op`, given the statistics
2428
/// plan selection bound (`stats`). `Err` is the fail-closed answer: no
25-
/// registered rule, or a missing input guarantee.
29+
/// registered rule, or a missing input guarantee. The default is the
30+
/// built-in rules (`asap_logical_asap_optimization::accuracy::composition::propagate`);
31+
/// a deployment overrides it only to add a rule.
2632
fn propagate(
2733
&self,
2834
op: &CompositionOperator,
2935
inputs: &[AccuracyGuarantee],
3036
local: Option<&AccuracyGuarantee>,
3137
stats: &PropagationStats,
32-
) -> Result<AccuracyGuarantee, AccuracyError>;
38+
) -> Result<AccuracyGuarantee, AccuracyError> {
39+
analytical::composition::propagate(op, inputs, local, stats)
40+
}
3341

3442
/// Whether `guarantee` meets `target`: a bound within its ε, and within
3543
/// its δ when it states one, over the values the target's scope covers
@@ -40,26 +48,65 @@ pub trait AccuracyModel {
4048
/// compared in its own metric. Unknown required dimensions fail;
4149
/// selection separately excludes missing accuracy evidence.
4250
fn satisfies(&self, guarantee: &AccuracyGuarantee, target: &AccuracyTarget) -> bool;
51+
52+
/// Whether the deployment accepts `output`, one query's output in a
53+
/// candidate, for `target` although the output has no guarantee: Stage 1
54+
/// had no analytical rule for it and the deployment's evidence supplies
55+
/// none ([`AccuracyEvidenceProvider::output_guarantee`]). Stage 3 asks only
56+
/// then; a guarantee from either source is checked with
57+
/// [`Self::satisfies`] instead. The default accepts none, and Stage 3
58+
/// rejects such a candidate (`RejectionCause::NoAccuracyGuarantee`).
59+
fn accepts_output_without_guarantee(
60+
&self,
61+
_output: &QueryRoot,
62+
_target: &AccuracyTarget,
63+
) -> bool {
64+
false
65+
}
4366
}
4467

4568
/// The planner's built-in analytical rules as an [`AccuracyModel`]: the
46-
/// same composition rules and conservative target check Stage 1 uses. The
47-
/// default in [`PlanningModels::builtin`](crate::PlanningModels::builtin).
69+
/// trait's default composition, the conservative target check Stage 1's
70+
/// `accuracy::satisfies` makes, and no output accepted without a guarantee.
71+
/// The default in [`PlanningModels::builtin`](crate::PlanningModels::builtin).
4872
#[derive(Debug, Default, Clone, Copy)]
49-
pub struct DefaultAccuracyModel;
50-
51-
impl AccuracyModel for DefaultAccuracyModel {
52-
fn propagate(
53-
&self,
54-
op: &CompositionOperator,
55-
inputs: &[AccuracyGuarantee],
56-
local: Option<&AccuracyGuarantee>,
57-
stats: &PropagationStats,
58-
) -> Result<AccuracyGuarantee, AccuracyError> {
59-
analytical::propagate(op, inputs, local, stats)
60-
}
73+
pub struct BuiltinAccuracyModel;
6174

75+
impl AccuracyModel for BuiltinAccuracyModel {
6276
fn satisfies(&self, guarantee: &AccuracyGuarantee, target: &AccuracyTarget) -> bool {
6377
analytical::satisfies(guarantee, target)
6478
}
6579
}
80+
81+
/// The deployment's planning-time accuracy evidence, read only by plan
82+
/// selection: enforced operand domains the propagation rules need, and
83+
/// empirical guarantees for whole query outputs. Passed in
84+
/// [`PlanningModels::evidence`](crate::PlanningModels::evidence). The trait
85+
/// moved here from `asap_logical_asap_optimization::accuracy`.
86+
pub trait AccuracyEvidenceProvider {
87+
/// Enforced domain of `operand`'s true values ([`OperandDomain`]), scoped
88+
/// to this complete expression, including its source, filters, grouping
89+
/// and window: a quantile ratio's operands, or the operands of a
90+
/// product or quotient of estimates. `None` means unknown, including
91+
/// emptiness.
92+
fn operand_domain(&self, _operand: &OperatorNode) -> Option<OperandDomain> {
93+
None
94+
}
95+
96+
/// The deployment's empirical accuracy for one candidate's whole query
97+
/// output, as a guarantee. Plan selection (#509 Stage 3) accepts a
98+
/// candidate whose output has no theoretical guarantee that meets the
99+
/// target (e.g. a difference of two quantile estimates) when this shows
100+
/// the output meets it. Stage 1 never reads it: root guarantees there
101+
/// come from the built-in analytical rules. `None` means no evidence.
102+
fn output_guarantee(&self, _output: &QueryRoot) -> Option<AccuracyGuarantee> {
103+
None
104+
}
105+
}
106+
107+
/// No deployment evidence: every operand domain and output guarantee is
108+
/// unknown. The default in [`PlanningModels::builtin`](crate::PlanningModels::builtin).
109+
#[derive(Debug, Default, Clone, Copy)]
110+
pub struct NoAccuracyEvidence;
111+
112+
impl AccuracyEvidenceProvider for NoAccuracyEvidence {}

0 commit comments

Comments
 (0)