Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/asap-aware-mapping/src/accuracy/reconciliation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
//! priced with, reflecting "one more reference into a structure that's
//! already being maintained" rather than "build a whole new one."
//!
//! `PlanSpace::global_selection` treats this rewrite as a cross-group edge:
//! `CandidatePostASAPDAGs::global_selection` treats this rewrite as a cross-group edge:
//! selecting it increments `rc`'s own `effective_consumer_count`, then lets
//! that sibling group propagate the uses through its selected implementation.
//! Accuracy edges are directed strictly from looser to tighter budgets, so
Expand Down
12 changes: 6 additions & 6 deletions crates/asap-aware-mapping/src/cost_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
//! `docs/design_docs/cse-cost-model-decision.md` for the full design discussion (why
//! cost-based, why not a full plan-search engine, the layering constraint
//! that forces detection to stay cost-agnostic).
//! [`PlanSpace::cost_sorted`](crate::replacement::PlanSpace::cost_sorted)
//! [`CandidatePostASAPDAGs::cost_sorted`](crate::replacement::CandidatePostASAPDAGs::cost_sorted)
//! (via [`crate::replacement`]'s own `cse_preference`) and
//! [`DefaultCostModel::estimate_cost`] are this crate's own callers.

Expand Down Expand Up @@ -139,7 +139,7 @@ pub struct ExactCompositionCostRequest<'a> {
/// formula charges.
pub summary: &'a SummaryNode,
/// How many times this site actually runs once ancestors' own choices
/// are accounted for (see `PlanSpace::global_selection`).
/// are accounted for (see `CandidatePostASAPDAGs::global_selection`).
pub effective_consumer_count: usize,
}

Expand Down Expand Up @@ -268,7 +268,7 @@ fn finite_rate(units_per_second: f64) -> Option<CostRate> {

/// A CSE-detected, legality-gated shared subtree with two or more consumers
/// — the unit [`CostModel::cse_share_decision`] decides over. Built by
/// [`PlanSpace::cost_sorted`](crate::replacement::PlanSpace::cost_sorted)
/// [`CandidatePostASAPDAGs::cost_sorted`](crate::replacement::CandidatePostASAPDAGs::cost_sorted)
/// (via [`crate::replacement`]'s own `cse_preference`) the first time it
/// needs a representative bound node for a subtree that
/// [`asap_types::pre_asap::cse::share_common_subtrees`] already collapsed
Expand Down Expand Up @@ -735,7 +735,7 @@ pub trait CostModel {
/// [`ReplacementSubDAG`] candidate at `target` — a real `f64`, not just a
/// relative rank, meant for a caller that wants to *display* "candidate A
/// costs ≈ X, candidate B costs ≈ Y" (e.g. a DAG-visualization view built
/// on [`PlanSpace::cost_sorted`](crate::replacement::PlanSpace::cost_sorted)),
/// on [`CandidatePostASAPDAGs::cost_sorted`](crate::replacement::CandidatePostASAPDAGs::cost_sorted)),
/// not just order candidates against each other — that ordering job
/// already belongs to [`rank_candidates`](Self::rank_candidates) (for a
/// [`SketchAlgorithmStrategy`](crate::replacement::SketchAlgorithmStrategy)
Expand Down Expand Up @@ -932,7 +932,7 @@ pub trait CostModel {
///
/// Default: every input unknown ([`ExactCompositionCostInputs::unknown`])
/// — unknown is never zero, and with no rate derivable
/// `PlanSpace::global_selection` keeps the conservative `KeepPreAsap`
/// `CandidatePostASAPDAGs::global_selection` keeps the conservative `KeepPreAsap`
/// behavior for the site. A deployment that wants defaults must supply
/// them here explicitly.
fn exact_composition_cost_inputs(
Expand Down Expand Up @@ -1103,7 +1103,7 @@ impl CostModel for DefaultCostModel {
}
}
// A composed candidate is costed in cost-units-per-second by
// `PlanSpace::global_selection` against the child decision it
// `CandidatePostASAPDAGs::global_selection` against the child decision it
// is committed with — a different unit from this structural
// estimate, and unknowable here without that child. `NaN`
// keeps it from ever out-ranking a real estimate by accident.
Expand Down
4 changes: 2 additions & 2 deletions crates/asap-aware-mapping/src/exact_composition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
//! `realize_child` takes the head of the child's own ranking): a
//! [`Replacement::ExactComposition`] carries only the child *target*
//! (`ExactComposition::child_target`, the same `Rc<QueryExpr>` whose
//! `TargetSubDAGCandidates` in `PlanSpace` already holds every candidate for it). It is
//! [`PlanSpace::global_selection`](crate::replacement::PlanSpace::global_selection)
//! `TargetSubDAGCandidates` in `CandidatePostASAPDAGs` already holds every candidate for it). It is
//! [`CandidatePostASAPDAGs::global_selection`](crate::replacement::CandidatePostASAPDAGs::global_selection)
//! that commits the compatible parent/child pair — so the child's own
//! cost-model ranking, workload-wide effective consumer count, and shared
//! `Rc` identity (one inner summary serving two outer folds) all stay
Expand Down
30 changes: 16 additions & 14 deletions crates/asap-aware-mapping/src/explanation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! (issue #252) now *already* computes, for every
//! [`TargetSubDAG`](crate::replacement::TargetSubDAG) in the workload, every
//! semantically valid [`crate::replacement::ReplacementSubDAG`] a registered
//! [`ReplacementStrategy`] can propose — a [`PlanSpace`] of [`TargetSubDAGCandidates`]s. A
//! [`ReplacementStrategy`] can propose — a [`CandidatePostASAPDAGs`] of [`TargetSubDAGCandidates`]s. A
//! rule re-deriving the same yes/no fact from scratch would be answering a
//! question the search already answered, via a second, independently
//! maintained traversal that has to keep agreeing with the first one.
Expand All @@ -39,7 +39,7 @@
//! genuine alternative to the status quo (share this already-shared subtree
//! instead of recomputing it at every consumer), *is* an applicability
//! finding — [`explain_replacements`] and
//! [`explain_replacements_with`] just translate [`PlanSpace`]'s
//! [`explain_replacements_with`] just translate [`CandidatePostASAPDAGs`]'s
//! [`TargetSubDAGCandidates`]s into that shape:
//!
//! - [`ExplanationKind::SketchApproximation`] — the `TargetSubDAG`'s
Expand Down Expand Up @@ -88,14 +88,14 @@
//! (`fn optimization(&self) -> ExplanationKind` + `fn evaluate(&self, roots)
//! -> Vec<ReplacementExplanation>`), the same shape [`crate::cost_model::CostModel`]
//! and [`crate::replacement::Matcher`] use elsewhere in this crate. Once
//! findings are a *view* over [`PlanSpace`] rather than an independent
//! findings are a *view* over [`CandidatePostASAPDAGs`] rather than an independent
//! computation, that trait would be a second extension point answering a
//! question [`ReplacementStrategy`] (issue #251) already answers: "does this
//! `TargetSubDAG` have an alternative worth reporting, and why". A caller who
//! wants a new optimization represented as a finding needs a new
//! `impl ReplacementStrategy` wired into
//! [`crate::replacement::search_workload_with`]'s strategy set *regardless*
//! (that's the only way its candidates end up in the [`PlanSpace`] this
//! (that's the only way its candidates end up in the [`CandidatePostASAPDAGs`] this
//! module reads) — adding an `ApplicabilityRule` too would mean maintaining
//! two extension points for the same new capability, one of which (the rule)
//! would just be re-describing candidates the other (the strategy) already
Expand Down Expand Up @@ -123,24 +123,24 @@
//! [`crate::replacement`] now instead of here.
//! 2. **A node reachable via more than one path is one finding, not one per
//! path.** [`TargetSubDAGCandidates`]s are keyed by `Rc` pointer identity in
//! [`PlanSpace`]'s internal map — there is exactly one group per distinct
//! [`CandidatePostASAPDAGs`]'s internal map — there is exactly one group per distinct
//! `Rc`, full stop, so a shared `Aggregate` reached via two different
//! `BinaryOp` branches (or two different workload roots) is exactly one
//! group, hence at most one [`ExplanationKind::SketchApproximation`]
//! finding, no matter how many paths reach it.
//! [`tests::a_shared_sketchable_aggregate_is_reported_only_once`] pins
//! this directly.
//!
//! ## One thing [`PlanSpace`] doesn't carry that this module still needs:
//! ## One thing [`CandidatePostASAPDAGs`] doesn't carry that this module still needs:
//! human-readable `location` text
//!
//! [`TargetSubDAGCandidates`]/[`PlanSpace`] deliberately track only `Rc<QueryExpr>`
//! [`TargetSubDAGCandidates`]/[`CandidatePostASAPDAGs`] deliberately track only `Rc<QueryExpr>`
//! pointer identity — the currency the search itself needs — not
//! caller-facing prose. [`ReplacementExplanation::location`] is prose (a
//! breadcrumb like `root "dash_a" > lhs`), so this module keeps one small,
//! self-contained walk of its own, [`collect_locations`], whose *only* job
//! is turning "this `Rc`" into "the human-readable place(s) it occurs" for a
//! finding already decided by [`PlanSpace`]. This is not a reincarnation of
//! finding already decided by [`CandidatePostASAPDAGs`]. This is not a reincarnation of
//! the deleted rule traversal: it makes no applicability decision (it runs
//! the same regardless of what any strategy found), and duplicating this
//! small, self-contained shape rather than threading location strings
Expand All @@ -161,7 +161,7 @@
//!
//! | Catalog entry | Status | Where a future `ExplanationKind` would come from |
//! |---|---|---|
//! | Semantic-equivalent rewriting (e.g. `avg` → `sum`/`count`) | [`AvgToSumOverCountStrategy`](crate::rewrite::AvgToSumOverCountStrategy) exists and is wired into `default_strategies()` (issue #253) — but still no `ExplanationKind` of its own below, since this table is about *direct* findings for a catalog entry, and this strategy's whole point is indirect: its `Replacement::Rewrite` candidate exposes `sum`/`count` as independently bindable discovered targets, which can then earn `CommonSubexpressionReuse` findings when the workload actually reuses them | A dedicated variant would need `findings_from_plan_space` to recognize a `LogicalRewrite`-provenance candidate as a finding in its own right, not just rely on what it exposes downstream |
//! | Semantic-equivalent rewriting (e.g. `avg` → `sum`/`count`) | [`AvgToSumOverCountStrategy`](crate::rewrite::AvgToSumOverCountStrategy) exists and is wired into `default_strategies()` (issue #253) — but still no `ExplanationKind` of its own below, since this table is about *direct* findings for a catalog entry, and this strategy's whole point is indirect: its `Replacement::Rewrite` candidate exposes `sum`/`count` as independently bindable discovered targets, which can then earn `CommonSubexpressionReuse` findings when the workload actually reuses them | A dedicated variant would need `findings_from_candidate_dags` to recognize a `LogicalRewrite`-provenance candidate as a finding in its own right, not just rely on what it exposes downstream |
//! | Roll-ups (fine-to-coarse group-by reuse) | [`RollupStrategy`](crate::rollup::RollupStrategy), derived from workload siblings after CSE/target discovery (issue #254) | Any `Replacement::Rewrite` candidate that rolls a coarse aggregate up from a compatible finer aggregate |
//! | Wavelets/OMP | Params type exists (`WaveletKind`/`WaveletParams`), reachable only via a deployment `CostModel::realize_extension` (no core `AggIntent` dispatch picks it) | A `ReplacementStrategy` that inspects a deployment's own `CostModel`, once some intent shape actually maps to `Realization::Wavelet` |
//! | Sampling | Same story as Wavelets: `SamplingKind`/`SamplingParams` exist, unreachable from core dispatch | Same hook as Wavelets, for `Realization::Sample` |
Expand All @@ -179,7 +179,7 @@
//! [`Replacement::Rewrite`]: crate::replacement::Replacement::Rewrite
//! [`SketchAlgorithmStrategy`]: crate::replacement::SketchAlgorithmStrategy
//! [`SharedSubtreeStrategy`]: crate::replacement::SharedSubtreeStrategy
//! [`PlanSpace`]: crate::replacement::PlanSpace
//! [`CandidatePostASAPDAGs`]: crate::replacement::CandidatePostASAPDAGs
//! [`TargetSubDAGCandidates`]: crate::replacement::TargetSubDAGCandidates

use std::collections::HashMap;
Expand All @@ -191,7 +191,7 @@ use asap_types::pre_asap::cse::{structural_hash, HashCache};
use asap_types::pre_asap::query_expr::QueryExpr;

use crate::replacement::{
self, PlanSpace, Replacement, ReplacementStrategy, TargetSubDAGCandidates,
self, CandidatePostASAPDAGs, Replacement, ReplacementStrategy, TargetSubDAGCandidates,
};

/// Which kind of replacement a [`ReplacementExplanation`] is about.
Expand Down Expand Up @@ -287,7 +287,7 @@ pub fn explain_replacements_with<'s, Id: Display>(
.map(|(id, expr)| (id.to_string(), Rc::new(expr)))
.collect();
let space = replacement::search_workload_with(ided, strategies);
findings_from_plan_space(&space)
findings_from_candidate_dags(&space)
}

/// Translate every discovered [`TargetSubDAGCandidates`] in `space` into zero, one, or two
Expand All @@ -301,7 +301,9 @@ pub fn explain_replacements_with<'s, Id: Display>(
/// so this function (and [`collect_locations`], which formats `id` with
/// [`std::fmt::Debug`] for the breadcrumb text) doesn't need its own generic
/// `Id` bound.
fn findings_from_plan_space(space: &PlanSpace<String>) -> Vec<ReplacementExplanation> {
fn findings_from_candidate_dags(
space: &CandidatePostASAPDAGs<String>,
) -> Vec<ReplacementExplanation> {
let locations = collect_locations(&space.roots);
// One cache for the whole pass, mirroring `dag_export::export`'s own
// `HashCache` reuse — this is a bottom-up pass over every discovered
Expand Down Expand Up @@ -425,7 +427,7 @@ fn is_sketch_realization(node: &SummaryNode) -> bool {
// ── location breadcrumbs ─────────────────────────────────────────────────

/// Build `location` text for every distinct `TargetSubDAG` reachable from
/// `roots` — see the module docs' "One thing `PlanSpace` doesn't carry"
/// `roots` — see the module docs' "One thing `CandidatePostASAPDAGs` doesn't carry"
/// section for why this module needs its own small walk for this. Returns
/// every breadcrumb path that reaches a given `Rc`, not just the first: a
/// shared node referenced from two workload roots (or two branches of one
Expand Down
16 changes: 8 additions & 8 deletions crates/asap-aware-mapping/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@
//!
//! ## Planning workflows
//!
//! Candidate search returns [`PlanSpace`](replacement::PlanSpace), a compact
//! Candidate search returns [`CandidatePostASAPDAGs`](replacement::CandidatePostASAPDAGs), a compact
//! logical choice space with one [`TargetSubDAGCandidates`] per target sub-DAG.
//! [`ReplacementStrategy`] implementations propose local alternatives; search
//! applies the applicable semantic and accuracy checks. Candidate presence does
//! not certify physical deployability or an unknown accuracy guarantee.
//!
//! Integrators choose among these workflows:
//!
//! - Inspect the candidate space, optionally using [`PlanSpace::cost_sorted`]
//! - Inspect the candidate space, optionally using [`CandidatePostASAPDAGs::cost_sorted`]
//! to obtain ranked views, and perform selection downstream.
//! - Call [`PlanSpace::global_selection`] once for the workload, then
//! - Call [`CandidatePostASAPDAGs::global_selection`] once for the workload, then
//! [`GlobalSelection::assemble_selected_dag`] for each query root. This
//! coordinates logical choices and preserves shared nodes, but makes no
//! summary-maintenance lifecycle decision.
Expand Down Expand Up @@ -73,7 +73,7 @@
//! where, reusing the candidate's own rationale rather than inventing new
//! prose), meant for the same downstream consumer (e.g. a
//! DAG-visualization view) the crate doc's planning workflows section above
//! already names for [`replacement::PlanSpace`] itself. Superseded PR
//! already names for [`replacement::CandidatePostASAPDAGs`] itself. Superseded PR
//! #247's own rule-based traversal, which re-walked the tree once per
//! optimization before [`replacement::search_workload`] existed to read
//! from instead — see that module's docs for the full reframing.
Expand Down Expand Up @@ -105,7 +105,7 @@
//! pair under the same grouping, re-divided back by a wrapping `Project`,
//! so those *are* ordinary mergeable accumulators sharing/sketching can
//! reach. It only reshapes; [`replacement::search_workload`]'s cost-based
//! ranking (or a downstream consumer reading [`replacement::PlanSpace`])
//! ranking (or a downstream consumer reading [`replacement::CandidatePostASAPDAGs`])
//! is what decides whether the reshaped form is actually worth picking,
//! the same propose-don't-decide split every other strategy here keeps.
//!
Expand Down Expand Up @@ -208,9 +208,9 @@ pub use recurrence::{
};
pub use replacement::{
default_strategies, default_strategies_with, search_workload, search_workload_with,
search_workload_with_targets, summary_candidates, CompositionDecision, GlobalSelection,
Matcher, PlanSpace, Proposals, RankedTargetSubDAGCandidates, Realization, RealizationError,
RecurrenceProfileMap, RejectedCandidate, Replacement, ReplacementProvenance,
search_workload_with_targets, summary_candidates, CandidatePostASAPDAGs, CompositionDecision,
GlobalSelection, Matcher, Proposals, RankedTargetSubDAGCandidates, Realization,
RealizationError, RecurrenceProfileMap, RejectedCandidate, Replacement, ReplacementProvenance,
ReplacementStrategy, ReplacementSubDAG, SharedSubtreeStrategy, SketchAlgorithmStrategy,
TargetSubDAG, TargetSubDAGCandidates, TargetSubDAGSelection, MAX_SEARCH_ITERATIONS,
};
Expand Down
Loading
Loading