Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
465bd4e
plan-selection: sub-expression memo: groups and Pass 1 candidates, ca…
zzylol Oct 22, 2026
2606697
plan-selection: sub-expression memo candidates read child group nodes…
zzylol Oct 22, 2026
ac5270d
plan-selection: sub-expression memo scan widening and raw-horizon sites
zzylol Oct 22, 2026
cfdb07f
plan-selection: sub-expression memo: exact-input and rollup requireme…
zzylol Oct 22, 2026
42dc762
Merge W1 (budget shares, pointer children, topological order) and W4 …
zzylol Oct 22, 2026
204dc5e
Merge remote-tracking branch 'origin/feat/memo-sx-w3' into feat/memo-sx
zzylol Oct 22, 2026
1152ad1
Merge W3 (per-metric scan widening, raw horizon sites); memo stats ho…
zzylol Oct 22, 2026
caf914c
Merge remote-tracking branch 'origin/main' into feat/memo-sx
zzylol Oct 22, 2026
9292ed3
plan-selection: Stage 3 prices one node at a time (price_node)
zzylol Oct 22, 2026
9a70f64
plan-selection: sub-expression memo: shared builds over equal input g…
zzylol Oct 22, 2026
115ea2f
plan-selection: sub-expression memo: a coarser grouping reads a finer…
zzylol Oct 22, 2026
6bf7c26
plan-selection: sub-expression memo Pass 1 parity test; top-k roots k…
zzylol Oct 22, 2026
10112d3
memo: reference brute-force search over the memo, behind memo_groups;…
zzylol Oct 22, 2026
c13db44
Merge remote-tracking branch 'origin/feat/memo-sx-w3' into feat/memo-sx
zzylol Oct 22, 2026
c160f4f
Merge W4 (rollup windows, requires_sites, resize builder)
zzylol Oct 22, 2026
27a7fa1
Merge remote-tracking branch 'origin/feat/memo-sx-w1' into feat/memo-sx
zzylol Oct 22, 2026
0c4f61e
Merge W1 (fused heap candidates keep their schema, Pass 1 parity test…
zzylol Oct 22, 2026
ecd42bf
memo: debugging test for a top-k memo
zzylol Oct 22, 2026
d220e45
physical: materialization_slots, the options a search chooses per mat…
zzylol Oct 22, 2026
f8bcdba
plan-selection: price a memo candidate's private nodes in its consume…
zzylol Oct 22, 2026
323c49f
plan-selection: sub-expression memo: shared builds resized at a size …
zzylol Oct 22, 2026
71e03d5
plan-selection: memo plans compose every node's guarantee again; Pass…
zzylol Oct 22, 2026
436cad4
plan-selection: memo reference search composes guarantees again over …
zzylol Oct 22, 2026
5fbea05
Merge remote-tracking branch 'origin/feat/memo-sx-w4' into feat/memo-sx
zzylol Oct 22, 2026
87916ff
Merge remote-tracking branch 'origin/feat/memo-sx-w1' into feat/memo-sx
zzylol Oct 22, 2026
476f953
Merge W2 (private-node pricing in a consumer context)
zzylol Oct 22, 2026
6c3c2e8
Merge W3 (shared builds resized at a threshold)
zzylol Oct 22, 2026
57fe7eb
plan-selection: depend on good_lp 1.15.3 with the HiGHS backend (MIT)…
zzylol Oct 22, 2026
0ba55f1
memo: MILP model over memo choices (reach, built-once groups, union r…
zzylol Oct 22, 2026
25098ff
plan-selection: memo reference search composes each query's own nodes…
zzylol Oct 22, 2026
c364c22
plan-selection: the selection report carries the memo's size (SearchR…
zzylol Oct 22, 2026
243b64c
docs: the planning stages over a memo of sub-expressions; memo module…
zzylol Oct 22, 2026
ea6ff41
plan-selection: fix a stale doc link in the memo types
zzylol Oct 22, 2026
67a18d4
devtools: stage_pipeline --search legacy|memo-brute-force; drop the d…
zzylol Oct 22, 2026
434fcbb
Merge origin/main into the memo (PR-A): port the facts-only pricing (…
zzylol Oct 22, 2026
5e553b8
plan-selection: memo choices and their MILP coefficients from Stage 3…
zzylol Oct 22, 2026
338325d
plan-selection: SearchAlgorithm setting, MILP stub, search report fie…
zzylol Oct 22, 2026
2f03791
Merge W2 (choice coefficients) onto PR-A
zzylol Oct 22, 2026
3f8a2ce
Merge W5 (SearchAlgorithm setting, --search, three-way harness) onto …
zzylol Oct 22, 2026
3ffb741
Memo MILP search: lazy loop over the model with exact pricing of each…
zzylol Oct 22, 2026
2a1bca0
wip: memo choices shared or apart per group, scan children apart or s…
zzylol Oct 22, 2026
f901bde
Memo MILP search: report the model size, the first round's bound and …
zzylol Oct 22, 2026
0753935
plan-selection: a fused memo candidate absorbs only groups no other r…
zzylol Oct 22, 2026
f8f5864
Merge origin/main into the memo (PR-A): port the label-set group boun…
zzylol Oct 22, 2026
c8e3d31
plan-selection: memo choices shared or apart, shared-node and scan-ho…
zzylol Oct 22, 2026
e2fe286
Merge remote-tracking branch 'origin/feat/memo-sx-w2-wip' into feat/m…
zzylol Oct 22, 2026
633c82e
Memo MILP model: shared choices only (a lower bound on a group's copi…
zzylol Oct 22, 2026
6221632
Memo MILP model: requirements and pane/top-k exclusivity as constrain…
zzylol Oct 22, 2026
e4a6859
plan-selection: the memo search lists sketch rollups of a shared fine…
zzylol Oct 22, 2026
470feed
Memo MILP model: aggregated reach constraints and linear floors on ra…
zzylol Oct 22, 2026
fe1b310
plan-selection: a reader's choice at a shared scan's horizon only whe…
zzylol Oct 22, 2026
8ea3ee1
Restore the MILP model's tight relaxation, which the horizon fix's re…
zzylol Oct 22, 2026
a64198f
Memo MILP search: a no-good cut excludes only its own group choice (a…
zzylol Oct 22, 2026
0ca9835
plan-selection: memo MILP encodes the rollup requirements as constraints
zzylol Oct 22, 2026
1f1b77a
Merge remote-tracking branch 'origin/feat/memo-pr-a' into feat/memo-pr-b
zzylol Oct 22, 2026
fee0594
plan-selection: memo shared-node coefficients are disjoint
zzylol Oct 22, 2026
fcabf39
Restore the MILP model's tight relaxation, cut form and lower-bound c…
zzylol Oct 22, 2026
7694939
plan-selection: memo choices at a sketch rollup's state-size thresholds
zzylol Oct 22, 2026
6769081
Memo MILP model: held memory over each query's query-time latency (li…
zzylol Oct 22, 2026
56759e0
Memo MILP search: cut off plans the model prices at or above the incu…
zzylol Oct 22, 2026
3f8706a
Memo search review fixes: name the selected logical candidate, drop u…
zzylol Oct 22, 2026
a4bea41
Memo MILP search: a time limit that reports its gap and is never call…
zzylol Oct 22, 2026
5578cac
Test the MILP search's time limit report and its argument check
zzylol Oct 22, 2026
ce875c1
Merge remote-tracking branch 'origin/feat/memo-pr-a' into tmp-restore
zzylol Oct 22, 2026
f4c2ea0
Merge remote-tracking branch 'origin/main' into tmp-restore
zzylol Oct 22, 2026
f152a47
Restore the stage_pipeline facts flags and the default-search helper …
zzylol Oct 22, 2026
f02f24d
Memo MILP: no absolute MIP gap; a solve stopped within the solver's g…
zzylol Oct 23, 2026
34bb909
Memo MILP: raw windows computed once per memo; a time-limited solve's…
zzylol Oct 23, 2026
700a4d0
Memo MILP report: incumbent_cost, model_bound, gap, rounds, model_var…
zzylol Oct 23, 2026
b73c99f
Selection report: incumbent_cost for every search; the MILP's lower b…
zzylol Oct 23, 2026
43afd7a
plan-selection: memo MILP stays a lower bound with shared slots and w…
zzylol Oct 22, 2026
7dc270e
plan-selection: memo MILP lower bound across groups and rollups
zzylol Oct 22, 2026
7381e32
plan-selection: memo shared slots and nodes keyed exactly, up to scan…
zzylol Oct 23, 2026
96ad7ef
plan-selection: memo shareable nodes leave scans to the scan choices
zzylol Oct 23, 2026
fe387fc
plan-selection: memo nodes equal up to scan widening charged once acr…
zzylol Oct 23, 2026
30aed58
plan-selection: memo cross-group nodes at min(per consumer, once); sl…
zzylol Oct 23, 2026
df2427d
plan-selection: memo consumers exist only with their choice or built-…
zzylol Oct 23, 2026
5e4c084
Regenerate the viewer fixtures for the search report's incumbent_cost
zzylol Oct 23, 2026
48e3057
plan-selection: memo MILP prices scaled per evaluation; held memory a…
zzylol Oct 23, 2026
85ba121
Merge remote-tracking branch 'origin/w2-lower-bound' into tmp-restore
zzylol Oct 23, 2026
123974c
Memo MILP MVP: drop the debugging environment hooks; a quick three-wa…
zzylol Oct 23, 2026
bbb4b1e
Merge remote-tracking branch 'origin/main' into feat/memo-milp-mvp
zzylol Oct 23, 2026
2b87f3d
stage_pipeline tests: per-call names for the mixed workload files, wh…
zzylol Oct 23, 2026
3ef44df
Memo MILP: no safety-net cuts outside the reference evaluation; a sol…
zzylol Oct 23, 2026
e45c42c
Restore runtime_install.rs, which an earlier merge truncated
zzylol Oct 23, 2026
d85fd45
Merge remote-tracking branch 'origin/main' into feat/memo-milp-mvp
zzylol Oct 23, 2026
a1f1a62
Memo MILP: identical scans and same-class query consumers charged once
zzylol Oct 23, 2026
f6af182
Memo MILP: scans read by a node built once or a slot at the union rate
zzylol Oct 23, 2026
848b0ee
Merge remote-tracking branch 'origin/main' into feat/memo-pr-b
zzylol Oct 23, 2026
231790c
Merge remote-tracking branch 'origin/main' into feat/memo-pr-b
zzylol Oct 23, 2026
4cb81fd
Memo MILP: a query's latency counts each node it computes once per no…
zzylol Oct 23, 2026
310a22e
plan-selection: memo MILP per independent cluster
zzylol Oct 23, 2026
973e164
plan-selection: memo MILP cluster solves take their time limit when t…
zzylol Oct 23, 2026
9b92577
plan-selection: drop a duplicated comment
zzylol Oct 23, 2026
4eb53c6
plan-selection: memo MILP requires child choices that keep each choic…
zzylol Oct 22, 2026
6fa2e64
plan-selection: memo MILP rules out root choices whose guarantee is i…
zzylol Oct 23, 2026
ecee483
plan-selection: memo MILP accuracy rules skip exact compositions and …
zzylol Oct 23, 2026
951265c
plan-selection: memo MILP failure-probability rule reads summaries at…
zzylol Oct 23, 2026
9038846
plan-selection: memo MILP accuracy rule treats a guarantee lost only …
zzylol Oct 23, 2026
d990e77
plan-selection: test that a guarantee lost only at the largest summar…
zzylol Oct 23, 2026
42c1bba
plan-selection: memo rollup rules compute each coarse build's source …
zzylol Oct 23, 2026
ebb932a
Memo MILP: solution decoding and incumbent evaluation per round
zzylol Oct 23, 2026
4551708
Memo MILP decoding: exact bound for unevaluated plans, built-once fid…
zzylol Oct 23, 2026
e33e594
plan-selection: memo MILP charges parts under an ingestion-time slot …
zzylol Oct 23, 2026
e7703d4
plan-selection: memo MILP charges ingestion-time inputs once per shar…
zzylol Oct 23, 2026
b3cb995
plan-selection: memo MILP held-memory share over a node's readers in …
zzylol Oct 23, 2026
b70496e
plan-selection: memo MILP warm-start incumbent from per-query plans
zzylol Oct 23, 2026
8481311
plan-selection: memo MILP keeps the solver's proven bound from a solv…
zzylol Oct 23, 2026
fd4f0c7
plan-selection: the solver's proven bound is lowered by its tolerance
zzylol Oct 23, 2026
9a52388
plan-selection: the memo's rollup-window rule builds only the pair's …
zzylol Oct 23, 2026
72a873a
test: compare the shared-chain candidates' roots
zzylol Oct 23, 2026
4110bbe
plan-selection: memo MILP held-memory share for readers in classes no…
zzylol Oct 23, 2026
532e6cb
Memo MILP: incumbent cutoff within the solver's tolerance; reach as f…
zzylol Oct 23, 2026
5b1dcb9
Merge remote-tracking branch 'origin/fix/memo-union-rate-classes' int…
zzylol Oct 23, 2026
9f10e65
Merge remote-tracking branch 'origin/feat/memo-pr-b' into feat/memo-pr-b
zzylol Oct 23, 2026
395d1a4
plan-selection: memo MILP reach flows count a child listed twice in o…
zzylol Oct 23, 2026
a1da0ce
plan-selection: memo MILP reports the cutoff's and the solver's toler…
zzylol Oct 23, 2026
c7c1b97
Memo MILP: term cuts for a source's scans, held memory and ingestion …
zzylol Oct 23, 2026
594629b
Memo MILP term cuts: test certification within the certified gap
zzylol Oct 23, 2026
04151ce
Memo MILP term cuts: only existing variables, query-time scan labels,…
zzylol Oct 23, 2026
20bac10
Merge remote-tracking branch 'origin/main' into merge/memo-pr-b
zzylol Oct 23, 2026
0f8bf09
stage_pipeline tests: a certified MILP gap is within the search's 1e-…
zzylol Oct 23, 2026
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 14 additions & 7 deletions crates/devtools/tests/stage_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,9 @@ fn search_flag_picks_the_search_algorithm() {
assert!(report.get("routed_to_legacy").is_none(), "{report}");
let milp_report = &report["milp"];
assert!(milp_report["rounds"].as_u64().unwrap() >= 1, "{report}");
assert!(milp_report["gap"].as_f64().unwrap() <= 1e-9, "{report}");
// Certified: the gap is within the search's tolerance (1e-4), which
// also absorbs the solver's and the incumbent cutoff's tolerances.
assert!(milp_report["gap"].as_f64().unwrap() <= 1e-4, "{report}");
assert!(
milp_report["lower_bound"].as_f64().unwrap() <= price(&milp) * (1.0 + 1e-9),
"{report}"
Expand Down Expand Up @@ -1789,8 +1791,9 @@ fn search_flag_is_checked() {
assert!(stderr.contains("drop it with --exhaustive"), "{stderr}");
}

/// The MILP search stopped by its time limit before any valid plan says
/// so (never a plan called optimal), and the limit needs the MILP search.
/// The MILP search stopped by its time limit before its first round
/// returns the warm-start plan (each query planned alone) with its gap,
/// never called optimal, and the limit needs the MILP search.
#[test]
fn milp_time_limit_is_reported_and_needs_the_milp_search() {
let document = document_of(&[
Expand All @@ -1802,11 +1805,15 @@ fn milp_time_limit_is_reported_and_needs_the_milp_search() {
"0",
]);
let selection = &document["stage3_plan_selection"];
assert!(selection["selected"].is_null(), "{selection}");
assert!(selection["selected"].is_string(), "{selection}");
let milp = &selection["search"]["milp"];
assert_eq!(milp["time_limit_reached"], true, "{selection}");
assert_eq!(milp["rounds"], 0, "{selection}");
let gap = milp["gap"].as_f64().unwrap();
assert!(gap > 1e-4 && gap <= 1.0, "{selection}");
assert!(
selection["error"]
.as_str()
.is_some_and(|e| e.contains("reached its time limit")),
milp["lower_bound"].as_f64().unwrap()
<= selection["search"]["incumbent_cost"].as_f64().unwrap(),
"{selection}"
);
let (_, stderr) = failure(&[
Expand Down
194 changes: 193 additions & 1 deletion crates/integration-tests/tests/joint_search_equivalence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ use asap_types::workload::{
};
use planner_layering_common::*;

/// The largest gap a certified search reports (the planner's
/// `GAP_TOLERANCE`): the solver's own tolerances.
const CERTIFIED_GAP: f64 = 1e-4;

/// Every cost model, each objective of cost model 3 included, with
/// `memory_gb` of cluster memory: small enough that some candidates do not
/// fit, so the limits are exercised too.
Expand Down Expand Up @@ -1486,7 +1490,9 @@ fn three_way(
.as_ref()
.and_then(|milp| milp.gap)
.expect("the MILP reports its gap");
if gap.abs() > 1e-9 {
// Certified: within the solver's tolerances (the planner's
// GAP_TOLERANCE), never reported as exactly 0 unless proven.
if gap.abs() > CERTIFIED_GAP {
return Err(format!("{label}: MILP gap {gap}"));
}
Ok(true)
Expand Down Expand Up @@ -1573,6 +1579,63 @@ fn assert_three_way_on_seeds(
assert!(mismatches.is_empty(), "{}", mismatches.join("\n"));
}

/// Queries over two gauges, two per gauge, are two independent clusters of
/// the memo, each searched with its own MILP and lazy loop: with raw data
/// kept and without, the MILP reports both clusters, each certified, and
/// the three searches select plans of one price.
#[test]
fn three_way_on_two_independent_clusters() {
let mut workload = random_workload_over(3, &["m", "n"]);
let queries = [
"quantile_over_time(0.9, m[5m])",
"sum_over_time(m[1m])",
"max_over_time(n[5m])",
"quantile_over_time(0.99, n[10m])",
];
workload.query_workload.repeating_queries = workload_of(
&queries.map(|q| (q, 60_000)),
AccuracyTarget::max_error(0.05),
)
.query_workload
.repeating_queries;
let roots = lower_promql_roots(&workload).unwrap();
let entries: Vec<_> = workload.query_workload.entries().collect();
let data = workload.data_workload.clone().unwrap();
for deployment in [
asap_logical_asap_optimization::DeploymentCapabilities::default(),
no_raw_data(),
] {
let models = PlanningModels::builtin().with_deployment_capabilities(&deployment);
let label = format!("raw data retained {}", deployment.raw_data_retained);
assert!(
assert_three_way(&label, &roots, &entries, &data, models),
"{label}"
);
let run = run_stage1_to_stage3_with(
roots.iter().cloned().enumerate().collect(),
&entries,
&data,
models,
Stage1ToStage3Search::with_algorithm(SearchAlgorithm::MemoMilp),
)
.unwrap();
let milp = run.stage3_plan_selection.unwrap().search.milp.unwrap();
let clusters: Vec<_> = milp.clusters.iter().map(|c| c.queries.clone()).collect();
assert_eq!(clusters, [vec![0, 1], vec![2, 3]], "{label}");
assert!(
milp.clusters
.iter()
.all(|c| c.gap.is_some_and(|gap| gap <= CERTIFIED_GAP)),
"{label}: {milp:?}"
);
assert_eq!(
milp.rounds,
milp.clusters.iter().map(|c| c.rounds).sum::<u32>(),
"{label}"
);
}
}

/// The three searches agree on the random workloads under cost model 1.
#[test]
#[ignore = "the exhaustive search and the brute force over every seed take minutes in a debug build; run with --release --ignored"]
Expand Down Expand Up @@ -1843,6 +1906,76 @@ fn a_sketch_rollup_beside_other_quantiles_selects_the_exhaustive_price() {
assert_memo_selects_the_exhaustive_price("Q2, Q3, Q4", &workload(&[q2, q3, q4]));
}

/// #839's workload (two 10-minute sums every 20 s, two 100-second
/// quantiles of one metric at different label sets every second): the
/// cheapest plan widens the quantiles' scans to one label set and shares
/// one scan. With its term cuts (a source's scans apart or widened, held
/// memory, ingestion copies) the memo MILP certifies the memo brute
/// force's price.
#[test]
fn term_cuts_certify_the_brute_force_price_on_839() {
let entries: Vec<serde_json::Value> = [
(
"sum by (region, service, job) (sum_over_time(m[10m]))",
20000,
),
("sum by (region, service) (sum_over_time(m[10m]))", 20000),
(
"avg by (region, service, job) (quantile_over_time(0.99, m[100s]))",
1000,
),
("avg by (region) (quantile_over_time(0.95, m[100s]))", 1000),
]
.iter()
.map(|(q, interval)| {
serde_json::json!({
"query": q,
"demand": {"fixed_interval": interval},
"requirements": {"accuracy": {"max_error": 0.05, "failure_probability": 0.3}},
"predictability": {"predictable": {"known_at": null}}
})
})
.collect();
let workload: PlanningWorkload = serde_json::from_value(serde_json::json!({
"query_workload": {"language": "promql", "query_batch": null, "repeating_queries": entries},
"data_workload": {
"arrival": {"ingesting": {"rows_per_second": 100000.0}},
"sources": {"m": {"series_count": 10000, "metric_type": "gauge", "values_non_negative": true, "sample_interval": 100}}
}
}))
.unwrap();
let roots = lower_promql_roots(&workload).unwrap();
let entries: Vec<_> = workload.query_workload.entries().collect();
let data = workload.data_workload.clone().unwrap();
let models = PlanningModels::builtin();
let run = |search| {
run_stage1_to_stage3_with(
roots.iter().cloned().enumerate().collect(),
&entries,
&data,
models,
search,
)
.unwrap()
.stage3_plan_selection
.unwrap()
};
let brute_force = run(Stage1ToStage3Search::with_algorithm(
SearchAlgorithm::MemoBruteForce,
));
let milp = run(Stage1ToStage3Search::with_algorithm(
SearchAlgorithm::MemoMilp,
));
let price = |s: &asap_plan_selection::Selection| s.costs[&s.selected].cost_per_second.unwrap();
let (b, m) = (price(&brute_force), price(&milp));
assert!(
(b - m).abs() <= 1e-9 * b,
"memo brute force {b}, memo MILP {m}"
);
let gap = milp.search.milp.and_then(|milp| milp.gap);
assert!(gap.is_some_and(|gap| gap <= CERTIFIED_GAP), "gap {gap:?}");
}

/// Debugging aid: the random workload of seed `JP_SEED` (over the gauge
/// `m`) as stage_pipeline's `--workload` JSON, at `JP_SEED_OUT`.
#[test]
Expand All @@ -1853,3 +1986,62 @@ fn dump_random_workload() {
let workload = random_workload(seed);
std::fs::write(&out, serde_json::to_string_pretty(&workload).unwrap()).unwrap();
}

/// With no time left for a single MILP round, memo-milp still returns a
/// plan: the warm-start incumbent, each query planned alone by the legacy
/// search with no sharing, offered before round 1. Under cost model 1 its
/// cost is the sum of the queries' own plans' costs, and the run reports
/// the time limit and a gap to the MILP lower bound.
#[test]
fn a_time_limited_memo_milp_run_returns_the_warm_start_plan() {
let queries = [
"quantile_over_time(0.9, m[5m])",
"sum_over_time(m[1m])",
"quantile_over_time(0.99, m[10m])",
];
let workload = workload_of(
&queries.map(|q| (q, 60_000)),
AccuracyTarget::max_error(0.05),
);
let roots = lower_promql_roots(&workload).unwrap();
let entries: Vec<_> = workload.query_workload.entries().collect();
let data = workload.data_workload.clone().unwrap();
let models = PlanningModels::builtin();
let alone: f64 = roots
.iter()
.zip(&entries)
.map(|(root, entry)| {
let run = run_stage1_to_stage3_with(
vec![(0, root.clone())],
std::slice::from_ref(entry),
&data,
models,
Stage1ToStage3Search::default(),
)
.unwrap();
let selection = run.stage3_plan_selection.unwrap();
selection.costs[&selection.selected]
.cost_per_second
.unwrap()
})
.sum();
let run = run_stage1_to_stage3_with(
roots.iter().cloned().enumerate().collect(),
&entries,
&data,
models,
Stage1ToStage3Search {
milp_time_limit_ms: Some(0),
..Stage1ToStage3Search::with_algorithm(SearchAlgorithm::MemoMilp)
},
)
.unwrap();
let selection = run.stage3_plan_selection.unwrap();
assert_eq!(selection.selected, "P0");
let cost = selection.search.incumbent_cost.unwrap();
assert!((cost - alone).abs() <= 1e-9 * alone, "{cost} vs {alone}");
let milp = selection.search.milp.unwrap();
assert!(milp.time_limit_reached, "{milp:?}");
assert!(milp.gap.is_some(), "{milp:?}");
assert!(run.stage3_selected_logical.is_some());
}
6 changes: 6 additions & 0 deletions crates/integration-tests/tests/tumbling_pane_merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use asap_integration_tests::fixtures::lower_promql;
use asap_integration_tests::planning::selected_dag;
use asap_logical_asap_optimization::asap_aware_cse::{
pane_candidates, window_composition_pass2_candidates,
window_composition_shared_chain_candidates,
};
use asap_types::ir::operator::operator_properties::TimeShift;
use asap_types::ir::operator::pane_chain::expand_pane_chains;
Expand Down Expand Up @@ -854,6 +855,11 @@ fn queries_at_different_intervals_read_one_chain_of_the_finer_panes() {
.into_iter()
.find(|c| c.pane_candidates.len() == 2 && !c.shared_chains.is_empty())
.expect("one shared chain");
// The whole set's shared chains, built alone, are the same candidates.
let alone = window_composition_shared_chain_candidates(&roots, &rule_candidates);
let first = alone.first().expect("one shared chain alone");
assert_eq!(first.shared_chains, shared.shared_chains);
assert_eq!(first.roots.as_ref().ok(), shared.roots.as_ref().ok());
assert_eq!(
(
shared.shared_chains[0].pane_width_ms,
Expand Down
Loading
Loading