From 008f6d40d8837cb376cf76bfa46bf1ea70ae282b Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Tue, 10 Nov 2026 10:41:42 +0100 Subject: [PATCH 01/19] DDIR: lowering treats arranged imports as arranged Trace imports, and parent imports of arranged parent items, are no longer wrapped in another Arrange, so printed plans replan identically with passes off. Co-Authored-By: Claude Opus 5.5 --- interactive/src/lower.rs | 58 ++++++++++++++++--- interactive/src/reducers.rs | 15 +++-- .../access_shared.lowered--optimized.diff | 12 ++-- .../access_shared.parsed--lowered.diff | 8 +-- .../plan_pairs/expected/as_of_shared.ddp | 5 +- .../as_of_shared.lowered--optimized.diff | 12 ---- .../as_of_shared.parsed--lowered.diff | 8 +-- .../as_of_shared.projected--as-of.diff | 9 ++- .../plan_pairs/expected/as_of_strict.ddp | 3 +- .../as_of_strict.parsed--lowered.diff | 5 +- .../as_of_strict.projected--as-of.diff | 4 +- .../plan_pairs/expected/ldbc_ic01_oneoff.ddp | 34 +++++------ .../ldbc_ic01_oneoff.lowered--optimized.diff | 53 +++++------------ .../ldbc_ic01_oneoff.parsed--lowered.diff | 41 +++++-------- .../plan_pairs/expected/ldbc_ic02_oneoff.ddp | 18 ++---- .../ldbc_ic02_oneoff.lowered--optimized.diff | 6 +- .../ldbc_ic02_oneoff.parsed--lowered.diff | 20 +++---- .../plan_pairs/expected/ldbc_ic03_oneoff.ddp | 25 ++++---- .../ldbc_ic03_oneoff.lowered--optimized.diff | 42 ++++---------- .../ldbc_ic03_oneoff.parsed--lowered.diff | 32 ++++------ .../plan_pairs/expected/ldbc_ic04_oneoff.ddp | 9 +-- .../ldbc_ic04_oneoff.lowered--optimized.diff | 6 +- ...ldbc_ic04_oneoff.optimized--projected.diff | 2 +- .../ldbc_ic04_oneoff.parsed--lowered.diff | 11 ++-- .../expected/ldbc_ic04_standing.ddp | 4 +- ...ldbc_ic04_standing.lowered--optimized.diff | 6 +- .../ldbc_ic04_standing.parsed--lowered.diff | 11 ++-- .../plan_pairs/expected/ldbc_ic05_oneoff.ddp | 23 +++----- .../ldbc_ic05_oneoff.lowered--optimized.diff | 22 +++---- .../ldbc_ic05_oneoff.parsed--lowered.diff | 26 +++------ .../plan_pairs/expected/ldbc_ic06_oneoff.ddp | 23 +++----- .../ldbc_ic06_oneoff.lowered--optimized.diff | 14 ++--- .../ldbc_ic06_oneoff.parsed--lowered.diff | 26 +++------ .../plan_pairs/expected/ldbc_ic07_oneoff.ddp | 15 ++--- ...ldbc_ic07_oneoff.optimized--projected.diff | 12 ++-- .../ldbc_ic07_oneoff.parsed--lowered.diff | 17 ++---- .../plan_pairs/expected/ldbc_ic08_oneoff.ddp | 14 ++--- .../ldbc_ic08_oneoff.lowered--optimized.diff | 12 +--- .../ldbc_ic08_oneoff.parsed--lowered.diff | 17 ++---- .../plan_pairs/expected/ldbc_ic09_oneoff.ddp | 22 +++---- .../ldbc_ic09_oneoff.lowered--optimized.diff | 24 ++------ ...ldbc_ic09_oneoff.optimized--projected.diff | 4 +- .../ldbc_ic09_oneoff.parsed--lowered.diff | 26 +++------ .../plan_pairs/expected/ldbc_ic10_oneoff.ddp | 17 ++---- .../ldbc_ic10_oneoff.lowered--optimized.diff | 13 ++--- ...ldbc_ic10_oneoff.optimized--projected.diff | 2 +- .../ldbc_ic10_oneoff.parsed--lowered.diff | 20 +++---- .../expected/ldbc_ic10_standing.ddp | 3 +- ...ldbc_ic10_standing.lowered--optimized.diff | 5 +- .../ldbc_ic10_standing.parsed--lowered.diff | 5 +- .../plan_pairs/expected/ldbc_ic11_oneoff.ddp | 19 +++--- .../ldbc_ic11_oneoff.lowered--optimized.diff | 19 ++---- .../ldbc_ic11_oneoff.parsed--lowered.diff | 23 +++----- .../plan_pairs/expected/ldbc_ic12_oneoff.ddp | 27 +++------ .../ldbc_ic12_oneoff.lowered--optimized.diff | 13 ++--- .../ldbc_ic12_oneoff.parsed--lowered.diff | 29 ++++------ ...ldbc_ic12_standing.lowered--optimized.diff | 8 +-- .../ldbc_ic12_standing.parsed--lowered.diff | 5 +- .../ldbc_ic13_oneoff.lowered--optimized.diff | 10 +--- .../ldbc_ic13_oneoff.parsed--lowered.diff | 5 +- .../plan_pairs/expected/ldbc_ic14_oneoff.ddp | 3 +- .../ldbc_ic14_oneoff.lowered--optimized.diff | 22 +------ .../ldbc_ic14_oneoff.parsed--lowered.diff | 11 ++-- .../expected/ldbc_ic14_standing.ddp | 6 +- ...ldbc_ic14_standing.lowered--optimized.diff | 4 +- .../ldbc_ic14_standing.parsed--lowered.diff | 8 +-- .../tests/plan_pairs/expected/ldbc_is01.ddp | 3 +- .../expected/ldbc_is01.parsed--lowered.diff | 5 +- .../tests/plan_pairs/expected/ldbc_is02.ddp | 16 ++--- .../ldbc_is02.lowered--optimized.diff | 16 ----- .../expected/ldbc_is02.parsed--lowered.diff | 20 +++---- .../tests/plan_pairs/expected/ldbc_is03.ddp | 6 +- .../ldbc_is03.lowered--optimized.diff | 4 +- .../expected/ldbc_is03.parsed--lowered.diff | 8 +-- .../tests/plan_pairs/expected/ldbc_is04.ddp | 3 +- .../expected/ldbc_is04.parsed--lowered.diff | 5 +- .../tests/plan_pairs/expected/ldbc_is05.ddp | 6 +- .../expected/ldbc_is05.parsed--lowered.diff | 8 +-- .../tests/plan_pairs/expected/ldbc_is06.ddp | 12 ++-- .../expected/ldbc_is06.parsed--lowered.diff | 14 ++--- .../tests/plan_pairs/expected/ldbc_is07.ddp | 14 ++--- .../ldbc_is07.lowered--optimized.diff | 16 ++--- .../ldbc_is07.optimized--projected.diff | 6 +- .../expected/ldbc_is07.parsed--lowered.diff | 17 ++---- .../tests/plan_pairs/expected/txn_resolve.ddp | 5 +- .../txn_resolve.lowered--optimized.diff | 15 +---- .../txn_resolve.optimized--projected.diff | 2 +- .../expected/txn_resolve.parsed--lowered.diff | 9 +-- .../expected/txn_resolve_by_key.ddp | 5 +- ...txn_resolve_by_key.lowered--optimized.diff | 17 +----- .../txn_resolve_by_key.parsed--lowered.diff | 11 ++-- 91 files changed, 461 insertions(+), 815 deletions(-) diff --git a/interactive/src/lower.rs b/interactive/src/lower.rs index 7ff7c21def..f83f8148a2 100644 --- a/interactive/src/lower.rs +++ b/interactive/src/lower.rs @@ -298,8 +298,20 @@ fn collect_body_references(body: &[Stmt], out: &mut BTreeSet) { use crate::scope_ir as st; -pub(crate) fn is_arranged(input: &st::Ref, items: &[st::Item]) -> bool { - matches!(input, st::Ref::Local(i) if matches!(&items[*i], st::Item::Op(st::Node::Arrange(_) | st::Node::Reduce { .. }))) +/// Whether `input` is already an arrangement. A local item is one when it is an +/// arrange or a reduce. An import is one when it names a trace, or when it enters +/// a parent item that is itself arranged (`parent_arranged`, indexed by import id). +/// Input imports are collections. +pub(crate) fn is_arranged(input: &st::Ref, items: &[st::Item], imports: &[st::Import], parent_arranged: &[bool]) -> bool { + match input { + st::Ref::Local(i) => matches!(&items[*i], st::Item::Op(st::Node::Arrange(_) | st::Node::Reduce { .. })), + st::Ref::Import(i) => match &imports[*i].from { + st::Source::Trace(_) => true, + st::Source::Parent(_) => parent_arranged[*i], + st::Source::Input(_) => false, + }, + _ => false, + } } pub fn lower_tree(mut stmts: Vec) -> st::Program { @@ -311,9 +323,9 @@ pub fn lower_tree(mut stmts: Vec) -> st::Program { resolve_body(&mut stmts, &[], &scopes, &mut plan); let empty = HashMap::new(); let mut distinct = HashMap::new(); - let mut program = st::Program { root: lower_scope_tree(&[], &stmts, &empty, &[], &plan, true, &mut distinct) }; + let mut program = st::Program { root: lower_scope_tree(&[], &stmts, &empty, &[], &plan, true, None, &mut distinct) }; let (shapes, _) = crate::shapes::infer(&program, &|_| None, 1); - crate::reducers::expand_distinct(&mut program.root, &shapes, &distinct, &mut Vec::new()); + crate::reducers::expand_distinct(&mut program.root, &shapes, &distinct, &[], &mut Vec::new()); program } @@ -328,6 +340,8 @@ struct ScopeLower { /// The statement being lowered, which names the items it pushes. statement: String, imports: Vec, + /// Per import, whether it enters an arranged item of the parent scope. + parent_arranged: Vec, input_import: HashMap, // input n -> import idx (root, deduped) trace_import: HashMap, // trace name -> import idx (root, deduped) env: HashMap, // local names, qualified child exports, and imports @@ -341,7 +355,7 @@ impl ScopeLower { st::Ref::Local(i) } fn arrange(&mut self, input: st::Ref) -> st::Ref { - if is_arranged(&input, &self.items) { input } + if is_arranged(&input, &self.items, &self.imports, &self.parent_arranged) { input } else { self.push(st::Node::Arrange(input)) } } /// Input `n`, named as written (`input "name"`), or `input{n}` if it is unnamed. @@ -351,6 +365,7 @@ impl ScopeLower { let i = self.imports.len(); let name = name.map_or_else(|| format!("input{n}"), str::to_string); self.imports.push(st::Import { name, from: st::Source::Input(n), shape: None }); + self.parent_arranged.push(false); self.input_import.insert(n, i); st::Ref::Import(i) } @@ -359,6 +374,7 @@ impl ScopeLower { if let Some(&i) = self.trace_import.get(name) { return st::Ref::Import(i); } let i = self.imports.len(); self.imports.push(st::Import { name: name.to_string(), from: st::Source::Trace(name.to_string()), shape: None }); + self.parent_arranged.push(false); self.trace_import.insert(name.to_string(), i); st::Ref::Import(i) } @@ -424,6 +440,7 @@ fn lower_scope_tree( exports_wanted: &[PathKey], plan: &PathPlan, is_root: bool, + parent: Option<&ScopeLower>, distinct: &mut HashMap, Vec>, ) -> st::Scope { let scope_name = scope_label(address); @@ -434,6 +451,7 @@ fn lower_scope_tree( labels: Vec::new(), statement: String::new(), imports: Vec::new(), + parent_arranged: Vec::new(), input_import: HashMap::new(), trace_import: HashMap::new(), env: HashMap::new(), @@ -453,6 +471,7 @@ fn lower_scope_tree( RefName::Path(key) => panic!("path `{}` is unavailable in scope `{scope_name}`", key.display()), }); let i = s.imports.len(); + s.parent_arranged.push(parent.is_some_and(|p| is_arranged(&from, &p.items, &p.imports, &p.parent_arranged))); s.imports.push(st::Import { name: match &name { RefName::Plain(n) => n.clone(), RefName::Path(key) => key.display(), @@ -558,7 +577,7 @@ fn lower_scope_tree( let mut child_address = address.to_vec(); child_address.push(name.clone()); let wanted: Vec = plan.exports.get(&child_address).into_iter().flatten().cloned().collect(); - let child = lower_scope_tree(&child_address, b, &s.env, &wanted, plan, false, distinct); + let child = lower_scope_tree(&child_address, b, &s.env, &wanted, plan, false, Some(&s), distinct); let slots = export_slots(&wanted, &child_address); let cidx = s.items.len(); s.items.push(st::Item::Sub(child)); @@ -665,10 +684,31 @@ mod tree_tests { st::Item::Op(st::Node::Reduce { input, .. }) => vec![input], _ => Vec::new(), }; - for input in inputs { assert!(is_arranged(input, &program.root.items), "{item:?}"); } + for input in inputs { assert!(is_arranged(input, &program.root.items, &program.root.imports, &[]), "{item:?}"); } } } + #[test] + fn arranged_trace_import_is_not_rearranged() { + let program = lower_tree(parse(r#" + let x = import "p::x" : (int, int); + output "o" = x | min; + "#)); + assert!(!program.root.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Arrange(_))))); + assert!(program.root.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Reduce { input: Ref::Import(_), .. })))); + } + + #[test] + fn arranged_parent_is_not_rearranged_in_child() { + let program = lower_tree(parse(r#" + let a = input 0 : (int, int) | arrange; + s: { let m = ::a | min; } + output "o" = s::m; + "#)); + let s = child(&program.root, "s"); + assert!(!s.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Arrange(_))))); + } + #[test] fn keeps_explicit_arranges_and_scope_boundaries() { let program = lower_tree(parse(r#" @@ -684,7 +724,9 @@ mod tree_tests { }).collect(); assert!(arranges.iter().any(|input| matches!(input, Ref::ChildExport(..)))); let inner = child(&program.root, "inner"); - assert!(matches!(&inner.items[0], st::Item::Op(st::Node::Arrange(Ref::Import(_))))); + // The arranged parent item is entered as an arrangement, so the child reads it as is. + assert!(matches!(&inner.items[0], st::Item::Op(st::Node::Reduce { input: Ref::Import(_), .. }))); + assert!(!inner.items.iter().any(|item| matches!(item, st::Item::Op(st::Node::Arrange(_))))); } #[test] diff --git a/interactive/src/reducers.rs b/interactive/src/reducers.rs index f33f27921b..f71e79a018 100644 --- a/interactive/src/reducers.rs +++ b/interactive/src/reducers.rs @@ -16,6 +16,7 @@ pub(crate) fn expand_distinct( scope: &mut crate::scope_ir::Scope, shapes: &crate::shapes::ScopeShapes, pending: &std::collections::HashMap, Vec>, + parent_arranged: &[bool], path: &mut Vec, ) { use crate::scope_ir::{Item, Node, Ref, Source}; @@ -39,19 +40,25 @@ pub(crate) fn expand_distinct( Item::Op(node) => node.for_each_ref(|r| remap_ref(r, &remap)), Item::Sub(child) => { let crate::shapes::ItemShapes::Sub(shapes) = &shapes.items[i] else { unreachable!() }; - path.push(child.name.clone()); - expand_distinct(child, shapes, pending, path); - path.pop(); for import in &mut child.imports { if let Source::Parent(r) = &mut import.from { remap_ref(r, &remap); } } + // A by-record distinct ends in a map, so an import that lowering took + // to be arranged may not be. Recompute it against the rewritten items. + let entering: Vec = child.imports.iter().map(|import| match &import.from { + Source::Parent(r) => crate::lower::is_arranged(r, &items, &scope.imports, parent_arranged), + _ => false, + }).collect(); + path.push(child.name.clone()); + expand_distinct(child, shapes, pending, &entering, path); + path.pop(); } } let mut push = |mut node: Node| { // Distinct can replace a Reduce with a map back from the record key. // Check consumers after remapping, when their actual input is known. let mut arrange = |input: &mut Ref| { - if !crate::lower::is_arranged(input, &items) { + if !crate::lower::is_arranged(input, &items, &scope.imports, parent_arranged) { let r = Ref::Local(items.len()); items.push(Item::Op(Node::Arrange(input.clone()))); labels.push(scope.labels[i].clone()); diff --git a/interactive/tests/plan_pairs/expected/access_shared.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/access_shared.lowered--optimized.diff index d31a8e1101..4fd700f6b7 100644 --- a/interactive/tests/plan_pairs/expected/access_shared.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/access_shared.lowered--optimized.diff @@ -1,6 +1,6 @@ --- lowered +++ optimized -@@ -4,35 +4,33 @@ +@@ -4,6 +4,8 @@ let grants = input 0 : (int, (Member, Access)); let groups = input 1 : (int, Member); let blocks = input 2 : (int, Member); @@ -9,16 +9,14 @@ let members_map = groups | map((grp, who) -> (grp inject Member::Group, who)); let members = members_map | arrange; barring: { - -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. +@@ -11,26 +13,24 @@ var barred : (Member, int); let barred_idx = barred | arrange; -- let members_idx = ::members | arrange; -- let beyond = barred_idx | join(members_idx, (_grp, doc, who) -> (who, doc)); + let beyond = barred_idx | join(::members, (_grp, doc, who) -> (who, doc)); - let barred_map = ::blocks | map((doc, who) -> (who, doc)); - let barred_rows = barred_map + beyond; - let barred_map2 = barred_rows | map((k, v) -> ((k, v), ())); - let barred_idx2 = barred_map2 | arrange; -+ let beyond = barred_idx | join(::members, (_grp, doc, who) -> (who, doc)); + let barred_rows = ::blocks_map + beyond; + let barred_map = barred_rows | map((k, v) -> ((k, v), ())); + let barred_idx2 = barred_map | arrange; @@ -35,11 +33,9 @@ var allowed : ((Member, int), Access); let inherited_map = allowed | map(((who, doc), acc) -> (who, (doc, acc))); let inherited_idx = inherited_map | arrange; -- let members_idx = ::members | arrange; -- let inherited = inherited_idx | join(members_idx, (_grp, (doc, acc), who) -> ((who, doc), acc)); + let inherited = inherited_idx | join(::members, (_grp, (doc, acc), who) -> ((who, doc), acc)); - let offered_map = ::grants | map((doc, (who, acc)) -> ((who, doc), acc)); - let offered = offered_map + inherited; -+ let inherited = inherited_idx | join(::members, (_grp, (doc, acc), who) -> ((who, doc), acc)); + let offered = ::grants_map + inherited; let offered_idx = offered | arrange; - let barred_idx = ::barred | arrange; diff --git a/interactive/tests/plan_pairs/expected/access_shared.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/access_shared.parsed--lowered.diff index ecce6a3d21..e1deac20af 100644 --- a/interactive/tests/plan_pairs/expected/access_shared.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/access_shared.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,19 +1,43 @@ +@@ -1,19 +1,41 @@ type Access = Owner | Edit | View; type Member = User int | Group int; +-- Time lanes: epoch. @@ -14,8 +14,7 @@ + -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. + var barred : (Member, int); + let barred_idx = barred | arrange; -+ let members_idx = ::members | arrange; -+ let beyond = barred_idx | join(members_idx, (_grp, doc, who) -> (who, doc)); ++ let beyond = barred_idx | join(::members, (_grp, doc, who) -> (who, doc)); + let barred_map = ::blocks | map((doc, who) -> (who, doc)); + let barred_rows = barred_map + beyond; + let barred_map2 = barred_rows | map((k, v) -> ((k, v), ())); @@ -34,8 +33,7 @@ + var allowed : ((Member, int), Access); + let inherited_map = allowed | map(((who, doc), acc) -> (who, (doc, acc))); + let inherited_idx = inherited_map | arrange; -+ let members_idx = ::members | arrange; -+ let inherited = inherited_idx | join(members_idx, (_grp, (doc, acc), who) -> ((who, doc), acc)); ++ let inherited = inherited_idx | join(::members, (_grp, (doc, acc), who) -> ((who, doc), acc)); + let offered_map = ::grants | map((doc, (who, acc)) -> ((who, doc), acc)); + let offered = offered_map + inherited; + let offered_idx = offered | arrange; diff --git a/interactive/tests/plan_pairs/expected/as_of_shared.ddp b/interactive/tests/plan_pairs/expected/as_of_shared.ddp index 58f316f05a..559f3e2862 100644 --- a/interactive/tests/plan_pairs/expected/as_of_shared.ddp +++ b/interactive/tests/plan_pairs/expected/as_of_shared.ddp @@ -3,9 +3,8 @@ let rows = import "rows::rows" : (int, int); let lifted = rows | lift; let lifted_filter = lifted | filter((_, (_, (t0))) -> (t0, 0) ne); -let rows_idx = rows | arrange; -let strict_join = lifted_filter | half_join(rows_idx, 1, (k, v, _) -> (k, v)); -let inclusive_join = lifted | half_join(rows_idx, 0, (k, v, _) -> (k, v)); +let strict_join = lifted_filter | half_join(rows, 1, (k, v, _) -> (k, v)); +let inclusive_join = lifted | half_join(rows, 0, (k, v, _) -> (k, v)); -- Renderer: build an export arrangement. output "strict" = strict_join; -- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/as_of_shared.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/as_of_shared.lowered--optimized.diff index ce2169f66c..e69de29bb2 100644 --- a/interactive/tests/plan_pairs/expected/as_of_shared.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/as_of_shared.lowered--optimized.diff @@ -1,12 +0,0 @@ ---- lowered -+++ optimized -@@ -4,8 +4,7 @@ - let lifted = rows | lift; - let rows_idx = rows | arrange; - let strict_join = lifted | half_join(rows_idx, 1, (k, v, _) -> (k, v)); --let rows_idx2 = rows | arrange; --let inclusive_join = lifted | half_join(rows_idx2, 0, (k, v, _) -> (k, v)); -+let inclusive_join = lifted | half_join(rows_idx, 0, (k, v, _) -> (k, v)); - -- Renderer: build an export arrangement. - output "strict" = strict_join; - -- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/as_of_shared.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/as_of_shared.parsed--lowered.diff index bc62f12101..396cae967d 100644 --- a/interactive/tests/plan_pairs/expected/as_of_shared.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/as_of_shared.parsed--lowered.diff @@ -1,16 +1,14 @@ --- parsed +++ lowered -@@ -1,4 +1,12 @@ +@@ -1,4 +1,10 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let rows = import "rows::rows" : (int, int); let lifted = rows | lift; -output "strict" = lifted | half_join(rows, 1, (k, v, _) -> (k, v)); -output "inclusive" = lifted | half_join(rows, 0, (k, v, _) -> (k, v)); -+let rows_idx = rows | arrange; -+let strict_join = lifted | half_join(rows_idx, 1, (k, v, _) -> (k, v)); -+let rows_idx2 = rows | arrange; -+let inclusive_join = lifted | half_join(rows_idx2, 0, (k, v, _) -> (k, v)); ++let strict_join = lifted | half_join(rows, 1, (k, v, _) -> (k, v)); ++let inclusive_join = lifted | half_join(rows, 0, (k, v, _) -> (k, v)); +-- Renderer: build an export arrangement. +output "strict" = strict_join; +-- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/as_of_shared.projected--as-of.diff b/interactive/tests/plan_pairs/expected/as_of_shared.projected--as-of.diff index 0176e83bcf..3608be2a8a 100644 --- a/interactive/tests/plan_pairs/expected/as_of_shared.projected--as-of.diff +++ b/interactive/tests/plan_pairs/expected/as_of_shared.projected--as-of.diff @@ -1,13 +1,12 @@ --- projected +++ as-of -@@ -2,8 +2,9 @@ +@@ -2,7 +2,8 @@ -- Trace imports use provider arrangements; history advances to G = (0, []). let rows = import "rows::rows" : (int, int); let lifted = rows | lift; +-let strict_join = lifted | half_join(rows, 1, (k, v, _) -> (k, v)); +let lifted_filter = lifted | filter((_, (_, (t0))) -> (t0, 0) ne); - let rows_idx = rows | arrange; --let strict_join = lifted | half_join(rows_idx, 1, (k, v, _) -> (k, v)); -+let strict_join = lifted_filter | half_join(rows_idx, 1, (k, v, _) -> (k, v)); - let inclusive_join = lifted | half_join(rows_idx, 0, (k, v, _) -> (k, v)); ++let strict_join = lifted_filter | half_join(rows, 1, (k, v, _) -> (k, v)); + let inclusive_join = lifted | half_join(rows, 0, (k, v, _) -> (k, v)); -- Renderer: build an export arrangement. output "strict" = strict_join; diff --git a/interactive/tests/plan_pairs/expected/as_of_strict.ddp b/interactive/tests/plan_pairs/expected/as_of_strict.ddp index d658ee19ad..4e2403862e 100644 --- a/interactive/tests/plan_pairs/expected/as_of_strict.ddp +++ b/interactive/tests/plan_pairs/expected/as_of_strict.ddp @@ -2,7 +2,6 @@ -- Trace imports use provider arrangements; history advances to G = (0, []). let rows = import "rows::rows" : (int, int); let out_rows = rows | lift | filter((_, (_, (t0))) -> (t0, 0) ne); -let rows_idx = rows | arrange; -let out_join = out_rows | half_join(rows_idx, 1, (k, v, _) -> (k, v)); +let out_join = out_rows | half_join(rows, 1, (k, v, _) -> (k, v)); -- Renderer: build an export arrangement. output "out" = out_join; diff --git a/interactive/tests/plan_pairs/expected/as_of_strict.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/as_of_strict.parsed--lowered.diff index eaa3a8aca0..23ce5459ef 100644 --- a/interactive/tests/plan_pairs/expected/as_of_strict.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/as_of_strict.parsed--lowered.diff @@ -1,12 +1,11 @@ --- parsed +++ lowered -@@ -1,2 +1,8 @@ +@@ -1,2 +1,7 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let rows = import "rows::rows" : (int, int); -output "out" = rows | lift | half_join(rows, 1, (k, v, _) -> (k, v)); +let out_rows = rows | lift; -+let rows_idx = rows | arrange; -+let out_join = out_rows | half_join(rows_idx, 1, (k, v, _) -> (k, v)); ++let out_join = out_rows | half_join(rows, 1, (k, v, _) -> (k, v)); +-- Renderer: build an export arrangement. +output "out" = out_join; diff --git a/interactive/tests/plan_pairs/expected/as_of_strict.projected--as-of.diff b/interactive/tests/plan_pairs/expected/as_of_strict.projected--as-of.diff index c581670014..561be9e94d 100644 --- a/interactive/tests/plan_pairs/expected/as_of_strict.projected--as-of.diff +++ b/interactive/tests/plan_pairs/expected/as_of_strict.projected--as-of.diff @@ -6,6 +6,6 @@ let rows = import "rows::rows" : (int, int); -let out_rows = rows | lift; +let out_rows = rows | lift | filter((_, (_, (t0))) -> (t0, 0) ne); - let rows_idx = rows | arrange; - let out_join = out_rows | half_join(rows_idx, 1, (k, v, _) -> (k, v)); + let out_join = out_rows | half_join(rows, 1, (k, v, _) -> (k, v)); -- Renderer: build an export arrangement. + output "out" = out_join; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.ddp index caeff6f00a..9001b1aa70 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.ddp @@ -11,49 +11,41 @@ let email = import "graph::email.by_person" : (int, List(int)); let language = import "graph::language.by_person" : (int, List(int)); let hop1_map = request | map(((rid, who, name), ()) -> (who, (rid, who, name))); let hop1_idx = hop1_map | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, (req, 1))); +let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, (req, 1))); let hop1_idx2 = hop1 | arrange; -let hop2 = hop1_idx2 | join(friend_idx, (_, (req, _), (g, _)) -> (g, (req, 2))); +let hop2 = hop1_idx2 | join(friend, (_, (req, _), (g, _)) -> (g, (req, 2))); let hop2_idx = hop2 | arrange; -let hop3 = hop2_idx | join(friend_idx, (_, (req, _), (h, _)) -> (h, (req, 3))); +let hop3 = hop2_idx | join(friend, (_, (req, _), (h, _)) -> (h, (req, 3))); let circle_rows = hop1 + hop2 + hop3; let circle_rows2 = circle_rows | filter((node, ((_, who, _), _)) -> (node, who) ne) | map((node, ((rid, _, name), d)) -> ((rid, node, name), d)); let circle_idx = circle_rows2 | arrange; let circle = circle_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let found_map = circle | map(((rid, node, name), d) -> (node, (rid, name, d))); let found_idx = found_map | arrange; -let person_idx = person | arrange; -let found_join = found_idx | join(person_idx, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))); +let found_join = found_idx | join(person, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))); let found_rows = found_join | filter((named, _) -> named) | map((_, row) -> row); let found_idx2 = found_rows | arrange; -let place_idx = place | arrange; -let found = found_idx2 | join(place_idx, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); +let found = found_idx2 | join(place, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); let who = found | map(((rid, node), _) -> (node, rid)); let who_idx = who | arrange; -let email_idx = email | arrange; -let emails_join = who_idx | join(email_idx, (node, rid, value) -> ((rid, node), value)); +let emails_join = who_idx | join(email, (node, rid, value) -> ((rid, node), value)); let emails_idx = emails_join | arrange; let emails = emails_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let language_idx = language | arrange; -let langs_join = who_idx | join(language_idx, (node, rid, value) -> ((rid, node), value)); +let langs_join = who_idx | join(language, (node, rid, value) -> ((rid, node), value)); let langs_idx = langs_join | arrange; let langs = langs_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let study_idx = study | arrange; -let school_join = who_idx | join(study_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); +let school_join = who_idx | join(study, (node, rid, (at, year)) -> (at, (rid, node, year))); let school_idx = school_join | arrange; -let org_idx = org | arrange; -let school_join2 = school_idx | join(org_idx, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); +let school_join2 = school_idx | join(org, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); let school_idx2 = school_join2 | arrange; -let school_join3 = school_idx2 | join(place_idx, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); +let school_join3 = school_idx2 | join(place, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); let school_idx3 = school_join3 | arrange; let school = school_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let work_idx = work | arrange; -let jobs_join = who_idx | join(work_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); +let jobs_join = who_idx | join(work, (node, rid, (at, year)) -> (at, (rid, node, year))); let jobs_idx = jobs_join | arrange; -let jobs_join2 = jobs_idx | join(org_idx, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); +let jobs_join2 = jobs_idx | join(org, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); let jobs_idx2 = jobs_join2 | arrange; -let jobs_join3 = jobs_idx2 | join(place_idx, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); +let jobs_join3 = jobs_idx2 | join(place, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); let jobs_idx3 = jobs_join3 | arrange; let jobs = jobs_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); let found_idx3 = found | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.lowered--optimized.diff index 3d9dea0c40..07feccb259 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.lowered--optimized.diff @@ -1,16 +1,8 @@ --- lowered +++ optimized -@@ -14,23 +14,19 @@ - let friend_idx = friend | arrange; - let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, (req, 1))); - let hop1_idx2 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx2 | join(friend_idx2, (_, (req, _), (g, _)) -> (g, (req, 2))); -+let hop2 = hop1_idx2 | join(friend_idx, (_, (req, _), (g, _)) -> (g, (req, 2))); +@@ -17,36 +17,31 @@ let hop2_idx = hop2 | arrange; --let friend_idx3 = friend | arrange; --let hop3 = hop2_idx | join(friend_idx3, (_, (req, _), (h, _)) -> (h, (req, 3))); -+let hop3 = hop2_idx | join(friend_idx, (_, (req, _), (h, _)) -> (h, (req, 3))); + let hop3 = hop2_idx | join(friend, (_, (req, _), (h, _)) -> (h, (req, 3))); let circle_rows = hop1 + hop2 + hop3; -let circle_filter = circle_rows | filter((node, ((_, who, _), _)) -> (node, who) ne); -let circle_map = circle_filter | map((node, ((rid, _, name), d)) -> ((rid, node, name), d)); @@ -20,52 +12,39 @@ let circle = circle_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let found_map = circle | map(((rid, node, name), d) -> (node, (rid, name, d))); let found_idx = found_map | arrange; - let person_idx = person | arrange; - let found_join = found_idx | join(person_idx, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))); + let found_join = found_idx | join(person, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))); -let found_filter = found_join | filter((named, _) -> named); -let found_map2 = found_filter | map((_, row) -> row); -let found_idx2 = found_map2 | arrange; +let found_rows = found_join | filter((named, _) -> named) | map((_, row) -> row); +let found_idx2 = found_rows | arrange; - let place_idx = place | arrange; - let found = found_idx2 | join(place_idx, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); + let found = found_idx2 | join(place, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); let who = found | map(((rid, node), _) -> (node, rid)); -@@ -39,61 +35,51 @@ - let emails_join = who_idx | join(email_idx, (node, rid, value) -> ((rid, node), value)); + let who_idx = who | arrange; + let emails_join = who_idx | join(email, (node, rid, value) -> ((rid, node), value)); let emails_idx = emails_join | arrange; let emails = emails_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let who_idx2 = who | arrange; - let language_idx = language | arrange; --let langs_join = who_idx2 | join(language_idx, (node, rid, value) -> ((rid, node), value)); -+let langs_join = who_idx | join(language_idx, (node, rid, value) -> ((rid, node), value)); +-let langs_join = who_idx2 | join(language, (node, rid, value) -> ((rid, node), value)); ++let langs_join = who_idx | join(language, (node, rid, value) -> ((rid, node), value)); let langs_idx = langs_join | arrange; let langs = langs_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let who_idx3 = who | arrange; - let study_idx = study | arrange; --let school_join = who_idx3 | join(study_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); -+let school_join = who_idx | join(study_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); +-let school_join = who_idx3 | join(study, (node, rid, (at, year)) -> (at, (rid, node, year))); ++let school_join = who_idx | join(study, (node, rid, (at, year)) -> (at, (rid, node, year))); let school_idx = school_join | arrange; - let org_idx = org | arrange; - let school_join2 = school_idx | join(org_idx, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); + let school_join2 = school_idx | join(org, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); let school_idx2 = school_join2 | arrange; --let place_idx2 = place | arrange; --let school_join3 = school_idx2 | join(place_idx2, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); -+let school_join3 = school_idx2 | join(place_idx, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); + let school_join3 = school_idx2 | join(place, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); let school_idx3 = school_join3 | arrange; let school = school_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let who_idx4 = who | arrange; - let work_idx = work | arrange; --let jobs_join = who_idx4 | join(work_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); -+let jobs_join = who_idx | join(work_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); +-let jobs_join = who_idx4 | join(work, (node, rid, (at, year)) -> (at, (rid, node, year))); ++let jobs_join = who_idx | join(work, (node, rid, (at, year)) -> (at, (rid, node, year))); let jobs_idx = jobs_join | arrange; --let org_idx2 = org | arrange; --let jobs_join2 = jobs_idx | join(org_idx2, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); -+let jobs_join2 = jobs_idx | join(org_idx, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); + let jobs_join2 = jobs_idx | join(org, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); let jobs_idx2 = jobs_join2 | arrange; --let place_idx3 = place | arrange; --let jobs_join3 = jobs_idx2 | join(place_idx3, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); -+let jobs_join3 = jobs_idx2 | join(place_idx, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); - let jobs_idx3 = jobs_join3 | arrange; +@@ -55,32 +50,28 @@ let jobs = jobs_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); let found_idx3 = found | arrange; let with1_join = found_idx3 | join(emails, (key, row, list) -> (key, (row, list))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.parsed--lowered.diff index ae8295b3c9..717218d8ec 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic01_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, List(int)), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let friend = import "graph::friend" : (int, (int, int)); -@@ -7,20 +9,99 @@ +@@ -7,20 +9,86 @@ let work = import "graph::work.by_person" : (int, (int, int)); let email = import "graph::email.by_person" : (int, List(int)); let language = import "graph::language.by_person" : (int, List(int)); @@ -17,14 +17,11 @@ -let found = circle | map(((rid, node, name), d) -> (node, (rid, name, d))) | join(person, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))) | filter((named, _) -> named) | map((_, row) -> row) | join(place, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); +let hop1_map = request | map(((rid, who, name), ()) -> (who, (rid, who, name))); +let hop1_idx = hop1_map | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, (req, 1))); ++let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, (req, 1))); +let hop1_idx2 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx2 | join(friend_idx2, (_, (req, _), (g, _)) -> (g, (req, 2))); ++let hop2 = hop1_idx2 | join(friend, (_, (req, _), (g, _)) -> (g, (req, 2))); +let hop2_idx = hop2 | arrange; -+let friend_idx3 = friend | arrange; -+let hop3 = hop2_idx | join(friend_idx3, (_, (req, _), (h, _)) -> (h, (req, 3))); ++let hop3 = hop2_idx | join(friend, (_, (req, _), (h, _)) -> (h, (req, 3))); +let circle_rows = hop1 + hop2 + hop3; +let circle_filter = circle_rows | filter((node, ((_, who, _), _)) -> (node, who) ne); +let circle_map = circle_filter | map((node, ((rid, _, name), d)) -> ((rid, node, name), d)); @@ -32,13 +29,11 @@ +let circle = circle_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); +let found_map = circle | map(((rid, node, name), d) -> (node, (rid, name, d))); +let found_idx = found_map | arrange; -+let person_idx = person | arrange; -+let found_join = found_idx | join(person_idx, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))); ++let found_join = found_idx | join(person, (node, (rid, name, d), (first, last, gender, birthday, created, ip, browser, home, _, _, _)) -> ((first, name) eq, (home, (rid, node, d, last, gender, birthday, created, ip, browser)))); +let found_filter = found_join | filter((named, _) -> named); +let found_map2 = found_filter | map((_, row) -> row); +let found_idx2 = found_map2 | arrange; -+let place_idx = place | arrange; -+let found = found_idx2 | join(place_idx, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); ++let found = found_idx2 | join(place, (_, (rid, node, d, last, gender, birthday, created, ip, browser), (town, _, _)) -> ((rid, node), (d, (last, gender, birthday, created, ip, browser, town)))); let who = found | map(((rid, node), _) -> (node, rid)); -let emails = who | join(email, (node, rid, value) -> ((rid, node), value)) | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let langs = who | join(language, (node, rid, value) -> ((rid, node), value)) | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); @@ -50,35 +45,27 @@ -let with4 = (with3 | join(jobs, (key, (row, e, l, s), list) -> (key, (row, e, l, s, list)))) + (with3 + (with3 | join(jobs, (key, row, _) -> (key, row)) | negate) | map((key, (row, e, l, s)) -> (key, (row, e, l, s, [] : List((List(int), int, List(int))))))); -let ranked = with4 | map(((rid, node), ((d, (last, gender, birthday, created, ip, browser, town)), e, l, s, w)) -> (rid, ((d, last, node), (gender, birthday, created, ip, browser, town, e, l, s, w)))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let who_idx = who | arrange; -+let email_idx = email | arrange; -+let emails_join = who_idx | join(email_idx, (node, rid, value) -> ((rid, node), value)); ++let emails_join = who_idx | join(email, (node, rid, value) -> ((rid, node), value)); +let emails_idx = emails_join | arrange; +let emails = emails_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let who_idx2 = who | arrange; -+let language_idx = language | arrange; -+let langs_join = who_idx2 | join(language_idx, (node, rid, value) -> ((rid, node), value)); ++let langs_join = who_idx2 | join(language, (node, rid, value) -> ((rid, node), value)); +let langs_idx = langs_join | arrange; +let langs = langs_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let who_idx3 = who | arrange; -+let study_idx = study | arrange; -+let school_join = who_idx3 | join(study_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); ++let school_join = who_idx3 | join(study, (node, rid, (at, year)) -> (at, (rid, node, year))); +let school_idx = school_join | arrange; -+let org_idx = org | arrange; -+let school_join2 = school_idx | join(org_idx, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); ++let school_join2 = school_idx | join(org, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); +let school_idx2 = school_join2 | arrange; -+let place_idx2 = place | arrange; -+let school_join3 = school_idx2 | join(place_idx2, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); ++let school_join3 = school_idx2 | join(place, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); +let school_idx3 = school_join3 | arrange; +let school = school_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let who_idx4 = who | arrange; -+let work_idx = work | arrange; -+let jobs_join = who_idx4 | join(work_idx, (node, rid, (at, year)) -> (at, (rid, node, year))); ++let jobs_join = who_idx4 | join(work, (node, rid, (at, year)) -> (at, (rid, node, year))); +let jobs_idx = jobs_join | arrange; -+let org_idx2 = org | arrange; -+let jobs_join2 = jobs_idx | join(org_idx2, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); ++let jobs_join2 = jobs_idx | join(org, (_, (rid, node, year), (name, _, at)) -> (at, (rid, node, name, year))); +let jobs_idx2 = jobs_join2 | arrange; -+let place_idx3 = place | arrange; -+let jobs_join3 = jobs_idx2 | join(place_idx3, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); ++let jobs_join3 = jobs_idx2 | join(place, (_, (rid, node, name, year), (where, _, _)) -> ((rid, node), (name, year, where))); +let jobs_idx3 = jobs_join3 | arrange; +let jobs = jobs_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let found_idx3 = found | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.ddp index 28571e75b3..16293a0226 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.ddp @@ -9,30 +9,24 @@ let latest = import "ic2s::latest" : (int, (int, int)); let newest = import "ic2s::newest" : (int, int); let friends_map = request | map(((rid, who, max), ()) -> (who, (rid, max))); let friends_idx = friends_map | arrange; -let friend_idx = friend | arrange; -let friends = friends_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); +let friends = friends_idx | join(friend, (_, req, (f, _)) -> (f, req)); let friends_idx2 = friends | arrange; -let newest_idx = newest | arrange; -let ahead = friends_idx2 | join(newest_idx, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); +let ahead = friends_idx2 | join(newest, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); let fast_filter = ahead | filter((_, (_, max, last)) -> (last, max) lt); let fast_idx = fast_filter | arrange; -let latest_idx = latest | arrange; -let fast = fast_idx | join(latest_idx, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); +let fast = fast_idx | join(latest, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); let slow_filter = ahead | filter((_, (_, max, last)) -> (last, max) ge); let slow_idx = slow_filter | arrange; -let by_author_idx = by_author | arrange; -let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> (rid, ((neg, id), f, max))); +let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> (rid, ((neg, id), f, max))); let slow = slow_join | filter((_, ((neg, _), _, max)) -> (neg neg, max) lt) | map((rid, (order, f, _)) -> (rid, (order, f))); let top_rows = fast + slow; let top_idx = top_rows | arrange; let top = top_idx | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer_map = top | map((rid, (rank, ((neg, id), f))) -> (id, (rid, rank, neg neg, f))); let answer_idx = answer_map | arrange; -let message_idx = message | arrange; -let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); +let answer_join = answer_idx | join(message, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); let answer_idx2 = answer_join | arrange; -let person_idx = person | arrange; -let answer = answer_idx2 | join(person_idx, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); +let answer = answer_idx2 | join(person, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); let answer_idx3 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.lowered--optimized.diff index 720d756252..65ca7ed81d 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.lowered--optimized.diff @@ -1,9 +1,9 @@ --- lowered +++ optimized -@@ -22,8 +22,7 @@ +@@ -18,8 +18,7 @@ + let slow_filter = ahead | filter((_, (_, max, last)) -> (last, max) ge); let slow_idx = slow_filter | arrange; - let by_author_idx = by_author | arrange; - let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> (rid, ((neg, id), f, max))); + let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> (rid, ((neg, id), f, max))); -let slow_filter2 = slow_join | filter((_, ((neg, _), _, max)) -> (neg neg, max) lt); -let slow = slow_filter2 | map((rid, (order, f, _)) -> (rid, (order, f))); +let slow = slow_join | filter((_, ((neg, _), _, max)) -> (neg neg, max) lt) | map((rid, (order, f, _)) -> (rid, (order, f))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.parsed--lowered.diff index e9a8173acb..05f5711569 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic02_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, int), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -5,10 +7,33 @@ +@@ -5,10 +7,27 @@ let by_author = import "ic2s::by_author" : (int, (int, int)); let latest = import "ic2s::latest" : (int, (int, int)); let newest = import "ic2s::newest" : (int, int); @@ -19,19 +19,15 @@ -output "answer" = answer | arrange; +let friends_map = request | map(((rid, who, max), ()) -> (who, (rid, max))); +let friends_idx = friends_map | arrange; -+let friend_idx = friend | arrange; -+let friends = friends_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); ++let friends = friends_idx | join(friend, (_, req, (f, _)) -> (f, req)); +let friends_idx2 = friends | arrange; -+let newest_idx = newest | arrange; -+let ahead = friends_idx2 | join(newest_idx, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); ++let ahead = friends_idx2 | join(newest, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); +let fast_filter = ahead | filter((_, (_, max, last)) -> (last, max) lt); +let fast_idx = fast_filter | arrange; -+let latest_idx = latest | arrange; -+let fast = fast_idx | join(latest_idx, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); ++let fast = fast_idx | join(latest, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); +let slow_filter = ahead | filter((_, (_, max, last)) -> (last, max) ge); +let slow_idx = slow_filter | arrange; -+let by_author_idx = by_author | arrange; -+let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> (rid, ((neg, id), f, max))); ++let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> (rid, ((neg, id), f, max))); +let slow_filter2 = slow_join | filter((_, ((neg, _), _, max)) -> (neg neg, max) lt); +let slow = slow_filter2 | map((rid, (order, f, _)) -> (rid, (order, f))); +let top_rows = fast + slow; @@ -39,11 +35,9 @@ +let top = top_idx | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let answer_map = top | map((rid, (rank, ((neg, id), f))) -> (id, (rid, rank, neg neg, f))); +let answer_idx = answer_map | arrange; -+let message_idx = message | arrange; -+let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); ++let answer_join = answer_idx | join(message, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); +let answer_idx2 = answer_join | arrange; -+let person_idx = person | arrange; -+let answer = answer_idx2 | join(person_idx, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); ++let answer = answer_idx2 | join(person, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); +let answer_idx3 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.ddp index 6c59ef1542..4954350bb5 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.ddp @@ -8,37 +8,32 @@ let by_name = import "graph::place.by_name" : (List(int), int); let sent_from = import "ic3s::sent_from" : (int, (int, int)); let asked_map = request | map(((rid, who, x, y, start, days), ()) -> (x, (rid, who, y, start, (start, (days, 86400000) mul) add))); let asked_idx = asked_map | arrange; -let by_name_idx = by_name | arrange; -let asked_join = asked_idx | join(by_name_idx, (_, req, x) -> (x, req)); +let asked_join = asked_idx | join(by_name, (_, req, x) -> (x, req)); let asked_idx2 = asked_join | arrange; -let place_idx = place | arrange; -let asked_join2 = asked_idx2 | join(place_idx, (x, (rid, who, y, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (y, (rid, who, x, start, end)))); +let asked_join2 = asked_idx2 | join(place, (x, (rid, who, y, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (y, (rid, who, x, start, end)))); let asked_rows = asked_join2 | filter((country, _) -> country) | map((_, row) -> row); let asked_idx3 = asked_rows | arrange; -let asked_join3 = asked_idx3 | join(by_name_idx, (_, req, y) -> (y, req)); +let asked_join3 = asked_idx3 | join(by_name, (_, req, y) -> (y, req)); let asked_idx4 = asked_join3 | arrange; -let asked_join4 = asked_idx4 | join(place_idx, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); +let asked_join4 = asked_idx4 | join(place, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); let asked = asked_join4 | filter((country, _) -> country) | map((_, row) -> row); let window_map = asked | map((rid, (_, x, _, start, end)) -> (x, (rid, start, end, 1, 0))); let window_map2 = asked | map((rid, (_, _, y, start, end)) -> (y, (rid, start, end, 0, 1))); let window = window_map + window_map2; let window_idx = window | arrange; -let sent_from_idx = sent_from | arrange; -let visits_join = window_idx | join(sent_from_idx, (_, (rid, start, end, ix, iy), (author, created)) -> ((rid, author), (created, start, end, ix, iy))); +let visits_join = window_idx | join(sent_from, (_, (rid, start, end, ix, iy), (author, created)) -> ((rid, author), (created, start, end, ix, iy))); let visits = visits_join | filter((_, (created, start, end, _, _)) -> ((created, start) ge, (created, end) lt) all) | map((key, (_, _, _, ix, iy)) -> (key, (ix, iy))); let hop1_map = asked | map((rid, (who, x, y, _, _)) -> (who, (rid, who, x, y))); let hop1_idx = hop1_map | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); +let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, req)); let hop1_idx2 = hop1 | arrange; -let hop2 = hop1_idx2 | join(friend_idx, (_, req, (g, _)) -> (g, req)); +let hop2 = hop1_idx2 | join(friend, (_, req, (g, _)) -> (g, req)); let circle_rows = hop1 + hop2; let circle_filter = circle_rows | filter((node, (_, who, _, _)) -> (node, who) ne); let circle_idx = circle_filter | arrange; -let person_idx = person | arrange; -let circle_join = circle_idx | join(person_idx, (node, (rid, _, x, y), (_, _, _, _, _, _, _, city, _, _, _)) -> (city, (rid, node, x, y))); +let circle_join = circle_idx | join(person, (node, (rid, _, x, y), (_, _, _, _, _, _, _, city, _, _, _)) -> (city, (rid, node, x, y))); let circle_idx2 = circle_join | arrange; -let circle_join2 = circle_idx2 | join(place_idx, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); +let circle_join2 = circle_idx2 | join(place, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); let circle_rows2 = circle_join2 | filter((_, (x, y, home)) -> ((home, x) ne, (home, y) ne) all) | map((key, _) -> (key, ())); let circle_idx3 = circle_rows2 | arrange; let circle = circle_idx3 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); @@ -53,7 +48,7 @@ let in_y = in_y_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let counts = in_x | join(in_y, (key, nx, ny) -> (key, (nx, ny))); let ranked_map = counts | map(((rid, node), (nx, ny)) -> (node, (rid, nx, ny))); let ranked_idx = ranked_map | arrange; -let ranked_join = ranked_idx | join(person_idx, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))); +let ranked_join = ranked_idx | join(person, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))); let ranked_idx2 = ranked_join | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((_, node), (first, last, nx, ny)))) -> ((rid, rank), (node, first, last, nx, ny, (nx, ny) add))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.lowered--optimized.diff index d76be3a0f2..6888d9a8b8 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.lowered--optimized.diff @@ -8,54 +8,39 @@ let friend = import "graph::friend" : (int, (int, int)); let place = import "graph::place" : (int, (List(int), List(int), int)); let by_name = import "graph::place.by_name" : (List(int), int); -@@ -14,58 +13,47 @@ +@@ -12,21 +11,18 @@ + let asked_join = asked_idx | join(by_name, (_, req, x) -> (x, req)); let asked_idx2 = asked_join | arrange; - let place_idx = place | arrange; - let asked_join2 = asked_idx2 | join(place_idx, (x, (rid, who, y, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (y, (rid, who, x, start, end)))); + let asked_join2 = asked_idx2 | join(place, (x, (rid, who, y, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (y, (rid, who, x, start, end)))); -let asked_filter = asked_join2 | filter((country, _) -> country); -let asked_map2 = asked_filter | map((_, row) -> row); -let asked_idx3 = asked_map2 | arrange; --let by_name_idx2 = by_name | arrange; --let asked_join3 = asked_idx3 | join(by_name_idx2, (_, req, y) -> (y, req)); +let asked_rows = asked_join2 | filter((country, _) -> country) | map((_, row) -> row); +let asked_idx3 = asked_rows | arrange; -+let asked_join3 = asked_idx3 | join(by_name_idx, (_, req, y) -> (y, req)); + let asked_join3 = asked_idx3 | join(by_name, (_, req, y) -> (y, req)); let asked_idx4 = asked_join3 | arrange; --let place_idx2 = place | arrange; --let asked_join4 = asked_idx4 | join(place_idx2, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); + let asked_join4 = asked_idx4 | join(place, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); -let asked_filter2 = asked_join4 | filter((country, _) -> country); -let asked = asked_filter2 | map((_, row) -> row); -+let asked_join4 = asked_idx4 | join(place_idx, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); +let asked = asked_join4 | filter((country, _) -> country) | map((_, row) -> row); let window_map = asked | map((rid, (_, x, _, start, end)) -> (x, (rid, start, end, 1, 0))); let window_map2 = asked | map((rid, (_, _, y, start, end)) -> (y, (rid, start, end, 0, 1))); let window = window_map + window_map2; let window_idx = window | arrange; - let sent_from_idx = sent_from | arrange; - let visits_join = window_idx | join(sent_from_idx, (_, (rid, start, end, ix, iy), (author, created)) -> ((rid, author), (created, start, end, ix, iy))); + let visits_join = window_idx | join(sent_from, (_, (rid, start, end, ix, iy), (author, created)) -> ((rid, author), (created, start, end, ix, iy))); -let visits_filter = visits_join | filter((_, (created, start, end, _, _)) -> ((created, start) ge, (created, end) lt) all); -let visits = visits_filter | map((key, (_, _, _, ix, iy)) -> (key, (ix, iy))); +let visits = visits_join | filter((_, (created, start, end, _, _)) -> ((created, start) ge, (created, end) lt) all) | map((key, (_, _, _, ix, iy)) -> (key, (ix, iy))); let hop1_map = asked | map((rid, (who, x, y, _, _)) -> (who, (rid, who, x, y))); let hop1_idx = hop1_map | arrange; - let friend_idx = friend | arrange; - let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); - let hop1_idx2 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx2 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); -+let hop2 = hop1_idx2 | join(friend_idx, (_, req, (g, _)) -> (g, req)); - let circle_rows = hop1 + hop2; - let circle_filter = circle_rows | filter((node, (_, who, _, _)) -> (node, who) ne); - let circle_idx = circle_filter | arrange; - let person_idx = person | arrange; - let circle_join = circle_idx | join(person_idx, (node, (rid, _, x, y), (_, _, _, _, _, _, _, city, _, _, _)) -> (city, (rid, node, x, y))); + let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, req)); +@@ -38,19 +34,16 @@ + let circle_join = circle_idx | join(person, (node, (rid, _, x, y), (_, _, _, _, _, _, _, city, _, _, _)) -> (city, (rid, node, x, y))); let circle_idx2 = circle_join | arrange; --let place_idx3 = place | arrange; --let circle_join2 = circle_idx2 | join(place_idx3, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); + let circle_join2 = circle_idx2 | join(place, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); -let circle_filter2 = circle_join2 | filter((_, (x, y, home)) -> ((home, x) ne, (home, y) ne) all); -let circle_map = circle_filter2 | map((key, _) -> (key, ())); -let circle_idx3 = circle_map | arrange; -+let circle_join2 = circle_idx2 | join(place_idx, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); +let circle_rows2 = circle_join2 | filter((_, (x, y, home)) -> ((home, x) ne, (home, y) ne) all) | map((key, _) -> (key, ())); +let circle_idx3 = circle_rows2 | arrange; let circle = circle_idx3 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); @@ -75,10 +60,3 @@ let in_y = in_y_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); let counts = in_x | join(in_y, (key, nx, ny) -> (key, (nx, ny))); let ranked_map = counts | map(((rid, node), (nx, ny)) -> (node, (rid, nx, ny))); - let ranked_idx = ranked_map | arrange; --let person_idx2 = person | arrange; --let ranked_join = ranked_idx | join(person_idx2, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))); -+let ranked_join = ranked_idx | join(person_idx, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))); - let ranked_idx2 = ranked_join | arrange; - let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); - let answer = ranked | map((rid, (rank, ((_, node), (first, last, nx, ny)))) -> ((rid, rank), (node, first, last, nx, ny, (nx, ny) add))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.parsed--lowered.diff index 5da749f991..8cc9c43271 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic03_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, List(int), List(int), int, int), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -5,16 +7,68 @@ +@@ -5,16 +7,58 @@ let place = import "graph::place" : (int, (List(int), List(int), int)); let by_name = import "graph::place.by_name" : (List(int), int); let sent_from = import "ic3s::sent_from" : (int, (int, int)); @@ -21,44 +21,35 @@ -let in_y = seen | filter((_, (_, iy)) -> (iy, 1) eq) | map((key, _) -> (key, ())) | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); +let asked_map = request | map(((rid, who, x, y, start, days), ()) -> (x, (rid, who, y, start, (start, (days, 86400000) mul) add))); +let asked_idx = asked_map | arrange; -+let by_name_idx = by_name | arrange; -+let asked_join = asked_idx | join(by_name_idx, (_, req, x) -> (x, req)); ++let asked_join = asked_idx | join(by_name, (_, req, x) -> (x, req)); +let asked_idx2 = asked_join | arrange; -+let place_idx = place | arrange; -+let asked_join2 = asked_idx2 | join(place_idx, (x, (rid, who, y, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (y, (rid, who, x, start, end)))); ++let asked_join2 = asked_idx2 | join(place, (x, (rid, who, y, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (y, (rid, who, x, start, end)))); +let asked_filter = asked_join2 | filter((country, _) -> country); +let asked_map2 = asked_filter | map((_, row) -> row); +let asked_idx3 = asked_map2 | arrange; -+let by_name_idx2 = by_name | arrange; -+let asked_join3 = asked_idx3 | join(by_name_idx2, (_, req, y) -> (y, req)); ++let asked_join3 = asked_idx3 | join(by_name, (_, req, y) -> (y, req)); +let asked_idx4 = asked_join3 | arrange; -+let place_idx2 = place | arrange; -+let asked_join4 = asked_idx4 | join(place_idx2, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); ++let asked_join4 = asked_idx4 | join(place, (y, (rid, who, x, start, end), (_, kind, _)) -> ((kind, [67,111,117,110,116,114,121]) eq, (rid, (who, x, y, start, end)))); +let asked_filter2 = asked_join4 | filter((country, _) -> country); +let asked = asked_filter2 | map((_, row) -> row); +let window_map = asked | map((rid, (_, x, _, start, end)) -> (x, (rid, start, end, 1, 0))); +let window_map2 = asked | map((rid, (_, _, y, start, end)) -> (y, (rid, start, end, 0, 1))); +let window = window_map + window_map2; +let window_idx = window | arrange; -+let sent_from_idx = sent_from | arrange; -+let visits_join = window_idx | join(sent_from_idx, (_, (rid, start, end, ix, iy), (author, created)) -> ((rid, author), (created, start, end, ix, iy))); ++let visits_join = window_idx | join(sent_from, (_, (rid, start, end, ix, iy), (author, created)) -> ((rid, author), (created, start, end, ix, iy))); +let visits_filter = visits_join | filter((_, (created, start, end, _, _)) -> ((created, start) ge, (created, end) lt) all); +let visits = visits_filter | map((key, (_, _, _, ix, iy)) -> (key, (ix, iy))); +let hop1_map = asked | map((rid, (who, x, y, _, _)) -> (who, (rid, who, x, y))); +let hop1_idx = hop1_map | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); ++let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, req)); +let hop1_idx2 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx2 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); ++let hop2 = hop1_idx2 | join(friend, (_, req, (g, _)) -> (g, req)); +let circle_rows = hop1 + hop2; +let circle_filter = circle_rows | filter((node, (_, who, _, _)) -> (node, who) ne); +let circle_idx = circle_filter | arrange; -+let person_idx = person | arrange; -+let circle_join = circle_idx | join(person_idx, (node, (rid, _, x, y), (_, _, _, _, _, _, _, city, _, _, _)) -> (city, (rid, node, x, y))); ++let circle_join = circle_idx | join(person, (node, (rid, _, x, y), (_, _, _, _, _, _, _, city, _, _, _)) -> (city, (rid, node, x, y))); +let circle_idx2 = circle_join | arrange; -+let place_idx3 = place | arrange; -+let circle_join2 = circle_idx2 | join(place_idx3, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); ++let circle_join2 = circle_idx2 | join(place, (_, (rid, node, x, y), (_, _, home)) -> ((rid, node), (x, y, home))); +let circle_filter2 = circle_join2 | filter((_, (x, y, home)) -> ((home, x) ne, (home, y) ne) all); +let circle_map = circle_filter2 | map((key, _) -> (key, ())); +let circle_idx3 = circle_map | arrange; @@ -77,8 +68,7 @@ -let ranked = counts | map(((rid, node), (nx, ny)) -> (node, (rid, nx, ny))) | join(person, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let ranked_map = counts | map(((rid, node), (nx, ny)) -> (node, (rid, nx, ny))); +let ranked_idx = ranked_map | arrange; -+let person_idx2 = person | arrange; -+let ranked_join = ranked_idx | join(person_idx2, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))); ++let ranked_join = ranked_idx | join(person, (node, (rid, nx, ny), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, (((nx, ny) add neg, node), (first, last, nx, ny)))); +let ranked_idx2 = ranked_join | arrange; +let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((_, node), (first, last, nx, ny)))) -> ((rid, rank), (node, first, last, nx, ny, (nx, ny) add))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.ddp index 24b9114151..762269a709 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.ddp @@ -6,14 +6,11 @@ let posts = import "ic4s::posts" : (int, (int, int)); let tags = import "ic4s::tags" : (int, (int, List(int))); let seen_map = request | map(((rid, who, start, days), ()) -> (who, (rid, start, (start, (days, 86400000) mul) add))); let seen_idx = seen_map | arrange; -let friend_idx = friend | arrange; -let seen_join = seen_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); +let seen_join = seen_idx | join(friend, (_, req, (f, _)) -> (f, req)); let seen_idx2 = seen_join | arrange; -let posts_idx = posts | arrange; -let seen_join2 = seen_idx2 | join(posts_idx, (_, (rid, start, end), (m, created)) -> (m, (rid, created, start, end))); +let seen_join2 = seen_idx2 | join(posts, (_, (rid, start, end), (m, created)) -> (m, (rid, created, start, end))); let seen_idx3 = seen_join2 | arrange; -let tags_idx = tags | arrange; -let seen = seen_idx3 | join(tags_idx, (_, (rid, created, start, end), (t, name)) -> ((rid, t), (name, created, start, end))); +let seen = seen_idx3 | join(tags, (_, (rid, created, start, end), (t, name)) -> ((rid, t), (name, created, start, end))); let before_rows = seen | filter((_, (_, created, start, _)) -> (created, start) lt) | map((key, _) -> (key, ())); let before_idx = before_rows | arrange; let before = before_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.lowered--optimized.diff index 34b756169a..77f833e40a 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.lowered--optimized.diff @@ -11,10 +11,10 @@ let posts = import "ic4s::posts" : (int, (int, int)); let tags = import "ic4s::tags" : (int, (int, List(int))); let seen_map = request | map(((rid, who, start, days), ()) -> (who, (rid, start, (start, (days, 86400000) mul) add))); -@@ -17,9 +14,8 @@ +@@ -14,9 +11,8 @@ + let seen_join2 = seen_idx2 | join(posts, (_, (rid, start, end), (m, created)) -> (m, (rid, created, start, end))); let seen_idx3 = seen_join2 | arrange; - let tags_idx = tags | arrange; - let seen = seen_idx3 | join(tags_idx, (_, (rid, created, start, end), (t, name)) -> ((rid, t), (name, created, start, end))); + let seen = seen_idx3 | join(tags, (_, (rid, created, start, end), (t, name)) -> ((rid, t), (name, created, start, end))); -let before_filter = seen | filter((_, (_, created, start, _)) -> (created, start) lt); -let before_map = before_filter | map((key, _) -> (key, ())); -let before_idx = before_map | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.optimized--projected.diff b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.optimized--projected.diff index 8f7c454e03..8cb00be837 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.optimized--projected.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.optimized--projected.diff @@ -1,6 +1,6 @@ --- optimized +++ projected -@@ -19,9 +19,10 @@ +@@ -16,9 +16,10 @@ let before = before_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let during = seen | filter((_, (_, created, start, end)) -> ((created, start) ge, (created, end) lt) all); let during_idx = during | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.parsed--lowered.diff index 2adc6878ed..6082d787ae 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, int, int), ()); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); let friend = import "graph::friend" : (int, (int, int)); -@@ -5,11 +7,32 @@ +@@ -5,11 +7,29 @@ let mtag = import "graph::mtag.by_tag" : (int, int); let posts = import "ic4s::posts" : (int, (int, int)); let tags = import "ic4s::tags" : (int, (int, List(int))); @@ -14,14 +14,11 @@ -let before = seen | filter((_, (_, created, start, _)) -> (created, start) lt) | map((key, _) -> (key, ())) | map((k, v) -> ((k, v), ())) | reduce((_, vals) -> vals map (((), _) -> ((), 1))) | map((kv, ()) -> kv); +let seen_map = request | map(((rid, who, start, days), ()) -> (who, (rid, start, (start, (days, 86400000) mul) add))); +let seen_idx = seen_map | arrange; -+let friend_idx = friend | arrange; -+let seen_join = seen_idx | join(friend_idx, (_, req, (f, _)) -> (f, req)); ++let seen_join = seen_idx | join(friend, (_, req, (f, _)) -> (f, req)); +let seen_idx2 = seen_join | arrange; -+let posts_idx = posts | arrange; -+let seen_join2 = seen_idx2 | join(posts_idx, (_, (rid, start, end), (m, created)) -> (m, (rid, created, start, end))); ++let seen_join2 = seen_idx2 | join(posts, (_, (rid, start, end), (m, created)) -> (m, (rid, created, start, end))); +let seen_idx3 = seen_join2 | arrange; -+let tags_idx = tags | arrange; -+let seen = seen_idx3 | join(tags_idx, (_, (rid, created, start, end), (t, name)) -> ((rid, t), (name, created, start, end))); ++let seen = seen_idx3 | join(tags, (_, (rid, created, start, end), (t, name)) -> ((rid, t), (name, created, start, end))); +let before_filter = seen | filter((_, (_, created, start, _)) -> (created, start) lt); +let before_map = before_filter | map((key, _) -> (key, ())); +let before_idx = before_map | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.ddp index 6439534ce2..6ea21adad1 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.ddp @@ -4,9 +4,7 @@ let message = import "graph::message" : (int, (int, int, int, int, List(int), Li let tag = import "graph::tag" : (int, (List(int), int)); let mtag = import "graph::mtag.by_tag" : (int, int); let posts = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq) | map((id, (_, created, who, _, _, _, _, _, _, _, _, _, _)) -> (who, (id, created))); -let mtag_idx = mtag | arrange; -let tag_idx = tag | arrange; -let tags = mtag_idx | join(tag_idx, (t, m, (name, _)) -> (m, (t, name))); +let tags = mtag | join(tag, (t, m, (name, _)) -> (m, (t, name))); let posts_idx = posts | arrange; let tags_idx = tags | arrange; -- Renderer: publish the existing arrangement. diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.lowered--optimized.diff index 4d697215a9..56a49aab21 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.lowered--optimized.diff @@ -10,6 +10,6 @@ -let posts_filter = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq); -let posts = posts_filter | map((id, (_, created, who, _, _, _, _, _, _, _, _, _, _)) -> (who, (id, created))); +let posts = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq) | map((id, (_, created, who, _, _, _, _, _, _, _, _, _, _)) -> (who, (id, created))); - let mtag_idx = mtag | arrange; - let tag_idx = tag | arrange; - let tags = mtag_idx | join(tag_idx, (t, m, (name, _)) -> (m, (t, name))); + let tags = mtag | join(tag, (t, m, (name, _)) -> (m, (t, name))); + let posts_idx = posts | arrange; + let tags_idx = tags | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.parsed--lowered.diff index b6a53a5073..f7fa5abf5e 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic04_standing.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,8 +1,17 @@ +@@ -1,8 +1,15 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); @@ -8,14 +8,11 @@ let tag = import "graph::tag" : (int, (List(int), int)); let mtag = import "graph::mtag.by_tag" : (int, int); -let posts = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq) | map((id, (_, created, who, _, _, _, _, _, _, _, _, _, _)) -> (who, (id, created))); --let tags = mtag | join(tag, (t, m, (name, _)) -> (m, (t, name))); --output "posts" = posts | arrange; --output "tags" = tags | arrange; +let posts_filter = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq); +let posts = posts_filter | map((id, (_, created, who, _, _, _, _, _, _, _, _, _, _)) -> (who, (id, created))); -+let mtag_idx = mtag | arrange; -+let tag_idx = tag | arrange; -+let tags = mtag_idx | join(tag_idx, (t, m, (name, _)) -> (m, (t, name))); + let tags = mtag | join(tag, (t, m, (name, _)) -> (m, (t, name))); +-output "posts" = posts | arrange; +-output "tags" = tags | arrange; +let posts_idx = posts | arrange; +let tags_idx = tags | arrange; +-- Renderer: publish the existing arrangement. diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.ddp index 9c4fe9ccf8..c278ba2036 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.ddp @@ -10,34 +10,28 @@ let first = import "ic5s::first" : (int, int); let lowest = import "ic5s::lowest" : (int, int); let hop1_map = request | map(((rid, who, date), ()) -> (who, (rid, who, date))); let hop1_idx = hop1_map | arrange; -let person_idx = person | arrange; -let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); +let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); let hop1_idx2 = hop1_join | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); +let hop1 = hop1_idx2 | join(friend, (_, req, (f, _)) -> (f, req)); let hop1_idx3 = hop1 | arrange; -let hop2 = hop1_idx3 | join(friend_idx, (_, req, (g, _)) -> (g, req)); +let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); let circle_rows = hop1 + hop2; let circle_rows2 = circle_rows | filter((node, (_, who, _)) -> (node, who) ne) | map((node, (rid, _, date)) -> ((node, rid, date), ())); let circle_idx = circle_rows2 | arrange; let circle_reduce = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let circle = circle_reduce | map(((node, rid, date), ()) -> (node, (rid, date))); let circle_idx2 = circle | arrange; -let member_idx = member | arrange; -let after_join = circle_idx2 | join(member_idx, (node, (rid, date), (f, since)) -> ((node, f), (rid, date, since))); +let after_join = circle_idx2 | join(member, (node, (rid, date), (f, since)) -> ((node, f), (rid, date, since))); let after = after_join | filter((_, (_, date, since)) -> (since, date) gt) | map((key, (rid, _, _)) -> (key, rid)); let after_idx = after | arrange; -let posted_idx = posted | arrange; -let busy_join = after_idx | join(posted_idx, ((_, f), rid, n) -> ((rid, f), n)); +let busy_join = after_idx | join(posted, ((_, f), rid, n) -> ((rid, f), n)); let busy_rows = busy_join | join_function((key, n) -> ((key, ()), (0), n) enlist); let busy_idx = busy_rows | arrange; let busy = busy_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); -let first_idx = first | arrange; -let timed = circle_idx2 | join(first_idx, (node, (rid, date), since) -> (node, (rid, date, since))); +let timed = circle_idx2 | join(first, (node, (rid, date), since) -> (node, (rid, date, since))); let fast_filter = timed | filter((_, (_, date, since)) -> (since, date) gt); let fast_idx = fast_filter | arrange; -let lowest_idx = lowest | arrange; -let fast = fast_idx | join(lowest_idx, (_, (rid, _, _), f) -> ((rid, f), ())); +let fast = fast_idx | join(lowest, (_, (rid, _, _), f) -> ((rid, f), ())); let slow_rows = timed | filter((_, (_, date, since)) -> (since, date) le) | map((node, (rid, _, _)) -> ((node, rid), ())); let slow_idx = slow_rows | arrange; let slow_map = after | map(((node, f), rid) -> ((node, rid), f)); @@ -53,8 +47,7 @@ let quiet = quiet_rows | map((key, ()) -> (key, 0)); let ranked_rows = busy + quiet; let ranked_map = ranked_rows | map(((rid, f), n) -> (f, (rid, n))); let ranked_idx = ranked_map | arrange; -let forum_idx = forum | arrange; -let ranked_join = ranked_idx | join(forum_idx, (f, (rid, n), (title, _, _)) -> (rid, ((n neg, f), title))); +let ranked_join = ranked_idx | join(forum, (f, (rid, n), (title, _, _)) -> (rid, ((n neg, f), title))); let ranked_idx2 = ranked_join | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((neg, _), title))) -> ((rid, rank), (title, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.lowered--optimized.diff index 3d777b080c..7f44a87265 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.lowered--optimized.diff @@ -8,13 +8,9 @@ let friend = import "graph::friend" : (int, (int, int)); let forum = import "graph::forum" : (int, (List(int), int, int)); let member = import "graph::member.by_person" : (int, (int, int)); -@@ -17,37 +16,32 @@ - let friend_idx = friend | arrange; - let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); +@@ -17,30 +16,26 @@ let hop1_idx3 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx3 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); -+let hop2 = hop1_idx3 | join(friend_idx, (_, req, (g, _)) -> (g, req)); + let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); let circle_rows = hop1 + hop2; -let circle_filter = circle_rows | filter((node, (_, who, _)) -> (node, who) ne); -let circle_map = circle_filter | map((node, (rid, _, date)) -> ((node, rid, date), ())); @@ -24,25 +20,21 @@ let circle_reduce = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let circle = circle_reduce | map(((node, rid, date), ()) -> (node, (rid, date))); let circle_idx2 = circle | arrange; - let member_idx = member | arrange; - let after_join = circle_idx2 | join(member_idx, (node, (rid, date), (f, since)) -> ((node, f), (rid, date, since))); + let after_join = circle_idx2 | join(member, (node, (rid, date), (f, since)) -> ((node, f), (rid, date, since))); -let after_filter = after_join | filter((_, (_, date, since)) -> (since, date) gt); -let after = after_filter | map((key, (rid, _, _)) -> (key, rid)); +let after = after_join | filter((_, (_, date, since)) -> (since, date) gt) | map((key, (rid, _, _)) -> (key, rid)); let after_idx = after | arrange; - let posted_idx = posted | arrange; - let busy_join = after_idx | join(posted_idx, ((_, f), rid, n) -> ((rid, f), n)); + let busy_join = after_idx | join(posted, ((_, f), rid, n) -> ((rid, f), n)); let busy_rows = busy_join | join_function((key, n) -> ((key, ()), (0), n) enlist); let busy_idx = busy_rows | arrange; let busy = busy_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); -let circle_idx3 = circle | arrange; - let first_idx = first | arrange; --let timed = circle_idx3 | join(first_idx, (node, (rid, date), since) -> (node, (rid, date, since))); -+let timed = circle_idx2 | join(first_idx, (node, (rid, date), since) -> (node, (rid, date, since))); +-let timed = circle_idx3 | join(first, (node, (rid, date), since) -> (node, (rid, date, since))); ++let timed = circle_idx2 | join(first, (node, (rid, date), since) -> (node, (rid, date, since))); let fast_filter = timed | filter((_, (_, date, since)) -> (since, date) gt); let fast_idx = fast_filter | arrange; - let lowest_idx = lowest | arrange; - let fast = fast_idx | join(lowest_idx, (_, (rid, _, _), f) -> ((rid, f), ())); + let fast = fast_idx | join(lowest, (_, (rid, _, _), f) -> ((rid, f), ())); -let slow_filter = timed | filter((_, (_, date, since)) -> (since, date) le); -let slow_map = slow_filter | map((node, (rid, _, _)) -> ((node, rid), ())); -let slow_idx = slow_map | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.parsed--lowered.diff index 33d36ad7d7..fd8b9eb594 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic05_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, int), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -7,16 +9,61 @@ +@@ -7,16 +9,53 @@ let posted = import "ic5s::posted" : ((int, int), int); let first = import "ic5s::first" : (int, int); let lowest = import "ic5s::lowest" : (int, int); @@ -23,14 +23,11 @@ -let ranked = busy + quiet | map(((rid, f), n) -> (f, (rid, n))) | join(forum, (f, (rid, n), (title, _, _)) -> (rid, ((n neg, f), title))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let hop1_map = request | map(((rid, who, date), ()) -> (who, (rid, who, date))); +let hop1_idx = hop1_map | arrange; -+let person_idx = person | arrange; -+let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); ++let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); +let hop1_idx2 = hop1_join | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); ++let hop1 = hop1_idx2 | join(friend, (_, req, (f, _)) -> (f, req)); +let hop1_idx3 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx3 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); ++let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); +let circle_rows = hop1 + hop2; +let circle_filter = circle_rows | filter((node, (_, who, _)) -> (node, who) ne); +let circle_map = circle_filter | map((node, (rid, _, date)) -> ((node, rid, date), ())); @@ -38,23 +35,19 @@ +let circle_reduce = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); +let circle = circle_reduce | map(((node, rid, date), ()) -> (node, (rid, date))); +let circle_idx2 = circle | arrange; -+let member_idx = member | arrange; -+let after_join = circle_idx2 | join(member_idx, (node, (rid, date), (f, since)) -> ((node, f), (rid, date, since))); ++let after_join = circle_idx2 | join(member, (node, (rid, date), (f, since)) -> ((node, f), (rid, date, since))); +let after_filter = after_join | filter((_, (_, date, since)) -> (since, date) gt); +let after = after_filter | map((key, (rid, _, _)) -> (key, rid)); +let after_idx = after | arrange; -+let posted_idx = posted | arrange; -+let busy_join = after_idx | join(posted_idx, ((_, f), rid, n) -> ((rid, f), n)); ++let busy_join = after_idx | join(posted, ((_, f), rid, n) -> ((rid, f), n)); +let busy_rows = busy_join | join_function((key, n) -> ((key, ()), (0), n) enlist); +let busy_idx = busy_rows | arrange; +let busy = busy_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); +let circle_idx3 = circle | arrange; -+let first_idx = first | arrange; -+let timed = circle_idx3 | join(first_idx, (node, (rid, date), since) -> (node, (rid, date, since))); ++let timed = circle_idx3 | join(first, (node, (rid, date), since) -> (node, (rid, date, since))); +let fast_filter = timed | filter((_, (_, date, since)) -> (since, date) gt); +let fast_idx = fast_filter | arrange; -+let lowest_idx = lowest | arrange; -+let fast = fast_idx | join(lowest_idx, (_, (rid, _, _), f) -> ((rid, f), ())); ++let fast = fast_idx | join(lowest, (_, (rid, _, _), f) -> ((rid, f), ())); +let slow_filter = timed | filter((_, (_, date, since)) -> (since, date) le); +let slow_map = slow_filter | map((node, (rid, _, _)) -> ((node, rid), ())); +let slow_idx = slow_map | arrange; @@ -71,8 +64,7 @@ +let ranked_rows = busy + quiet; +let ranked_map = ranked_rows | map(((rid, f), n) -> (f, (rid, n))); +let ranked_idx = ranked_map | arrange; -+let forum_idx = forum | arrange; -+let ranked_join = ranked_idx | join(forum_idx, (f, (rid, n), (title, _, _)) -> (rid, ((n neg, f), title))); ++let ranked_join = ranked_idx | join(forum, (f, (rid, n), (title, _, _)) -> (rid, ((n neg, f), title))); +let ranked_idx2 = ranked_join | arrange; +let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((neg, _), title))) -> ((rid, rank), (title, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.ddp index e9e5f8a342..f4bd79293d 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.ddp @@ -10,40 +10,33 @@ let tagged = import "graph::mtag.by_tag" : (int, int); let tags_of = import "graph::mtag.by_message" : (int, int); let hop1_map = request | map(((rid, who, _), ()) -> (who, (rid, who))); let hop1_idx = hop1_map | arrange; -let person_idx = person | arrange; -let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); +let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); let hop1_idx2 = hop1_join | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx2 | join(friend_idx, (_, (rid, who), (f, _)) -> (f, (rid, who))); +let hop1 = hop1_idx2 | join(friend, (_, (rid, who), (f, _)) -> (f, (rid, who))); let hop1_idx3 = hop1 | arrange; -let hop2 = hop1_idx3 | join(friend_idx, (_, (rid, who), (g, _)) -> (g, (rid, who))); +let hop2 = hop1_idx3 | join(friend, (_, (rid, who), (g, _)) -> (g, (rid, who))); let circle_rows = hop1 + hop2; let circle_rows2 = circle_rows | filter((node, (_, who)) -> (node, who) ne) | map((node, (rid, _)) -> ((rid, node), ())); let circle_idx = circle_rows2 | arrange; let circle = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let with_it_map = request | map(((rid, _, name), ()) -> (name, rid)); let with_it_idx = with_it_map | arrange; -let by_name_idx = by_name | arrange; -let with_it_join = with_it_idx | join(by_name_idx, (_, rid, t) -> (t, rid)); +let with_it_join = with_it_idx | join(by_name, (_, rid, t) -> (t, rid)); let with_it_idx2 = with_it_join | arrange; -let tagged_idx = tagged | arrange; -let with_it_join2 = with_it_idx2 | join(tagged_idx, (t, rid, m) -> (m, (rid, t))); +let with_it_join2 = with_it_idx2 | join(tagged, (t, rid, m) -> (m, (rid, t))); let with_it_idx3 = with_it_join2 | arrange; -let message_idx = message | arrange; -let with_it_join3 = with_it_idx3 | join(message_idx, (m, (rid, t), (kind, _, author, _, _, _, _, _, _, _, _, _, _)) -> ((rid, author), (kind, m, t))); +let with_it_join3 = with_it_idx3 | join(message, (m, (rid, t), (kind, _, author, _, _, _, _, _, _, _, _, _, _)) -> ((rid, author), (kind, m, t))); let with_it_filter = with_it_join3 | filter((_, (kind, _, _)) -> (kind, 0) eq); let with_it_idx4 = with_it_filter | arrange; let with_it = with_it_idx4 | join(circle, ((rid, _), (_, m, t), ()) -> (m, (rid, t))); let with_it_idx5 = with_it | arrange; -let tags_of_idx = tags_of | arrange; -let others_join = with_it_idx5 | join(tags_of_idx, (_, (rid, t), other) -> ((rid, t, other), ())); +let others_join = with_it_idx5 | join(tags_of, (_, (rid, t), other) -> ((rid, t, other), ())); let others_rows = others_join | filter(((_, t, other), ()) -> (t, other) ne) | map(((rid, _, other), ()) -> ((rid, other), ())); let others_idx = others_rows | arrange; let others = others_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); let ranked_map = others | map(((rid, other), n) -> (other, (rid, n))); let ranked_idx = ranked_map | arrange; -let tag_idx = tag | arrange; -let ranked_join = ranked_idx | join(tag_idx, (_, (rid, n), (name, _)) -> (rid, (n neg, name))); +let ranked_join = ranked_idx | join(tag, (_, (rid, n), (name, _)) -> (rid, (n neg, name))); let ranked_idx2 = ranked_join | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, (neg, other))) -> ((rid, rank), (other, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.lowered--optimized.diff index 2bdd24233a..4ec44743eb 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.lowered--optimized.diff @@ -1,12 +1,8 @@ --- lowered +++ optimized -@@ -16,12 +16,10 @@ - let friend_idx = friend | arrange; - let hop1 = hop1_idx2 | join(friend_idx, (_, (rid, who), (f, _)) -> (f, (rid, who))); +@@ -16,9 +16,8 @@ let hop1_idx3 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx3 | join(friend_idx2, (_, (rid, who), (g, _)) -> (g, (rid, who))); -+let hop2 = hop1_idx3 | join(friend_idx, (_, (rid, who), (g, _)) -> (g, (rid, who))); + let hop2 = hop1_idx3 | join(friend, (_, (rid, who), (g, _)) -> (g, (rid, who))); let circle_rows = hop1 + hop2; -let circle_filter = circle_rows | filter((node, (_, who)) -> (node, who) ne); -let circle_map = circle_filter | map((node, (rid, _)) -> ((rid, node), ())); @@ -16,10 +12,10 @@ let circle = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let with_it_map = request | map(((rid, _, name), ()) -> (name, rid)); let with_it_idx = with_it_map | arrange; -@@ -39,9 +37,8 @@ +@@ -32,9 +31,8 @@ + let with_it = with_it_idx4 | join(circle, ((rid, _), (_, m, t), ()) -> (m, (rid, t))); let with_it_idx5 = with_it | arrange; - let tags_of_idx = tags_of | arrange; - let others_join = with_it_idx5 | join(tags_of_idx, (_, (rid, t), other) -> ((rid, t, other), ())); + let others_join = with_it_idx5 | join(tags_of, (_, (rid, t), other) -> ((rid, t, other), ())); -let others_filter = others_join | filter(((_, t, other), ()) -> (t, other) ne); -let others_map = others_filter | map(((rid, _, other), ()) -> ((rid, other), ())); -let others_idx = others_map | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.parsed--lowered.diff index 68527476c2..94fdb6ceb5 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic06_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, List(int)), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -6,11 +8,48 @@ +@@ -6,11 +8,40 @@ let by_name = import "graph::tag.by_name" : (List(int), int); let tagged = import "graph::mtag.by_tag" : (int, int); let tags_of = import "graph::mtag.by_message" : (int, int); @@ -18,14 +18,11 @@ -let ranked = others | map(((rid, other), n) -> (other, (rid, n))) | join(tag, (_, (rid, n), (name, _)) -> (rid, (n neg, name))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let hop1_map = request | map(((rid, who, _), ()) -> (who, (rid, who))); +let hop1_idx = hop1_map | arrange; -+let person_idx = person | arrange; -+let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); ++let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); +let hop1_idx2 = hop1_join | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx2 | join(friend_idx, (_, (rid, who), (f, _)) -> (f, (rid, who))); ++let hop1 = hop1_idx2 | join(friend, (_, (rid, who), (f, _)) -> (f, (rid, who))); +let hop1_idx3 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx3 | join(friend_idx2, (_, (rid, who), (g, _)) -> (g, (rid, who))); ++let hop2 = hop1_idx3 | join(friend, (_, (rid, who), (g, _)) -> (g, (rid, who))); +let circle_rows = hop1 + hop2; +let circle_filter = circle_rows | filter((node, (_, who)) -> (node, who) ne); +let circle_map = circle_filter | map((node, (rid, _)) -> ((rid, node), ())); @@ -33,28 +30,23 @@ +let circle = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); +let with_it_map = request | map(((rid, _, name), ()) -> (name, rid)); +let with_it_idx = with_it_map | arrange; -+let by_name_idx = by_name | arrange; -+let with_it_join = with_it_idx | join(by_name_idx, (_, rid, t) -> (t, rid)); ++let with_it_join = with_it_idx | join(by_name, (_, rid, t) -> (t, rid)); +let with_it_idx2 = with_it_join | arrange; -+let tagged_idx = tagged | arrange; -+let with_it_join2 = with_it_idx2 | join(tagged_idx, (t, rid, m) -> (m, (rid, t))); ++let with_it_join2 = with_it_idx2 | join(tagged, (t, rid, m) -> (m, (rid, t))); +let with_it_idx3 = with_it_join2 | arrange; -+let message_idx = message | arrange; -+let with_it_join3 = with_it_idx3 | join(message_idx, (m, (rid, t), (kind, _, author, _, _, _, _, _, _, _, _, _, _)) -> ((rid, author), (kind, m, t))); ++let with_it_join3 = with_it_idx3 | join(message, (m, (rid, t), (kind, _, author, _, _, _, _, _, _, _, _, _, _)) -> ((rid, author), (kind, m, t))); +let with_it_filter = with_it_join3 | filter((_, (kind, _, _)) -> (kind, 0) eq); +let with_it_idx4 = with_it_filter | arrange; +let with_it = with_it_idx4 | join(circle, ((rid, _), (_, m, t), ()) -> (m, (rid, t))); +let with_it_idx5 = with_it | arrange; -+let tags_of_idx = tags_of | arrange; -+let others_join = with_it_idx5 | join(tags_of_idx, (_, (rid, t), other) -> ((rid, t, other), ())); ++let others_join = with_it_idx5 | join(tags_of, (_, (rid, t), other) -> ((rid, t, other), ())); +let others_filter = others_join | filter(((_, t, other), ()) -> (t, other) ne); +let others_map = others_filter | map(((rid, _, other), ()) -> ((rid, other), ())); +let others_idx = others_map | arrange; +let others = others_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); +let ranked_map = others | map(((rid, other), n) -> (other, (rid, n))); +let ranked_idx = ranked_map | arrange; -+let tag_idx = tag | arrange; -+let ranked_join = ranked_idx | join(tag_idx, (_, (rid, n), (name, _)) -> (rid, (n neg, name))); ++let ranked_join = ranked_idx | join(tag, (_, (rid, n), (name, _)) -> (rid, (n neg, name))); +let ranked_idx2 = ranked_join | arrange; +let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, (neg, other))) -> ((rid, rank), (other, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.ddp index 904a8f2524..abfdd26e7c 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.ddp @@ -8,20 +8,16 @@ let likes = import "graph::likes.by_message" : (int, (int, int)); let pals = import "graph::friend.pair" : ((int, int), ()); let latest_map = request | map(((rid, who), ()) -> (who, rid)); let latest_idx = latest_map | arrange; -let wrote_idx = wrote | arrange; -let latest_join = latest_idx | join(wrote_idx, (who, rid, m) -> (m, (rid, who))); +let latest_join = latest_idx | join(wrote, (who, rid, m) -> (m, (rid, who))); let latest_idx2 = latest_join | arrange; -let likes_idx = likes | arrange; -let latest_join2 = latest_idx2 | join(likes_idx, (m, (rid, who), (liker, when)) -> ((rid, who, liker), (when neg, m))); +let latest_join2 = latest_idx2 | join(likes, (m, (rid, who), (liker, when)) -> ((rid, who, liker), (when neg, m))); let latest_idx3 = latest_join2 | arrange; let latest = latest_idx3 | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let rows_map = latest | map(((rid, who, liker), (neg, m)) -> (m, (rid, who, liker, neg neg))); let rows_idx = rows_map | arrange; -let message_idx = message | arrange; -let rows = rows_idx | join(message_idx, (m, (rid, who, liker, when), (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((who, liker), (rid, liker, when, m, ((text len, 0) gt, text, image) select, (when, created) sub))); +let rows = rows_idx | join(message, (m, (rid, who, liker, when), (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((who, liker), (rid, liker, when, m, ((text len, 0) gt, text, image) select, (when, created) sub))); let rows_idx2 = rows | arrange; -let pals_idx = pals | arrange; -let known = rows_idx2 | join(pals_idx, arg -> let _call0 = let input = arg in let (pair, row, ()) = input in (pair, row) in (((), ()), (_call0.1.0, _call0.1.1, _call0.1.2, _call0.1.3, _call0.1.4, _call0.1.5))); +let known = rows_idx2 | join(pals, arg -> let _call0 = let input = arg in let (pair, row, ()) = input in (pair, row) in (((), ()), (_call0.1.0, _call0.1.1, _call0.1.2, _call0.1.3, _call0.1.4, _call0.1.5))); let marked_map = known | map((_, row) -> (row, 0)); let marked_map2 = rows | map(arg -> let _call0 = let input = arg in input in (((), ()), (_call0.1.0, _call0.1.1, _call0.1.2, _call0.1.3, _call0.1.4, _call0.1.5))); let marked_neg = known | negate; @@ -30,8 +26,7 @@ let marked_map3 = marked_rows | map((_, row) -> (row, 1)); let marked = marked_map + marked_map3; let ranked_map = marked | map(((rid, liker, when, m, body, age), fresh) -> (liker, (rid, when, m, body, age, fresh))); let ranked_idx = ranked_map | arrange; -let person_idx = person | arrange; -let ranked_join = ranked_idx | join(person_idx, (liker, (rid, when, m, body, age, fresh), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((when neg, liker), (first, last, m, body, (age, 60000) div, fresh)))); +let ranked_join = ranked_idx | join(person, (liker, (rid, when, m, body, age, fresh), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((when neg, liker), (first, last, m, body, (age, 60000) div, fresh)))); let ranked_idx2 = ranked_join | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((neg, liker), (first, last, m, body, minutes, fresh)))) -> ((rid, rank), (liker, first, last, neg neg, m, body, minutes, fresh))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.optimized--projected.diff b/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.optimized--projected.diff index c90d26d3c9..88dbedff29 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.optimized--projected.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.optimized--projected.diff @@ -1,11 +1,11 @@ --- optimized +++ projected -@@ -21,12 +21,13 @@ - let rows = rows_idx | join(message_idx, (m, (rid, who, liker, when), (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((who, liker), (rid, liker, when, m, ((text len, 0) gt, text, image) select, (when, created) sub))); +@@ -17,12 +17,13 @@ + let rows_idx = rows_map | arrange; + let rows = rows_idx | join(message, (m, (rid, who, liker, when), (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((who, liker), (rid, liker, when, m, ((text len, 0) gt, text, image) select, (when, created) sub))); let rows_idx2 = rows | arrange; - let pals_idx = pals | arrange; --let known = rows_idx2 | join(pals_idx, (pair, row, ()) -> (pair, row)); -+let known = rows_idx2 | join(pals_idx, arg -> let _call0 = let input = arg in let (pair, row, ()) = input in (pair, row) in (((), ()), (_call0.1.0, _call0.1.1, _call0.1.2, _call0.1.3, _call0.1.4, _call0.1.5))); +-let known = rows_idx2 | join(pals, (pair, row, ()) -> (pair, row)); ++let known = rows_idx2 | join(pals, arg -> let _call0 = let input = arg in let (pair, row, ()) = input in (pair, row) in (((), ()), (_call0.1.0, _call0.1.1, _call0.1.2, _call0.1.3, _call0.1.4, _call0.1.5))); let marked_map = known | map((_, row) -> (row, 0)); +let marked_map2 = rows | map(arg -> let _call0 = let input = arg in input in (((), ()), (_call0.1.0, _call0.1.1, _call0.1.2, _call0.1.3, _call0.1.4, _call0.1.5))); let marked_neg = known | negate; @@ -17,4 +17,4 @@ +let marked = marked_map + marked_map3; let ranked_map = marked | map(((rid, liker, when, m, body, age), fresh) -> (liker, (rid, when, m, body, age, fresh))); let ranked_idx = ranked_map | arrange; - let person_idx = person | arrange; + let ranked_join = ranked_idx | join(person, (liker, (rid, when, m, body, age, fresh), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((when neg, liker), (first, last, m, body, (age, 60000) div, fresh)))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.parsed--lowered.diff index bba8ee0f95..d4a8bf2b72 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic07_oneoff.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,13 +1,39 @@ +@@ -1,13 +1,34 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -16,20 +16,16 @@ -let ranked = marked | map(((rid, liker, when, m, body, age), fresh) -> (liker, (rid, when, m, body, age, fresh))) | join(person, (liker, (rid, when, m, body, age, fresh), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((when neg, liker), (first, last, m, body, (age, 60000) div, fresh)))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let latest_map = request | map(((rid, who), ()) -> (who, rid)); +let latest_idx = latest_map | arrange; -+let wrote_idx = wrote | arrange; -+let latest_join = latest_idx | join(wrote_idx, (who, rid, m) -> (m, (rid, who))); ++let latest_join = latest_idx | join(wrote, (who, rid, m) -> (m, (rid, who))); +let latest_idx2 = latest_join | arrange; -+let likes_idx = likes | arrange; -+let latest_join2 = latest_idx2 | join(likes_idx, (m, (rid, who), (liker, when)) -> ((rid, who, liker), (when neg, m))); ++let latest_join2 = latest_idx2 | join(likes, (m, (rid, who), (liker, when)) -> ((rid, who, liker), (when neg, m))); +let latest_idx3 = latest_join2 | arrange; +let latest = latest_idx3 | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); +let rows_map = latest | map(((rid, who, liker), (neg, m)) -> (m, (rid, who, liker, neg neg))); +let rows_idx = rows_map | arrange; -+let message_idx = message | arrange; -+let rows = rows_idx | join(message_idx, (m, (rid, who, liker, when), (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((who, liker), (rid, liker, when, m, ((text len, 0) gt, text, image) select, (when, created) sub))); ++let rows = rows_idx | join(message, (m, (rid, who, liker, when), (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((who, liker), (rid, liker, when, m, ((text len, 0) gt, text, image) select, (when, created) sub))); +let rows_idx2 = rows | arrange; -+let pals_idx = pals | arrange; -+let known = rows_idx2 | join(pals_idx, (pair, row, ()) -> (pair, row)); ++let known = rows_idx2 | join(pals, (pair, row, ()) -> (pair, row)); +let marked_map = known | map((_, row) -> (row, 0)); +let marked_neg = known | negate; +let marked_rows = rows + marked_neg; @@ -37,8 +33,7 @@ +let marked = marked_map + marked_map2; +let ranked_map = marked | map(((rid, liker, when, m, body, age), fresh) -> (liker, (rid, when, m, body, age, fresh))); +let ranked_idx = ranked_map | arrange; -+let person_idx = person | arrange; -+let ranked_join = ranked_idx | join(person_idx, (liker, (rid, when, m, body, age, fresh), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((when neg, liker), (first, last, m, body, (age, 60000) div, fresh)))); ++let ranked_join = ranked_idx | join(person, (liker, (rid, when, m, body, age, fresh), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((when neg, liker), (first, last, m, body, (age, 60000) div, fresh)))); +let ranked_idx2 = ranked_join | arrange; +let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((neg, liker), (first, last, m, body, minutes, fresh)))) -> ((rid, rank), (liker, first, last, neg neg, m, body, minutes, fresh))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.ddp index 96feb7cdee..52650d1f1b 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.ddp @@ -7,23 +7,19 @@ let wrote = import "graph::message.by_creator" : (int, int); let replies = import "graph::message.by_parent" : (int, int); let top_map = request | map(((rid, who), ()) -> (who, rid)); let top_idx = top_map | arrange; -let wrote_idx = wrote | arrange; -let top_join = top_idx | join(wrote_idx, (_, rid, op) -> (op, rid)); +let top_join = top_idx | join(wrote, (_, rid, op) -> (op, rid)); let top_idx2 = top_join | arrange; -let replies_idx = replies | arrange; -let top_join2 = top_idx2 | join(replies_idx, (_, rid, id) -> (id, rid)); +let top_join2 = top_idx2 | join(replies, (_, rid, id) -> (id, rid)); let top_idx3 = top_join2 | arrange; -let message_idx = message | arrange; -let top_join3 = top_idx3 | join(message_idx, (id, rid, (kind, created, who, _, _, _, _, _, _, _, _, _, _)) -> (rid, (kind, (created neg, id), who))); +let top_join3 = top_idx3 | join(message, (id, rid, (kind, created, who, _, _, _, _, _, _, _, _, _, _)) -> (rid, (kind, (created neg, id), who))); let top_rows = top_join3 | filter((_, (kind, _, _)) -> (kind, 1) eq) | map((rid, (_, order, who)) -> (rid, (order, who))); let top_idx4 = top_rows | arrange; let top = top_idx4 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer_map = top | map((rid, (rank, ((neg, id), who))) -> (id, (rid, rank, neg neg, who))); let answer_idx = answer_map | arrange; -let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, who), (_, _, _, _, content, _, _, _, _, _, _, _, _)) -> (who, (rid, rank, id, content, created))); +let answer_join = answer_idx | join(message, (id, (rid, rank, created, who), (_, _, _, _, content, _, _, _, _, _, _, _, _)) -> (who, (rid, rank, id, content, created))); let answer_idx2 = answer_join | arrange; -let person_idx = person | arrange; -let answer = answer_idx2 | join(person_idx, (who, (rid, rank, id, content, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (who, first, last, created, id, content))); +let answer = answer_idx2 | join(person, (who, (rid, rank, id, content, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (who, first, last, created, id, content))); let answer_idx3 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.lowered--optimized.diff index fbb5744742..5f05bfc30f 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.lowered--optimized.diff @@ -1,9 +1,9 @@ --- lowered +++ optimized -@@ -15,14 +15,12 @@ +@@ -12,9 +12,8 @@ + let top_join2 = top_idx2 | join(replies, (_, rid, id) -> (id, rid)); let top_idx3 = top_join2 | arrange; - let message_idx = message | arrange; - let top_join3 = top_idx3 | join(message_idx, (id, rid, (kind, created, who, _, _, _, _, _, _, _, _, _, _)) -> (rid, (kind, (created neg, id), who))); + let top_join3 = top_idx3 | join(message, (id, rid, (kind, created, who, _, _, _, _, _, _, _, _, _, _)) -> (rid, (kind, (created neg, id), who))); -let top_filter = top_join3 | filter((_, (kind, _, _)) -> (kind, 1) eq); -let top_map2 = top_filter | map((rid, (_, order, who)) -> (rid, (order, who))); -let top_idx4 = top_map2 | arrange; @@ -12,9 +12,3 @@ let top = top_idx4 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer_map = top | map((rid, (rank, ((neg, id), who))) -> (id, (rid, rank, neg neg, who))); let answer_idx = answer_map | arrange; --let message_idx2 = message | arrange; --let answer_join = answer_idx | join(message_idx2, (id, (rid, rank, created, who), (_, _, _, _, content, _, _, _, _, _, _, _, _)) -> (who, (rid, rank, id, content, created))); -+let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, who), (_, _, _, _, content, _, _, _, _, _, _, _, _)) -> (who, (rid, rank, id, content, created))); - let answer_idx2 = answer_join | arrange; - let person_idx = person | arrange; - let answer = answer_idx2 | join(person_idx, (who, (rid, rank, id, content, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (who, first, last, created, id, content))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.parsed--lowered.diff index a5159a60a7..1d25d6df44 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic08_oneoff.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,8 +1,31 @@ +@@ -1,8 +1,26 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -13,25 +13,20 @@ -output "answer" = answer | arrange; +let top_map = request | map(((rid, who), ()) -> (who, rid)); +let top_idx = top_map | arrange; -+let wrote_idx = wrote | arrange; -+let top_join = top_idx | join(wrote_idx, (_, rid, op) -> (op, rid)); ++let top_join = top_idx | join(wrote, (_, rid, op) -> (op, rid)); +let top_idx2 = top_join | arrange; -+let replies_idx = replies | arrange; -+let top_join2 = top_idx2 | join(replies_idx, (_, rid, id) -> (id, rid)); ++let top_join2 = top_idx2 | join(replies, (_, rid, id) -> (id, rid)); +let top_idx3 = top_join2 | arrange; -+let message_idx = message | arrange; -+let top_join3 = top_idx3 | join(message_idx, (id, rid, (kind, created, who, _, _, _, _, _, _, _, _, _, _)) -> (rid, (kind, (created neg, id), who))); ++let top_join3 = top_idx3 | join(message, (id, rid, (kind, created, who, _, _, _, _, _, _, _, _, _, _)) -> (rid, (kind, (created neg, id), who))); +let top_filter = top_join3 | filter((_, (kind, _, _)) -> (kind, 1) eq); +let top_map2 = top_filter | map((rid, (_, order, who)) -> (rid, (order, who))); +let top_idx4 = top_map2 | arrange; +let top = top_idx4 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let answer_map = top | map((rid, (rank, ((neg, id), who))) -> (id, (rid, rank, neg neg, who))); +let answer_idx = answer_map | arrange; -+let message_idx2 = message | arrange; -+let answer_join = answer_idx | join(message_idx2, (id, (rid, rank, created, who), (_, _, _, _, content, _, _, _, _, _, _, _, _)) -> (who, (rid, rank, id, content, created))); ++let answer_join = answer_idx | join(message, (id, (rid, rank, created, who), (_, _, _, _, content, _, _, _, _, _, _, _, _)) -> (who, (rid, rank, id, content, created))); +let answer_idx2 = answer_join | arrange; -+let person_idx = person | arrange; -+let answer = answer_idx2 | join(person_idx, (who, (rid, rank, id, content, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (who, first, last, created, id, content))); ++let answer = answer_idx2 | join(person, (who, (rid, rank, id, content, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (who, first, last, created, id, content))); +let answer_idx3 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.ddp index 8bd5b1d70c..5ed9c406e7 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.ddp @@ -9,29 +9,24 @@ let latest = import "ic9s::latest" : (int, (int, int)); let newest = import "ic9s::newest" : (int, int); let hop1_map = request | map(((rid, who, max), ()) -> (who, (rid, who, max))); let hop1_idx = hop1_map | arrange; -let person_idx = person | arrange; -let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); +let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); let hop1_idx2 = hop1_join | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); +let hop1 = hop1_idx2 | join(friend, (_, req, (f, _)) -> (f, req)); let hop1_idx3 = hop1 | arrange; -let hop2 = hop1_idx3 | join(friend_idx, (_, req, (g, _)) -> (g, req)); +let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); let friends_rows = hop1 + hop2; let friends_rows2 = friends_rows | filter((node, (_, who, _)) -> (node, who) ne) | map((node, (rid, _, max)) -> ((node, rid, max), ())); let friends_idx = friends_rows2 | arrange; let friends_reduce = friends_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let friends = friends_reduce | map(((node, rid, max), ()) -> (node, (rid, max))); let friends_idx2 = friends | arrange; -let newest_idx = newest | arrange; -let ahead = friends_idx2 | join(newest_idx, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); +let ahead = friends_idx2 | join(newest, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); let fast_filter = ahead | filter((_, (_, max, last)) -> (last, max) lt); let fast_idx = fast_filter | arrange; -let latest_idx = latest | arrange; -let fast = fast_idx | join(latest_idx, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); +let fast = fast_idx | join(latest, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); let slow_filter = ahead | filter((_, (_, max, last)) -> (last, max) ge); let slow_idx = slow_filter | arrange; -let by_author_idx = by_author | arrange; -let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); +let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); let slow_rows = slow_join | filter((_, ((neg, _), max)) -> (neg neg, max) lt) | map((key, (order, _)) -> (key, order)); let slow_idx2 = slow_rows | arrange; let slow_reduce = slow_idx2 | reduce((_, a) -> let v0 = (a map ((_, a) -> (a, 0) gt), (0, a len) range) zip filter in let v1 = (((0, (v0 len, 20) min) range, v0) gather, a) gather in let v2 = (v1, v1 map ((_, a) -> (a, 20) min) scan_add) zip map ((a, b) -> let v0 = (a.1, 20) min in let v1 = (((20, (b, v0) sub) sub, 0) max, v0) min in ((v1, 0) gt, (a.0, v1))) filter in (v2, v2 map ((_, a) -> a) scan_add) zip map ((a, b) -> (a.0, ((b, a.1) sub, b) range) cap_list map ((a, b) -> ((b, a), 1))) flatten.1 map ((a, b) -> (((), a.1), b))); @@ -41,10 +36,9 @@ let top_idx = top_rows | arrange; let top = top_idx | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer_map = top | map((rid, (rank, ((neg, id), f))) -> (id, (rid, rank, neg neg, f))); let answer_idx = answer_map | arrange; -let message_idx = message | arrange; -let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); +let answer_join = answer_idx | join(message, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); let answer_idx2 = answer_join | arrange; -let answer = answer_idx2 | join(person_idx, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); +let answer = answer_idx2 | join(person, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); let answer_idx3 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.lowered--optimized.diff index 89e924cae7..d974a727fa 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.lowered--optimized.diff @@ -1,12 +1,8 @@ --- lowered +++ optimized -@@ -15,12 +15,10 @@ - let friend_idx = friend | arrange; - let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); +@@ -15,9 +15,8 @@ let hop1_idx3 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx3 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); -+let hop2 = hop1_idx3 | join(friend_idx, (_, req, (g, _)) -> (g, req)); + let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); let friends_rows = hop1 + hop2; -let friends_filter = friends_rows | filter((node, (_, who, _)) -> (node, who) ne); -let friends_map = friends_filter | map((node, (rid, _, max)) -> ((node, rid, max), ())); @@ -16,10 +12,10 @@ let friends_reduce = friends_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let friends = friends_reduce | map(((node, rid, max), ()) -> (node, (rid, max))); let friends_idx2 = friends | arrange; -@@ -34,9 +32,8 @@ +@@ -28,9 +27,8 @@ + let slow_filter = ahead | filter((_, (_, max, last)) -> (last, max) ge); let slow_idx = slow_filter | arrange; - let by_author_idx = by_author | arrange; - let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); + let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); -let slow_filter2 = slow_join | filter((_, ((neg, _), max)) -> (neg neg, max) lt); -let slow_map = slow_filter2 | map((key, (order, _)) -> (key, order)); -let slow_idx2 = slow_map | arrange; @@ -28,13 +24,3 @@ let slow_reduce = slow_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let slow = slow_reduce | map(((rid, f), (_, order)) -> (rid, (order, f))); let top_rows = fast + slow; -@@ -47,8 +44,7 @@ - let message_idx = message | arrange; - let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); - let answer_idx2 = answer_join | arrange; --let person_idx2 = person | arrange; --let answer = answer_idx2 | join(person_idx2, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); -+let answer = answer_idx2 | join(person_idx, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); - let answer_idx3 = answer | arrange; - -- Renderer: publish the existing arrangement. - output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.optimized--projected.diff b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.optimized--projected.diff index c6d3255ebc..0b7f8becb4 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.optimized--projected.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.optimized--projected.diff @@ -1,7 +1,7 @@ --- optimized +++ projected -@@ -34,7 +34,7 @@ - let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); +@@ -29,7 +29,7 @@ + let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); let slow_rows = slow_join | filter((_, ((neg, _), max)) -> (neg neg, max) lt) | map((key, (order, _)) -> (key, order)); let slow_idx2 = slow_rows | arrange; -let slow_reduce = slow_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.parsed--lowered.diff index 066fd252cf..fc557ee777 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic09_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, int), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -5,12 +7,48 @@ +@@ -5,12 +7,40 @@ let by_author = import "ic9s::by_author" : (int, (int, int)); let latest = import "ic9s::latest" : (int, (int, int)); let newest = import "ic9s::newest" : (int, int); @@ -21,14 +21,11 @@ -output "answer" = answer | arrange; +let hop1_map = request | map(((rid, who, max), ()) -> (who, (rid, who, max))); +let hop1_idx = hop1_map | arrange; -+let person_idx = person | arrange; -+let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); ++let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); +let hop1_idx2 = hop1_join | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); ++let hop1 = hop1_idx2 | join(friend, (_, req, (f, _)) -> (f, req)); +let hop1_idx3 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx3 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); ++let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); +let friends_rows = hop1 + hop2; +let friends_filter = friends_rows | filter((node, (_, who, _)) -> (node, who) ne); +let friends_map = friends_filter | map((node, (rid, _, max)) -> ((node, rid, max), ())); @@ -36,16 +33,13 @@ +let friends_reduce = friends_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); +let friends = friends_reduce | map(((node, rid, max), ()) -> (node, (rid, max))); +let friends_idx2 = friends | arrange; -+let newest_idx = newest | arrange; -+let ahead = friends_idx2 | join(newest_idx, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); ++let ahead = friends_idx2 | join(newest, (f, (rid, max), neg) -> (f, (rid, max, neg neg))); +let fast_filter = ahead | filter((_, (_, max, last)) -> (last, max) lt); +let fast_idx = fast_filter | arrange; -+let latest_idx = latest | arrange; -+let fast = fast_idx | join(latest_idx, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); ++let fast = fast_idx | join(latest, (f, (rid, _, _), (neg, id)) -> (rid, ((neg, id), f))); +let slow_filter = ahead | filter((_, (_, max, last)) -> (last, max) ge); +let slow_idx = slow_filter | arrange; -+let by_author_idx = by_author | arrange; -+let slow_join = slow_idx | join(by_author_idx, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); ++let slow_join = slow_idx | join(by_author, (f, (rid, max, _), (neg, id)) -> ((rid, f), ((neg, id), max))); +let slow_filter2 = slow_join | filter((_, ((neg, _), max)) -> (neg neg, max) lt); +let slow_map = slow_filter2 | map((key, (order, _)) -> (key, order)); +let slow_idx2 = slow_map | arrange; @@ -56,11 +50,9 @@ +let top = top_idx | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let answer_map = top | map((rid, (rank, ((neg, id), f))) -> (id, (rid, rank, neg neg, f))); +let answer_idx = answer_map | arrange; -+let message_idx = message | arrange; -+let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); ++let answer_join = answer_idx | join(message, (id, (rid, rank, created, f), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (f, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); +let answer_idx2 = answer_join | arrange; -+let person_idx2 = person | arrange; -+let answer = answer_idx2 | join(person_idx2, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); ++let answer = answer_idx2 | join(person, (f, (rid, rank, id, body, created), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (f, first, last, id, body, created))); +let answer_idx3 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.ddp index 60e95c218d..d192f292ec 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.ddp @@ -8,30 +8,25 @@ let posts = import "ic10s::posts" : (int, int); let likes = import "ic10s::likes" : ((int, int), ()); let hop1_map = request | map(((rid, who, month), ()) -> (who, (rid, who, month))); let hop1_idx = hop1_map | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, (req, 1))); +let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, (req, 1))); let hop1_idx2 = hop1 | arrange; -let hop2 = hop1_idx2 | join(friend_idx, (_, (req, _), (g, _)) -> (g, (req, 2))); +let hop2 = hop1_idx2 | join(friend, (_, (req, _), (g, _)) -> (g, (req, 2))); let twohop_rows = hop1 + hop2; let twohop_rows2 = twohop_rows | filter((node, ((_, who, _), _)) -> (node, who) ne) | map((node, ((rid, who, month), d)) -> ((rid, who, month, node), d)); let twohop_idx = twohop_rows2 | arrange; let twohop_reduce = twohop_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let cands_rows = twohop_reduce | filter((_, d) -> (d, 2) eq) | map(((rid, who, month, node), _) -> (node, (rid, who, month))); let cands_idx = cands_rows | arrange; -let people_idx = people | arrange; -let cands_join = cands_idx | join(people_idx, (node, (rid, who, month), (first, last, gender, town, bmonth, bday)) -> ((rid, who, node), (first, last, gender, town, month, bmonth, bday))); +let cands_join = cands_idx | join(people, (node, (rid, who, month), (first, last, gender, town, bmonth, bday)) -> ((rid, who, node), (first, last, gender, town, month, bmonth, bday))); let cands = cands_join | filter((_, (_, _, _, _, month, bmonth, bday)) -> (((bmonth, month) eq, (bday, 21) ge) all, ((bmonth, ((month, 12) eq, 1, (month, 1) add) select) eq, (bday, 22) lt) all) any) | map((key, (first, last, gender, town, _, _, _)) -> (key, (first, last, gender, town))); let wrote_map = cands | map(((rid, who, node), _) -> (node, (rid, who))); let wrote_idx = wrote_map | arrange; -let posts_idx = posts | arrange; -let wrote = wrote_idx | join(posts_idx, (node, (rid, who), m) -> ((rid, who, node, m), ())); +let wrote = wrote_idx | join(posts, (node, (rid, who), m) -> ((rid, who, node, m), ())); let liked_map = wrote | map(((rid, who, node, m), ()) -> (m, (rid, who, node))); let liked_idx = liked_map | arrange; -let tags_of_idx = tags_of | arrange; -let liked_join = liked_idx | join(tags_of_idx, (m, (rid, who, node), t) -> ((who, t), (rid, node, m))); +let liked_join = liked_idx | join(tags_of, (m, (rid, who, node), t) -> ((who, t), (rid, node, m))); let liked_idx2 = liked_join | arrange; -let likes_idx = likes | arrange; -let liked_join2 = liked_idx2 | join(likes_idx, ((who, _), (rid, node, m), ()) -> ((rid, who, node, m), ())); +let liked_join2 = liked_idx2 | join(likes, ((who, _), (rid, node, m), ()) -> ((rid, who, node, m), ())); let liked_idx3 = liked_join2 | arrange; let liked = liked_idx3 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let points_map = liked | map(((rid, who, node, _), ()) -> ((rid, who, node), 1)); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.lowered--optimized.diff index 39451088ad..f5e5a2205b 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.lowered--optimized.diff @@ -13,13 +13,9 @@ let people = import "ic10s::people" : (int, (List(int), List(int), List(int), List(int), int, int)); let posts = import "ic10s::posts" : (int, int); let likes = import "ic10s::likes" : ((int, int), ()); -@@ -15,20 +11,16 @@ - let friend_idx = friend | arrange; - let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, (req, 1))); +@@ -16,16 +12,13 @@ let hop1_idx2 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx2 | join(friend_idx2, (_, (req, _), (g, _)) -> (g, (req, 2))); -+let hop2 = hop1_idx2 | join(friend_idx, (_, (req, _), (g, _)) -> (g, (req, 2))); + let hop2 = hop1_idx2 | join(friend, (_, (req, _), (g, _)) -> (g, (req, 2))); let twohop_rows = hop1 + hop2; -let twohop_filter = twohop_rows | filter((node, ((_, who, _), _)) -> (node, who) ne); -let twohop_map = twohop_filter | map((node, ((rid, who, month), d)) -> ((rid, who, month, node), d)); @@ -32,11 +28,10 @@ -let cands_idx = cands_map | arrange; +let cands_rows = twohop_reduce | filter((_, d) -> (d, 2) eq) | map(((rid, who, month, node), _) -> (node, (rid, who, month))); +let cands_idx = cands_rows | arrange; - let people_idx = people | arrange; - let cands_join = cands_idx | join(people_idx, (node, (rid, who, month), (first, last, gender, town, bmonth, bday)) -> ((rid, who, node), (first, last, gender, town, month, bmonth, bday))); + let cands_join = cands_idx | join(people, (node, (rid, who, month), (first, last, gender, town, bmonth, bday)) -> ((rid, who, node), (first, last, gender, town, month, bmonth, bday))); -let cands_filter = cands_join | filter((_, (_, _, _, _, month, bmonth, bday)) -> (((bmonth, month) eq, (bday, 21) ge) all, ((bmonth, ((month, 12) eq, 1, (month, 1) add) select) eq, (bday, 22) lt) all) any); -let cands = cands_filter | map((key, (first, last, gender, town, _, _, _)) -> (key, (first, last, gender, town))); +let cands = cands_join | filter((_, (_, _, _, _, month, bmonth, bday)) -> (((bmonth, month) eq, (bday, 21) ge) all, ((bmonth, ((month, 12) eq, 1, (month, 1) add) select) eq, (bday, 22) lt) all) any) | map((key, (first, last, gender, town, _, _, _)) -> (key, (first, last, gender, town))); let wrote_map = cands | map(((rid, who, node), _) -> (node, (rid, who))); let wrote_idx = wrote_map | arrange; - let posts_idx = posts | arrange; + let wrote = wrote_idx | join(posts, (node, (rid, who), m) -> ((rid, who, node, m), ())); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.optimized--projected.diff b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.optimized--projected.diff index a28c9a1c02..3acdc458a8 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.optimized--projected.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.optimized--projected.diff @@ -1,6 +1,6 @@ --- optimized +++ projected -@@ -35,10 +35,11 @@ +@@ -30,10 +30,11 @@ let liked_idx3 = liked_join2 | arrange; let liked = liked_idx3 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let points_map = liked | map(((rid, who, node, _), ()) -> ((rid, who, node), 1)); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.parsed--lowered.diff index 583b2db0b0..876f964380 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, int), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -8,16 +10,59 @@ +@@ -8,16 +10,53 @@ let people = import "ic10s::people" : (int, (List(int), List(int), List(int), List(int), int, int)); let posts = import "ic10s::posts" : (int, int); let likes = import "ic10s::likes" : ((int, int), ()); @@ -20,11 +20,9 @@ -let summed = points | join_function((key, p) -> ((key, ()), (0), p) enlist) | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); +let hop1_map = request | map(((rid, who, month), ()) -> (who, (rid, who, month))); +let hop1_idx = hop1_map | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx | join(friend_idx, (_, req, (f, _)) -> (f, (req, 1))); ++let hop1 = hop1_idx | join(friend, (_, req, (f, _)) -> (f, (req, 1))); +let hop1_idx2 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx2 | join(friend_idx2, (_, (req, _), (g, _)) -> (g, (req, 2))); ++let hop2 = hop1_idx2 | join(friend, (_, (req, _), (g, _)) -> (g, (req, 2))); +let twohop_rows = hop1 + hop2; +let twohop_filter = twohop_rows | filter((node, ((_, who, _), _)) -> (node, who) ne); +let twohop_map = twohop_filter | map((node, ((rid, who, month), d)) -> ((rid, who, month, node), d)); @@ -33,21 +31,17 @@ +let twohop = twohop_reduce | filter((_, d) -> (d, 2) eq); +let cands_map = twohop | map(((rid, who, month, node), _) -> (node, (rid, who, month))); +let cands_idx = cands_map | arrange; -+let people_idx = people | arrange; -+let cands_join = cands_idx | join(people_idx, (node, (rid, who, month), (first, last, gender, town, bmonth, bday)) -> ((rid, who, node), (first, last, gender, town, month, bmonth, bday))); ++let cands_join = cands_idx | join(people, (node, (rid, who, month), (first, last, gender, town, bmonth, bday)) -> ((rid, who, node), (first, last, gender, town, month, bmonth, bday))); +let cands_filter = cands_join | filter((_, (_, _, _, _, month, bmonth, bday)) -> (((bmonth, month) eq, (bday, 21) ge) all, ((bmonth, ((month, 12) eq, 1, (month, 1) add) select) eq, (bday, 22) lt) all) any); +let cands = cands_filter | map((key, (first, last, gender, town, _, _, _)) -> (key, (first, last, gender, town))); +let wrote_map = cands | map(((rid, who, node), _) -> (node, (rid, who))); +let wrote_idx = wrote_map | arrange; -+let posts_idx = posts | arrange; -+let wrote = wrote_idx | join(posts_idx, (node, (rid, who), m) -> ((rid, who, node, m), ())); ++let wrote = wrote_idx | join(posts, (node, (rid, who), m) -> ((rid, who, node, m), ())); +let liked_map = wrote | map(((rid, who, node, m), ()) -> (m, (rid, who, node))); +let liked_idx = liked_map | arrange; -+let tags_of_idx = tags_of | arrange; -+let liked_join = liked_idx | join(tags_of_idx, (m, (rid, who, node), t) -> ((who, t), (rid, node, m))); ++let liked_join = liked_idx | join(tags_of, (m, (rid, who, node), t) -> ((who, t), (rid, node, m))); +let liked_idx2 = liked_join | arrange; -+let likes_idx = likes | arrange; -+let liked_join2 = liked_idx2 | join(likes_idx, ((who, _), (rid, node, m), ()) -> ((rid, who, node, m), ())); ++let liked_join2 = liked_idx2 | join(likes, ((who, _), (rid, node, m), ()) -> ((rid, who, node, m), ())); +let liked_idx3 = liked_join2 | arrange; +let liked = liked_idx3 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); +let points_map = liked | map(((rid, who, node, _), ()) -> ((rid, who, node), 1)); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.ddp index 697d6ee130..ddde2b17e8 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.ddp @@ -6,8 +6,7 @@ let place = import "graph::place" : (int, (List(int), List(int), int)); let interest = import "graph::interest.by_person" : (int, int); let people_map = person | map((id, (first, last, gender, _, _, _, _, home, bmonth, bday, _)) -> (home, (id, first, last, gender, bmonth, bday))); let people_idx = people_map | arrange; -let place_idx = place | arrange; -let people = people_idx | join(place_idx, (_, (id, first, last, gender, bmonth, bday), (town, _, _)) -> (id, (first, last, gender, town, bmonth, bday))); +let people = people_idx | join(place, (_, (id, first, last, gender, bmonth, bday), (town, _, _)) -> (id, (first, last, gender, town, bmonth, bday))); let posts = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq) | map((id, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, id)); let likes = interest | map((p, t) -> ((p, t), ())); let people_idx2 = people | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.lowered--optimized.diff index a30233b3aa..40d9b5b615 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.lowered--optimized.diff @@ -1,6 +1,6 @@ --- lowered +++ optimized -@@ -2,16 +2,13 @@ +@@ -2,15 +2,12 @@ -- Trace imports use provider arrangements; history advances to G = (0, []). let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); @@ -10,8 +10,7 @@ let interest = import "graph::interest.by_person" : (int, int); let people_map = person | map((id, (first, last, gender, _, _, _, _, home, bmonth, bday, _)) -> (home, (id, first, last, gender, bmonth, bday))); let people_idx = people_map | arrange; - let place_idx = place | arrange; - let people = people_idx | join(place_idx, (_, (id, first, last, gender, bmonth, bday), (town, _, _)) -> (id, (first, last, gender, town, bmonth, bday))); + let people = people_idx | join(place, (_, (id, first, last, gender, bmonth, bday), (town, _, _)) -> (id, (first, last, gender, town, bmonth, bday))); -let posts_filter = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq); -let posts = posts_filter | map((id, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, id)); +let posts = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq) | map((id, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, id)); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.parsed--lowered.diff index 0c15102e61..049bb3d1f9 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic10_standing.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,12 +1,24 @@ +@@ -1,12 +1,23 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); @@ -13,8 +13,7 @@ -let posts = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq) | map((id, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, id)); +let people_map = person | map((id, (first, last, gender, _, _, _, _, home, bmonth, bday, _)) -> (home, (id, first, last, gender, bmonth, bday))); +let people_idx = people_map | arrange; -+let place_idx = place | arrange; -+let people = people_idx | join(place_idx, (_, (id, first, last, gender, bmonth, bday), (town, _, _)) -> (id, (first, last, gender, town, bmonth, bday))); ++let people = people_idx | join(place, (_, (id, first, last, gender, bmonth, bday), (town, _, _)) -> (id, (first, last, gender, town, bmonth, bday))); +let posts_filter = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 0) eq); +let posts = posts_filter | map((id, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, id)); let likes = interest | map((p, t) -> ((p, t), ())); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.ddp index 8e51eb1649..1692d8b32e 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.ddp @@ -8,34 +8,29 @@ let org = import "graph::org" : (int, (List(int), List(int), int)); let place = import "graph::place" : (int, (List(int), List(int), int)); let hop1_map = request | map(((rid, who, country, year), ()) -> (who, (rid, who, country, year))); let hop1_idx = hop1_map | arrange; -let person_idx = person | arrange; -let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); +let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); let hop1_idx2 = hop1_join | arrange; -let friend_idx = friend | arrange; -let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); +let hop1 = hop1_idx2 | join(friend, (_, req, (f, _)) -> (f, req)); let hop1_idx3 = hop1 | arrange; -let hop2 = hop1_idx3 | join(friend_idx, (_, req, (g, _)) -> (g, req)); +let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); let circle_rows = hop1 + hop2; let circle_rows2 = circle_rows | filter((node, (_, who, _, _)) -> (node, who) ne) | map((node, (rid, _, country, year)) -> ((node, rid, country, year), ())); let circle_idx = circle_rows2 | arrange; let circle = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let jobs_map = circle | map(((node, rid, country, year), ()) -> (node, (rid, country, year))); let jobs_idx = jobs_map | arrange; -let work_idx = work | arrange; -let jobs_join = jobs_idx | join(work_idx, (node, (rid, country, year), (at, since)) -> (at, (rid, node, country, year, since))); +let jobs_join = jobs_idx | join(work, (node, (rid, country, year), (at, since)) -> (at, (rid, node, country, year, since))); let jobs_filter = jobs_join | filter((_, (_, _, _, year, since)) -> (since, year) lt); let jobs_idx2 = jobs_filter | arrange; -let org_idx = org | arrange; -let jobs_join2 = jobs_idx2 | join(org_idx, (_, (rid, node, country, _, since), (company, _, located)) -> (located, ((rid, since, node), (company, country)))); +let jobs_join2 = jobs_idx2 | join(org, (_, (rid, node, country, _, since), (company, _, located)) -> (located, ((rid, since, node), (company, country)))); let jobs_idx3 = jobs_join2 | arrange; -let place_idx = place | arrange; -let jobs_join3 = jobs_idx3 | join(place_idx, (_, (key, (company, country)), (there, _, _)) -> (key, (company, country, there))); +let jobs_join3 = jobs_idx3 | join(place, (_, (key, (company, country)), (there, _, _)) -> (key, (company, country, there))); let jobs = jobs_join3 | filter((_, (_, country, there)) -> (country, there) eq) | map((key, (company, _, _)) -> (key, company)); let jobs_idx4 = jobs | arrange; let named_reduce = jobs_idx4 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); let ranked_rows = named_reduce | flatmap((_, entries) -> entries) | map(((rid, since, node), (pos, company)) -> (node, (rid, since, pos, company))); let ranked_idx = ranked_rows | arrange; -let ranked_join = ranked_idx | join(person_idx, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); +let ranked_join = ranked_idx | join(person, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); let ranked_idx2 = ranked_join | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((since, node, _), (first, last, company)))) -> ((rid, rank), (node, first, last, company, since))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.lowered--optimized.diff index 4812e94835..09078cb78a 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.lowered--optimized.diff @@ -1,12 +1,8 @@ --- lowered +++ optimized -@@ -14,12 +14,10 @@ - let friend_idx = friend | arrange; - let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); +@@ -14,9 +14,8 @@ let hop1_idx3 = hop1 | arrange; --let friend_idx2 = friend | arrange; --let hop2 = hop1_idx3 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); -+let hop2 = hop1_idx3 | join(friend_idx, (_, req, (g, _)) -> (g, req)); + let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); let circle_rows = hop1 + hop2; -let circle_filter = circle_rows | filter((node, (_, who, _, _)) -> (node, who) ne); -let circle_map = circle_filter | map((node, (rid, _, country, year)) -> ((node, rid, country, year), ())); @@ -16,10 +12,10 @@ let circle = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let jobs_map = circle | map(((node, rid, country, year), ()) -> (node, (rid, country, year))); let jobs_idx = jobs_map | arrange; -@@ -32,15 +30,12 @@ +@@ -26,13 +25,11 @@ + let jobs_join2 = jobs_idx2 | join(org, (_, (rid, node, country, _, since), (company, _, located)) -> (located, ((rid, since, node), (company, country)))); let jobs_idx3 = jobs_join2 | arrange; - let place_idx = place | arrange; - let jobs_join3 = jobs_idx3 | join(place_idx, (_, (key, (company, country)), (there, _, _)) -> (key, (company, country, there))); + let jobs_join3 = jobs_idx3 | join(place, (_, (key, (company, country)), (there, _, _)) -> (key, (company, country, there))); -let jobs_filter2 = jobs_join3 | filter((_, (_, country, there)) -> (country, there) eq); -let jobs = jobs_filter2 | map((key, (company, _, _)) -> (key, company)); +let jobs = jobs_join3 | filter((_, (_, country, there)) -> (country, there) eq) | map((key, (company, _, _)) -> (key, company)); @@ -28,11 +24,8 @@ -let named = named_reduce | flatmap((_, entries) -> entries); -let ranked_map = named | map(((rid, since, node), (pos, company)) -> (node, (rid, since, pos, company))); -let ranked_idx = ranked_map | arrange; --let person_idx2 = person | arrange; --let ranked_join = ranked_idx | join(person_idx2, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); +let ranked_rows = named_reduce | flatmap((_, entries) -> entries) | map(((rid, since, node), (pos, company)) -> (node, (rid, since, pos, company))); +let ranked_idx = ranked_rows | arrange; -+let ranked_join = ranked_idx | join(person_idx, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); + let ranked_join = ranked_idx | join(person, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); let ranked_idx2 = ranked_join | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); - let answer = ranked | map((rid, (rank, ((since, node, _), (first, last, company)))) -> ((rid, rank), (node, first, last, company, since))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.parsed--lowered.diff index 1ff2a9cf0e..818eec8772 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic11_oneoff.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,14 +1,49 @@ +@@ -1,14 +1,42 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int, List(int), int), ()); @@ -17,14 +17,11 @@ -let ranked = named | map(((rid, since, node), (pos, company)) -> (node, (rid, since, pos, company))) | join(person, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let hop1_map = request | map(((rid, who, country, year), ()) -> (who, (rid, who, country, year))); +let hop1_idx = hop1_map | arrange; -+let person_idx = person | arrange; -+let hop1_join = hop1_idx | join(person_idx, (who, req, _) -> (who, req)); ++let hop1_join = hop1_idx | join(person, (who, req, _) -> (who, req)); +let hop1_idx2 = hop1_join | arrange; -+let friend_idx = friend | arrange; -+let hop1 = hop1_idx2 | join(friend_idx, (_, req, (f, _)) -> (f, req)); ++let hop1 = hop1_idx2 | join(friend, (_, req, (f, _)) -> (f, req)); +let hop1_idx3 = hop1 | arrange; -+let friend_idx2 = friend | arrange; -+let hop2 = hop1_idx3 | join(friend_idx2, (_, req, (g, _)) -> (g, req)); ++let hop2 = hop1_idx3 | join(friend, (_, req, (g, _)) -> (g, req)); +let circle_rows = hop1 + hop2; +let circle_filter = circle_rows | filter((node, (_, who, _, _)) -> (node, who) ne); +let circle_map = circle_filter | map((node, (rid, _, country, year)) -> ((node, rid, country, year), ())); @@ -32,15 +29,12 @@ +let circle = circle_idx | reduce((_, vals) -> vals map (((), _) -> ((), 1))); +let jobs_map = circle | map(((node, rid, country, year), ()) -> (node, (rid, country, year))); +let jobs_idx = jobs_map | arrange; -+let work_idx = work | arrange; -+let jobs_join = jobs_idx | join(work_idx, (node, (rid, country, year), (at, since)) -> (at, (rid, node, country, year, since))); ++let jobs_join = jobs_idx | join(work, (node, (rid, country, year), (at, since)) -> (at, (rid, node, country, year, since))); +let jobs_filter = jobs_join | filter((_, (_, _, _, year, since)) -> (since, year) lt); +let jobs_idx2 = jobs_filter | arrange; -+let org_idx = org | arrange; -+let jobs_join2 = jobs_idx2 | join(org_idx, (_, (rid, node, country, _, since), (company, _, located)) -> (located, ((rid, since, node), (company, country)))); ++let jobs_join2 = jobs_idx2 | join(org, (_, (rid, node, country, _, since), (company, _, located)) -> (located, ((rid, since, node), (company, country)))); +let jobs_idx3 = jobs_join2 | arrange; -+let place_idx = place | arrange; -+let jobs_join3 = jobs_idx3 | join(place_idx, (_, (key, (company, country)), (there, _, _)) -> (key, (company, country, there))); ++let jobs_join3 = jobs_idx3 | join(place, (_, (key, (company, country)), (there, _, _)) -> (key, (company, country, there))); +let jobs_filter2 = jobs_join3 | filter((_, (_, country, there)) -> (country, there) eq); +let jobs = jobs_filter2 | map((key, (company, _, _)) -> (key, company)); +let jobs_idx4 = jobs | arrange; @@ -48,8 +42,7 @@ +let named = named_reduce | flatmap((_, entries) -> entries); +let ranked_map = named | map(((rid, since, node), (pos, company)) -> (node, (rid, since, pos, company))); +let ranked_idx = ranked_map | arrange; -+let person_idx2 = person | arrange; -+let ranked_join = ranked_idx | join(person_idx2, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); ++let ranked_join = ranked_idx | join(person, (node, (rid, since, pos, company), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since, node, pos neg), (first, last, company)))); +let ranked_idx2 = ranked_join | arrange; +let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((since, node, _), (first, last, company)))) -> ((rid, rank), (node, first, last, company, since))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.ddp index 87b54fff31..97d524fff3 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.ddp @@ -12,30 +12,22 @@ let below_hl = import "ic12s::below_hl" : (int, int); let reply = import "ic12s::reply" : (int, (int, int)); let intag_map = request | map(((rid, _, name), ()) -> (name, rid)); let intag_idx = intag_map | arrange; -let classes_idx = classes | arrange; -let intag_join = intag_idx | join(classes_idx, (_, rid, high) -> (high, rid)); +let intag_join = intag_idx | join(classes, (_, rid, high) -> (high, rid)); let intag_idx2 = intag_join | arrange; -let below_hl_idx = below_hl | arrange; -let intag_join2 = intag_idx2 | join(below_hl_idx, (_, rid, low) -> (low, rid)); +let intag_join2 = intag_idx2 | join(below_hl, (_, rid, low) -> (low, rid)); let intag_idx3 = intag_join2 | arrange; -let by_class_idx = by_class | arrange; -let intag_join3 = intag_idx3 | join(by_class_idx, (_, rid, t) -> (t, rid)); +let intag_join3 = intag_idx3 | join(by_class, (_, rid, t) -> (t, rid)); let intag_idx4 = intag_join3 | arrange; -let tag_idx = tag | arrange; -let intag_join4 = intag_idx4 | join(tag_idx, (t, rid, (name, _)) -> (t, (rid, name))); +let intag_join4 = intag_idx4 | join(tag, (t, rid, (name, _)) -> (t, (rid, name))); let intag_idx5 = intag_join4 | arrange; -let mtag_idx = mtag | arrange; -let intag_join5 = intag_idx5 | join(mtag_idx, (_, (rid, name), m) -> (m, (rid, name))); +let intag_join5 = intag_idx5 | join(mtag, (_, (rid, name), m) -> (m, (rid, name))); let intag_idx6 = intag_join5 | arrange; -let message_idx = message | arrange; -let intag_join6 = intag_idx6 | join(message_idx, (m, (rid, name), (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> ((rid, m, name), kind)); +let intag_join6 = intag_idx6 | join(message, (m, (rid, name), (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> ((rid, m, name), kind)); let hits_map = request | map(((rid, who, _), ()) -> (who, rid)); let hits_idx = hits_map | arrange; -let friend_idx = friend | arrange; -let hits_join = hits_idx | join(friend_idx, (_, rid, (f, _)) -> (f, rid)); +let hits_join = hits_idx | join(friend, (_, rid, (f, _)) -> (f, rid)); let hits_idx2 = hits_join | arrange; -let reply_idx = reply | arrange; -let hits_join2 = hits_idx2 | join(reply_idx, (f, rid, (id, parent)) -> ((rid, parent), (f, id))); +let hits_join2 = hits_idx2 | join(reply, (f, rid, (id, parent)) -> ((rid, parent), (f, id))); let hits_idx3 = hits_join2 | arrange; let hits_rows = intag_join6 | filter((_, kind) -> (kind, 0) eq) | map(((a, b, c), _) -> ((a, b), c)); let hits_idx4 = hits_rows | arrange; @@ -54,8 +46,7 @@ let tagset_idx2 = tagset_map2 | arrange; let tagset = tagset_idx2 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); let ranked_join = counts | join(tagset, ((rid, f), n, list) -> (f, (rid, n, list))); let ranked_idx = ranked_join | arrange; -let person_idx = person | arrange; -let ranked_join2 = ranked_idx | join(person_idx, (f, (rid, n, list), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((n neg, f), (first, last, list)))); +let ranked_join2 = ranked_idx | join(person, (f, (rid, n, list), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((n neg, f), (first, last, list)))); let ranked_idx2 = ranked_join2 | arrange; let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((neg, f), (first, last, list)))) -> ((rid, rank), (f, first, last, list, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.lowered--optimized.diff index 45a66d7934..a3f1327684 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.lowered--optimized.diff @@ -8,18 +8,17 @@ let classes = import "graph::tagclass.by_name" : (List(int), int); let mtag = import "graph::mtag.by_tag" : (int, int); let below_hl = import "ic12s::below_hl" : (int, int); -@@ -30,8 +29,6 @@ +@@ -24,16 +23,14 @@ + let intag_join5 = intag_idx5 | join(mtag, (_, (rid, name), m) -> (m, (rid, name))); let intag_idx6 = intag_join5 | arrange; - let message_idx = message | arrange; - let intag_join6 = intag_idx6 | join(message_idx, (m, (rid, name), (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> ((rid, m, name), kind)); + let intag_join6 = intag_idx6 | join(message, (m, (rid, name), (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> ((rid, m, name), kind)); -let intag_filter = intag_join6 | filter((_, kind) -> (kind, 0) eq); -let intag = intag_filter | map((key, _) -> (key, ())); let hits_map = request | map(((rid, who, _), ()) -> (who, rid)); let hits_idx = hits_map | arrange; - let friend_idx = friend | arrange; -@@ -40,8 +37,8 @@ - let reply_idx = reply | arrange; - let hits_join2 = hits_idx2 | join(reply_idx, (f, rid, (id, parent)) -> ((rid, parent), (f, id))); + let hits_join = hits_idx | join(friend, (_, rid, (f, _)) -> (f, rid)); + let hits_idx2 = hits_join | arrange; + let hits_join2 = hits_idx2 | join(reply, (f, rid, (id, parent)) -> ((rid, parent), (f, id))); let hits_idx3 = hits_join2 | arrange; -let hits_map2 = intag | map(((rid, m, name), ()) -> ((rid, m), name)); -let hits_idx4 = hits_map2 | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.parsed--lowered.diff index 0fa2979137..4eac7d0dee 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic12_oneoff.parsed--lowered.diff @@ -6,7 +6,7 @@ let request = input 0 : ((int, int, List(int)), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); -@@ -9,10 +11,57 @@ +@@ -9,10 +11,48 @@ let mtag = import "graph::mtag.by_tag" : (int, int); let below_hl = import "ic12s::below_hl" : (int, int); let reply = import "ic12s::reply" : (int, (int, int)); @@ -17,32 +17,24 @@ -let ranked = counts | join(tagset, ((rid, f), n, list) -> (f, (rid, n, list))) | join(person, (f, (rid, n, list), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((n neg, f), (first, last, list)))) | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let intag_map = request | map(((rid, _, name), ()) -> (name, rid)); +let intag_idx = intag_map | arrange; -+let classes_idx = classes | arrange; -+let intag_join = intag_idx | join(classes_idx, (_, rid, high) -> (high, rid)); ++let intag_join = intag_idx | join(classes, (_, rid, high) -> (high, rid)); +let intag_idx2 = intag_join | arrange; -+let below_hl_idx = below_hl | arrange; -+let intag_join2 = intag_idx2 | join(below_hl_idx, (_, rid, low) -> (low, rid)); ++let intag_join2 = intag_idx2 | join(below_hl, (_, rid, low) -> (low, rid)); +let intag_idx3 = intag_join2 | arrange; -+let by_class_idx = by_class | arrange; -+let intag_join3 = intag_idx3 | join(by_class_idx, (_, rid, t) -> (t, rid)); ++let intag_join3 = intag_idx3 | join(by_class, (_, rid, t) -> (t, rid)); +let intag_idx4 = intag_join3 | arrange; -+let tag_idx = tag | arrange; -+let intag_join4 = intag_idx4 | join(tag_idx, (t, rid, (name, _)) -> (t, (rid, name))); ++let intag_join4 = intag_idx4 | join(tag, (t, rid, (name, _)) -> (t, (rid, name))); +let intag_idx5 = intag_join4 | arrange; -+let mtag_idx = mtag | arrange; -+let intag_join5 = intag_idx5 | join(mtag_idx, (_, (rid, name), m) -> (m, (rid, name))); ++let intag_join5 = intag_idx5 | join(mtag, (_, (rid, name), m) -> (m, (rid, name))); +let intag_idx6 = intag_join5 | arrange; -+let message_idx = message | arrange; -+let intag_join6 = intag_idx6 | join(message_idx, (m, (rid, name), (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> ((rid, m, name), kind)); ++let intag_join6 = intag_idx6 | join(message, (m, (rid, name), (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> ((rid, m, name), kind)); +let intag_filter = intag_join6 | filter((_, kind) -> (kind, 0) eq); +let intag = intag_filter | map((key, _) -> (key, ())); +let hits_map = request | map(((rid, who, _), ()) -> (who, rid)); +let hits_idx = hits_map | arrange; -+let friend_idx = friend | arrange; -+let hits_join = hits_idx | join(friend_idx, (_, rid, (f, _)) -> (f, rid)); ++let hits_join = hits_idx | join(friend, (_, rid, (f, _)) -> (f, rid)); +let hits_idx2 = hits_join | arrange; -+let reply_idx = reply | arrange; -+let hits_join2 = hits_idx2 | join(reply_idx, (f, rid, (id, parent)) -> ((rid, parent), (f, id))); ++let hits_join2 = hits_idx2 | join(reply, (f, rid, (id, parent)) -> ((rid, parent), (f, id))); +let hits_idx3 = hits_join2 | arrange; +let hits_map2 = intag | map(((rid, m, name), ()) -> ((rid, m), name)); +let hits_idx4 = hits_map2 | arrange; @@ -61,8 +53,7 @@ +let tagset = tagset_idx2 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let ranked_join = counts | join(tagset, ((rid, f), n, list) -> (f, (rid, n, list))); +let ranked_idx = ranked_join | arrange; -+let person_idx = person | arrange; -+let ranked_join2 = ranked_idx | join(person_idx, (f, (rid, n, list), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((n neg, f), (first, last, list)))); ++let ranked_join2 = ranked_idx | join(person, (f, (rid, n, list), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((n neg, f), (first, last, list)))); +let ranked_idx2 = ranked_join2 | arrange; +let ranked = ranked_idx2 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 20) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 20) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 20) min in let before = (end, count) sub in let keep = (((20, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer = ranked | map((rid, (rank, ((neg, f), (first, last, list)))) -> ((rid, rank), (f, first, last, list, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.lowered--optimized.diff index fcae73f9d5..c8499e64fa 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.lowered--optimized.diff @@ -1,6 +1,6 @@ --- lowered +++ optimized -@@ -1,31 +1,22 @@ +@@ -1,13 +1,7 @@ -- Time lanes: epoch. -- Trace imports use provider arrangements; history advances to G = (0, []). -let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); @@ -14,14 +14,12 @@ let selves = tagclass | map((id, _) -> ((id, id), ())); below: { -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. - var below; +@@ -15,16 +9,14 @@ let step_map = below | map(((low, high), ()) -> (high, low)); let step_idx = step_map | arrange; -- let tagclass_idx = ::tagclass | arrange; -- let step_join = step_idx | join(tagclass_idx, (_, low, (_, parent)) -> (low, parent)); + let step_join = step_idx | join(::tagclass, (_, low, (_, parent)) -> (low, parent)); - let step_filter = step_join | filter((_, parent) -> (parent, 0) ge); - let step = step_filter | map((low, higher) -> ((low, higher), ())); -+ let step_join = step_idx | join(::tagclass, (_, low, (_, parent)) -> (low, parent)); + let step = step_join | filter((_, parent) -> (parent, 0) ge) | map((low, higher) -> ((low, higher), ())); let below_rows = ::selves + step; let below_idx = below_rows | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.parsed--lowered.diff index 9b0d442607..393fc2b43d 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic12_standing.parsed--lowered.diff @@ -6,7 +6,7 @@ let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); let friend = import "graph::friend" : (int, (int, int)); -@@ -8,10 +10,25 @@ +@@ -8,10 +10,24 @@ let mtag = import "graph::mtag.by_tag" : (int, int); let selves = tagclass | map((id, _) -> ((id, id), ())); below: { @@ -16,8 +16,7 @@ + var below; + let step_map = below | map(((low, high), ()) -> (high, low)); + let step_idx = step_map | arrange; -+ let tagclass_idx = ::tagclass | arrange; -+ let step_join = step_idx | join(tagclass_idx, (_, low, (_, parent)) -> (low, parent)); ++ let step_join = step_idx | join(::tagclass, (_, low, (_, parent)) -> (low, parent)); + let step_filter = step_join | filter((_, parent) -> (parent, 0) ge); + let step = step_filter | map((low, higher) -> ((low, higher), ())); + let below_rows = ::selves + step; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.lowered--optimized.diff index 0c55c21175..714c0dd13f 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.lowered--optimized.diff @@ -13,7 +13,7 @@ let side0_idx = side0 | arrange; let side1_idx = side1 | arrange; let best_join = side0_idx | join(side1_idx, ((rid, _), d0, d1) -> (rid, (d0, d1) add)); -@@ -24,15 +22,12 @@ +@@ -24,10 +22,8 @@ let open_join = by_rid_idx | join(met_idx, (rid, row, ()) -> (rid, row)); let open_neg = open_join | negate; let open = by_rid + open_neg; @@ -26,13 +26,7 @@ let grow_rows = open + near; let grow_map = grow_rows | map((rid, (side, node, d)) -> (node, (rid, side, d))); let grow_idx = grow_map | arrange; -- let friend_idx = ::friend | arrange; -- let grow = grow_idx | join(friend_idx, (_, (rid, side, d), (next, _)) -> ((rid, side, next, (d, 1) add), ())); -+ let grow = grow_idx | join(::friend, (_, (rid, side, d), (next, _)) -> ((rid, side, next, (d, 1) add), ())); - let search_rows = ::starts + search + grow; - let search_map = search_rows | map(((rid, side, node, d), ()) -> ((rid, side, node), d)); - let search_idx = search_map | arrange; -@@ -40,10 +35,8 @@ +@@ -39,10 +35,8 @@ let search_map2 = search_reduce | map(((rid, side, node), d) -> ((rid, side, node, d), ())); set search = search_map2; } diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.parsed--lowered.diff index c506c1ed96..2cee3bf616 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic13_oneoff.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,21 +1,62 @@ +@@ -1,21 +1,61 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int, int), ()); @@ -42,8 +42,7 @@ + let grow_rows = open + near; + let grow_map = grow_rows | map((rid, (side, node, d)) -> (node, (rid, side, d))); + let grow_idx = grow_map | arrange; -+ let friend_idx = ::friend | arrange; -+ let grow = grow_idx | join(friend_idx, (_, (rid, side, d), (next, _)) -> ((rid, side, next, (d, 1) add), ())); ++ let grow = grow_idx | join(::friend, (_, (rid, side, d), (next, _)) -> ((rid, side, next, (d, 1) add), ())); + let search_rows = ::starts + search + grow; + let search_map = search_rows | map(((rid, side, node, d), ()) -> ((rid, side, node), d)); + let search_idx = search_map | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.ddp index 55d86150c4..8e446dd962 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.ddp @@ -18,8 +18,7 @@ dist: { let best = dist::dist | map(((rid, node, cost), ()) -> ((rid, node), cost)); let pred_map = dist::dist | map(((rid, u, cost), ()) -> (u, (rid, cost))); let pred_idx = pred_map | arrange; -let weighted_idx = weighted | arrange; -let pred_join = pred_idx | join(weighted_idx, (u, (rid, cost), (v, w)) -> ((rid, v), (u, (cost, w) add))); +let pred_join = pred_idx | join(weighted, (u, (rid, cost), (v, w)) -> ((rid, v), (u, (cost, w) add))); let pred_idx2 = pred_join | arrange; let best_idx = best | arrange; let pred_join2 = pred_idx2 | join(best_idx, ((rid, v), (u, via), least) -> ((rid, v), (u, via, least))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.lowered--optimized.diff index bd7f36fcaa..4aab3c07d6 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.lowered--optimized.diff @@ -9,17 +9,7 @@ let weighted = import "ic14s::weighted" : (int, (int, int)); let starts = request | map(((rid, from, _), ()) -> ((rid, from), 0)); dist: { -@@ -10,8 +8,7 @@ - var dist; - let grow_map = dist | map(((rid, node, cost), ()) -> (node, (rid, cost))); - let grow_idx = grow_map | arrange; -- let weighted_idx = ::weighted | arrange; -- let grow = grow_idx | join(weighted_idx, (_, (rid, cost), (next, w)) -> ((rid, next), (cost, w) add)); -+ let grow = grow_idx | join(::weighted, (_, (rid, cost), (next, w)) -> ((rid, next), (cost, w) add)); - let dist_rows = ::starts + grow; - let dist_idx = dist_rows | arrange; - let dist_reduce = dist_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); -@@ -26,39 +23,34 @@ +@@ -24,32 +22,28 @@ let pred_idx2 = pred_join | arrange; let best_idx = best | arrange; let pred_join2 = pred_idx2 | join(best_idx, ((rid, v), (u, via), least) -> ((rid, v), (u, via, least))); @@ -57,15 +47,7 @@ walk: { -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. var walk; - let step_map = walk | map(((rid, node, path), ()) -> ((rid, node), path)); - let step_idx = step_map | arrange; -- let next_idx = ::next | arrange; -- let step = step_idx | join(next_idx, ((rid, _), path, v) -> ((rid, v, (path, v enlist) append), ())); -+ let step = step_idx | join(::next, ((rid, _), path, v) -> ((rid, v, (path, v enlist) append), ())); - let walk_rows = ::first + step; - set walk = walk_rows; - } -@@ -67,8 +59,7 @@ +@@ -64,8 +58,7 @@ let targets_idx2 = targets | arrange; let answer_join = answer_idx | join(targets_idx2, ((rid, node), path, ()) -> ((rid, node), path)); let answer_idx2 = answer_join | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.parsed--lowered.diff index d5d7d4e92f..5bf9c15db1 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic14_oneoff.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,24 +1,74 @@ +@@ -1,24 +1,71 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int, int), ()); @@ -15,8 +15,7 @@ + var dist; + let grow_map = dist | map(((rid, node, cost), ()) -> (node, (rid, cost))); + let grow_idx = grow_map | arrange; -+ let weighted_idx = ::weighted | arrange; -+ let grow = grow_idx | join(weighted_idx, (_, (rid, cost), (next, w)) -> ((rid, next), (cost, w) add)); ++ let grow = grow_idx | join(::weighted, (_, (rid, cost), (next, w)) -> ((rid, next), (cost, w) add)); + let dist_rows = ::starts + grow; + let dist_idx = dist_rows | arrange; + let dist_reduce = dist_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); @@ -28,8 +27,7 @@ -let targets = request | map(((rid, _, to), ()) -> ((rid, to), ())) | join(best, (key, (), _) -> (key, ())); +let pred_map = dist::dist | map(((rid, u, cost), ()) -> (u, (rid, cost))); +let pred_idx = pred_map | arrange; -+let weighted_idx = weighted | arrange; -+let pred_join = pred_idx | join(weighted_idx, (u, (rid, cost), (v, w)) -> ((rid, v), (u, (cost, w) add))); ++let pred_join = pred_idx | join(weighted, (u, (rid, cost), (v, w)) -> ((rid, v), (u, (cost, w) add))); +let pred_idx2 = pred_join | arrange; +let best_idx = best | arrange; +let pred_join2 = pred_idx2 | join(best_idx, ((rid, v), (u, via), least) -> ((rid, v), (u, via, least))); @@ -70,8 +68,7 @@ + var walk; + let step_map = walk | map(((rid, node, path), ()) -> ((rid, node), path)); + let step_idx = step_map | arrange; -+ let next_idx = ::next | arrange; -+ let step = step_idx | join(next_idx, ((rid, _), path, v) -> ((rid, v, (path, v enlist) append), ())); ++ let step = step_idx | join(::next, ((rid, _), path, v) -> ((rid, v, (path, v enlist) append), ())); + let walk_rows = ::first + step; + set walk = walk_rows; } diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.ddp b/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.ddp index 7ea9f852a1..544b8d7e63 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.ddp @@ -4,16 +4,14 @@ let message = import "graph::message" : (int, (int, int, int, int, List(int), Li let pals = import "graph::friend.pair" : ((int, int), ()); let answered_rows = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 1) eq) | map((_, (_, _, who, _, _, _, _, _, _, parent, _, _, _)) -> (parent, who)); let answered_idx = answered_rows | arrange; -let message_idx = message | arrange; -let answered_join = answered_idx | join(message_idx, (_, who, (_, _, to, _, _, _, _, _, _, _, _, _, _)) -> (who, to)); +let answered_join = answered_idx | join(message, (_, who, (_, _, to, _, _, _, _, _, _, _, _, _, _)) -> (who, to)); let answered = answered_join | filter((who, to) -> (who, to) ne); let talks_map = answered | map((a, b) -> ((a, b), ())); let talks_map2 = answered | map((a, b) -> ((b, a), ())); let talks = talks_map + talks_map2; let talks_idx = talks | arrange; let weighted_reduce = talks_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); -let pals_idx = pals | arrange; -let weighted_join = weighted_reduce | join(pals_idx, (pair, n, ()) -> (pair, n)); +let weighted_join = weighted_reduce | join(pals, (pair, n, ()) -> (pair, n)); let weighted = weighted_join | map(((a, b), n) -> (a, (b, (((0, n), (1, 40) range) fold (((acc, n), k) -> ((acc, ((((k, (k, 1) sub) mul, 1) add, n) gt, 1, 0) select) add, n)) .0, 1) add))); let weighted_idx = weighted | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.lowered--optimized.diff index b63f2011ea..10eb251314 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.lowered--optimized.diff @@ -9,6 +9,6 @@ -let answered_idx = answered_map | arrange; +let answered_rows = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 1) eq) | map((_, (_, _, who, _, _, _, _, _, _, parent, _, _, _)) -> (parent, who)); +let answered_idx = answered_rows | arrange; - let message_idx = message | arrange; - let answered_join = answered_idx | join(message_idx, (_, who, (_, _, to, _, _, _, _, _, _, _, _, _, _)) -> (who, to)); + let answered_join = answered_idx | join(message, (_, who, (_, _, to, _, _, _, _, _, _, _, _, _, _)) -> (who, to)); let answered = answered_join | filter((who, to) -> (who, to) ne); + let talks_map = answered | map((a, b) -> ((a, b), ())); diff --git a/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.parsed--lowered.diff index 926ece7aef..c5a71a3ae1 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_ic14_standing.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,7 +1,22 @@ +@@ -1,7 +1,20 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); @@ -11,16 +11,14 @@ +let answered_filter = message | filter((_, (kind, _, _, _, _, _, _, _, _, _, _, _, _)) -> (kind, 1) eq); +let answered_map = answered_filter | map((_, (_, _, who, _, _, _, _, _, _, parent, _, _, _)) -> (parent, who)); +let answered_idx = answered_map | arrange; -+let message_idx = message | arrange; -+let answered_join = answered_idx | join(message_idx, (_, who, (_, _, to, _, _, _, _, _, _, _, _, _, _)) -> (who, to)); ++let answered_join = answered_idx | join(message, (_, who, (_, _, to, _, _, _, _, _, _, _, _, _, _)) -> (who, to)); +let answered = answered_join | filter((who, to) -> (who, to) ne); +let talks_map = answered | map((a, b) -> ((a, b), ())); +let talks_map2 = answered | map((a, b) -> ((b, a), ())); +let talks = talks_map + talks_map2; +let talks_idx = talks | arrange; +let weighted_reduce = talks_idx | reduce((_, vals) -> let diffs = vals map ((_, d) -> d) in let n = diffs fold_add in (n, (n, 1)) enlist filter); -+let pals_idx = pals | arrange; -+let weighted_join = weighted_reduce | join(pals_idx, (pair, n, ()) -> (pair, n)); ++let weighted_join = weighted_reduce | join(pals, (pair, n, ()) -> (pair, n)); +let weighted = weighted_join | map(((a, b), n) -> (a, (b, (((0, n), (1, 40) range) fold (((acc, n), k) -> ((acc, ((((k, (k, 1) sub) mul, 1) add, n) gt, 1, 0) select) add, n)) .0, 1) add))); -output "weighted" = weighted | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is01.ddp b/interactive/tests/plan_pairs/expected/ldbc_is01.ddp index c4de7b330d..f528576057 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is01.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is01.ddp @@ -4,8 +4,7 @@ let request = input 0 : ((int, int), ()); let person = import "graph::person" : (int, (List(int), List(int), List(int), int, int, List(int), List(int), int, int, int, int)); let answer_map = request | map(((rid, who), ()) -> (who, rid)); let answer_idx = answer_map | arrange; -let person_idx = person | arrange; -let answer = answer_idx | join(person_idx, (_, rid, (first, last, gender, birthday, created, ip, browser, city, _, _, _)) -> ((rid, 0), (first, last, birthday, ip, browser, city, gender, created))); +let answer = answer_idx | join(person, (_, rid, (first, last, gender, birthday, created, ip, browser, city, _, _, _)) -> ((rid, 0), (first, last, birthday, ip, browser, city, gender, created))); let answer_idx2 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx2; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is01.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is01.parsed--lowered.diff index 884638de4e..9553afaadc 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is01.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is01.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,4 +1,11 @@ +@@ -1,4 +1,10 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -9,8 +9,7 @@ -output "answer" = answer | arrange; +let answer_map = request | map(((rid, who), ()) -> (who, rid)); +let answer_idx = answer_map | arrange; -+let person_idx = person | arrange; -+let answer = answer_idx | join(person_idx, (_, rid, (first, last, gender, birthday, created, ip, browser, city, _, _, _)) -> ((rid, 0), (first, last, birthday, ip, browser, city, gender, created))); ++let answer = answer_idx | join(person, (_, rid, (first, last, gender, birthday, created, ip, browser, city, _, _, _)) -> ((rid, 0), (first, last, birthday, ip, browser, city, gender, created))); +let answer_idx2 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx2; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is02.ddp b/interactive/tests/plan_pairs/expected/ldbc_is02.ddp index 6a52ec2c1a..d452231b28 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is02.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is02.ddp @@ -7,24 +7,20 @@ let by_creator = import "graph::message.by_creator" : (int, int); let root_of = import "graph::message.root" : (int, int); let mine_map = request | map(((rid, who), ()) -> (who, rid)); let mine_idx = mine_map | arrange; -let by_creator_idx = by_creator | arrange; -let mine_join = mine_idx | join(by_creator_idx, (_, rid, id) -> (id, rid)); +let mine_join = mine_idx | join(by_creator, (_, rid, id) -> (id, rid)); let mine_idx2 = mine_join | arrange; -let message_idx = message | arrange; -let mine_join2 = mine_idx2 | join(message_idx, (id, rid, (_, created, _, _, _, _, _, _, _, _, _, _, _)) -> (id, (rid, created))); +let mine_join2 = mine_idx2 | join(message, (id, rid, (_, created, _, _, _, _, _, _, _, _, _, _, _)) -> (id, (rid, created))); let mine_idx3 = mine_join2 | arrange; -let root_of_idx = root_of | arrange; -let mine = mine_idx3 | join(root_of_idx, (id, (rid, created), root) -> (rid, ((created neg, id neg), (id, created, root)))); +let mine = mine_idx3 | join(root_of, (id, (rid, created), root) -> (rid, ((created neg, id neg), (id, created, root)))); let mine_idx4 = mine | arrange; let top = mine_idx4 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); let answer_map = top | map((rid, (rank, (_, (id, created, root)))) -> (id, (rid, rank, created, root))); let answer_idx = answer_map | arrange; -let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, root), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (root, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); +let answer_join = answer_idx | join(message, (id, (rid, rank, created, root), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (root, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); let answer_idx2 = answer_join | arrange; -let answer_join2 = answer_idx2 | join(message_idx, (root, (rid, rank, id, body, created), (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (op, (rid, rank, id, body, created, root))); +let answer_join2 = answer_idx2 | join(message, (root, (rid, rank, id, body, created), (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (op, (rid, rank, id, body, created, root))); let answer_idx3 = answer_join2 | arrange; -let person_idx = person | arrange; -let answer = answer_idx3 | join(person_idx, (op, (rid, rank, id, body, created, root), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (id, body, created, root, op, first, last))); +let answer = answer_idx3 | join(person, (op, (rid, rank, id, body, created, root), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (id, body, created, root, op, first, last))); let answer_idx4 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx4; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is02.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_is02.lowered--optimized.diff index fff47f8666..e69de29bb2 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is02.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is02.lowered--optimized.diff @@ -1,16 +0,0 @@ ---- lowered -+++ optimized -@@ -19,11 +19,9 @@ - let top = mine_idx4 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); - let answer_map = top | map((rid, (rank, (_, (id, created, root)))) -> (id, (rid, rank, created, root))); - let answer_idx = answer_map | arrange; --let message_idx2 = message | arrange; --let answer_join = answer_idx | join(message_idx2, (id, (rid, rank, created, root), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (root, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); -+let answer_join = answer_idx | join(message_idx, (id, (rid, rank, created, root), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (root, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); - let answer_idx2 = answer_join | arrange; --let message_idx3 = message | arrange; --let answer_join2 = answer_idx2 | join(message_idx3, (root, (rid, rank, id, body, created), (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (op, (rid, rank, id, body, created, root))); -+let answer_join2 = answer_idx2 | join(message_idx, (root, (rid, rank, id, body, created), (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (op, (rid, rank, id, body, created, root))); - let answer_idx3 = answer_join2 | arrange; - let person_idx = person | arrange; - let answer = answer_idx3 | join(person_idx, (op, (rid, rank, id, body, created, root), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (id, body, created, root, op, first, last))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_is02.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is02.parsed--lowered.diff index 67b0104cc8..7801a80ec0 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is02.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is02.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,9 +1,32 @@ +@@ -1,9 +1,26 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -14,26 +14,20 @@ -output "answer" = answer | arrange; +let mine_map = request | map(((rid, who), ()) -> (who, rid)); +let mine_idx = mine_map | arrange; -+let by_creator_idx = by_creator | arrange; -+let mine_join = mine_idx | join(by_creator_idx, (_, rid, id) -> (id, rid)); ++let mine_join = mine_idx | join(by_creator, (_, rid, id) -> (id, rid)); +let mine_idx2 = mine_join | arrange; -+let message_idx = message | arrange; -+let mine_join2 = mine_idx2 | join(message_idx, (id, rid, (_, created, _, _, _, _, _, _, _, _, _, _, _)) -> (id, (rid, created))); ++let mine_join2 = mine_idx2 | join(message, (id, rid, (_, created, _, _, _, _, _, _, _, _, _, _, _)) -> (id, (rid, created))); +let mine_idx3 = mine_join2 | arrange; -+let root_of_idx = root_of | arrange; -+let mine = mine_idx3 | join(root_of_idx, (id, (rid, created), root) -> (rid, ((created neg, id neg), (id, created, root)))); ++let mine = mine_idx3 | join(root_of, (id, (rid, created), root) -> (rid, ((created neg, id neg), (id, created, root)))); +let mine_idx4 = mine | arrange; +let top = mine_idx4 | reduce((_, vals) -> let positive = (vals map ((_, d) -> (d, 0) gt), (0, vals len) range) zip filter in let indices = ((0, (positive len, 10) min) range, positive) gather in let prefix = (indices, vals) gather in let ends = prefix map ((_, d) -> (d, 10) min) scan_add in let chosen = (prefix, ends) zip map (((item, d), end) -> let count = (d, 10) min in let before = (end, count) sub in let keep = (((10, before) sub, 0) max, count) min in ((keep, 0) gt, (item, keep))) filter in let ends = chosen map ((_, d) -> d) scan_add in (chosen, ends) zip map (((item, d), end) -> (item, ((end, d) sub, end) range) cap_list map ((item, rank) -> ((rank, item), 1))) flatten .1); +let answer_map = top | map((rid, (rank, (_, (id, created, root)))) -> (id, (rid, rank, created, root))); +let answer_idx = answer_map | arrange; -+let message_idx2 = message | arrange; -+let answer_join = answer_idx | join(message_idx2, (id, (rid, rank, created, root), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (root, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); ++let answer_join = answer_idx | join(message, (id, (rid, rank, created, root), (_, _, _, _, content, image, _, _, _, _, _, _, _)) -> (root, (rid, rank, id, ((content len, 0) gt, content, image) select, created))); +let answer_idx2 = answer_join | arrange; -+let message_idx3 = message | arrange; -+let answer_join2 = answer_idx2 | join(message_idx3, (root, (rid, rank, id, body, created), (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (op, (rid, rank, id, body, created, root))); ++let answer_join2 = answer_idx2 | join(message, (root, (rid, rank, id, body, created), (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (op, (rid, rank, id, body, created, root))); +let answer_idx3 = answer_join2 | arrange; -+let person_idx = person | arrange; -+let answer = answer_idx3 | join(person_idx, (op, (rid, rank, id, body, created, root), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (id, body, created, root, op, first, last))); ++let answer = answer_idx3 | join(person, (op, (rid, rank, id, body, created, root), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, rank), (id, body, created, root, op, first, last))); +let answer_idx4 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx4; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is03.ddp b/interactive/tests/plan_pairs/expected/ldbc_is03.ddp index 0d5b730dba..dd69875507 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is03.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is03.ddp @@ -5,11 +5,9 @@ let person = import "graph::person" : (int, (List(int), List(int), List(int), in let friend = import "graph::friend" : (int, (int, int)); let ranked_map = request | map(((rid, who), ()) -> (who, rid)); let ranked_idx = ranked_map | arrange; -let friend_idx = friend | arrange; -let ranked_join = ranked_idx | join(friend_idx, (_, rid, (f, since)) -> (f, (rid, since))); +let ranked_join = ranked_idx | join(friend, (_, rid, (f, since)) -> (f, (rid, since))); let ranked_idx2 = ranked_join | arrange; -let person_idx = person | arrange; -let ranked_join2 = ranked_idx2 | join(person_idx, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))); +let ranked_join2 = ranked_idx2 | join(person, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))); let ranked_idx3 = ranked_join2 | arrange; let ranked_reduce = ranked_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); let answer = ranked_reduce | flatmap((_, entries) -> entries) | map((rid, (rank, ((neg, f), (first, last)))) -> ((rid, rank), (f, first, last, neg neg))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_is03.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_is03.lowered--optimized.diff index e85652ae2c..6d133257c9 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is03.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is03.lowered--optimized.diff @@ -1,7 +1,7 @@ --- lowered +++ optimized -@@ -12,8 +12,7 @@ - let ranked_join2 = ranked_idx2 | join(person_idx, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))); +@@ -10,8 +10,7 @@ + let ranked_join2 = ranked_idx2 | join(person, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))); let ranked_idx3 = ranked_join2 | arrange; let ranked_reduce = ranked_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let ranked = ranked_reduce | flatmap((_, entries) -> entries); diff --git a/interactive/tests/plan_pairs/expected/ldbc_is03.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is03.parsed--lowered.diff index c849e10e7a..024b0d199e 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is03.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is03.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,6 +1,19 @@ +@@ -1,6 +1,17 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -9,11 +9,9 @@ -let ranked = request | map(((rid, who), ()) -> (who, rid)) | join(friend, (_, rid, (f, since)) -> (f, (rid, since))) | join(person, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))) | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist) | flatmap((_, entries) -> entries); +let ranked_map = request | map(((rid, who), ()) -> (who, rid)); +let ranked_idx = ranked_map | arrange; -+let friend_idx = friend | arrange; -+let ranked_join = ranked_idx | join(friend_idx, (_, rid, (f, since)) -> (f, (rid, since))); ++let ranked_join = ranked_idx | join(friend, (_, rid, (f, since)) -> (f, (rid, since))); +let ranked_idx2 = ranked_join | arrange; -+let person_idx = person | arrange; -+let ranked_join2 = ranked_idx2 | join(person_idx, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))); ++let ranked_join2 = ranked_idx2 | join(person, (f, (rid, since), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((since neg, f), (first, last)))); +let ranked_idx3 = ranked_join2 | arrange; +let ranked_reduce = ranked_idx3 | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let ranked = ranked_reduce | flatmap((_, entries) -> entries); diff --git a/interactive/tests/plan_pairs/expected/ldbc_is04.ddp b/interactive/tests/plan_pairs/expected/ldbc_is04.ddp index c17e1ad197..95ca1f865a 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is04.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is04.ddp @@ -4,8 +4,7 @@ let request = input 0 : ((int, int), ()); let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); let answer_map = request | map(((rid, m), ()) -> (m, rid)); let answer_idx = answer_map | arrange; -let message_idx = message | arrange; -let answer = answer_idx | join(message_idx, (_, rid, (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((rid, 0), (created, ((text len, 0) gt, text, image) select))); +let answer = answer_idx | join(message, (_, rid, (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((rid, 0), (created, ((text len, 0) gt, text, image) select))); let answer_idx2 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx2; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is04.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is04.parsed--lowered.diff index ff621ea755..43f9c07011 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is04.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is04.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,4 +1,11 @@ +@@ -1,4 +1,10 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -9,8 +9,7 @@ -output "answer" = answer | arrange; +let answer_map = request | map(((rid, m), ()) -> (m, rid)); +let answer_idx = answer_map | arrange; -+let message_idx = message | arrange; -+let answer = answer_idx | join(message_idx, (_, rid, (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((rid, 0), (created, ((text len, 0) gt, text, image) select))); ++let answer = answer_idx | join(message, (_, rid, (_, created, _, _, text, image, _, _, _, _, _, _, _)) -> ((rid, 0), (created, ((text len, 0) gt, text, image) select))); +let answer_idx2 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx2; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is05.ddp b/interactive/tests/plan_pairs/expected/ldbc_is05.ddp index 9172fc792c..0ab419ad70 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is05.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is05.ddp @@ -5,11 +5,9 @@ let person = import "graph::person" : (int, (List(int), List(int), List(int), in let message = import "graph::message" : (int, (int, int, int, int, List(int), List(int), int, List(int), int, int, int, int, int)); let answer_map = request | map(((rid, m), ()) -> (m, rid)); let answer_idx = answer_map | arrange; -let message_idx = message | arrange; -let answer_join = answer_idx | join(message_idx, (_, rid, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, rid)); +let answer_join = answer_idx | join(message, (_, rid, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, rid)); let answer_idx2 = answer_join | arrange; -let person_idx = person | arrange; -let answer = answer_idx2 | join(person_idx, (who, rid, (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (who, first, last))); +let answer = answer_idx2 | join(person, (who, rid, (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (who, first, last))); let answer_idx3 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is05.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is05.parsed--lowered.diff index a91541d9f2..44db594d6f 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is05.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is05.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,5 +1,15 @@ +@@ -1,5 +1,13 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -10,11 +10,9 @@ -output "answer" = answer | arrange; +let answer_map = request | map(((rid, m), ()) -> (m, rid)); +let answer_idx = answer_map | arrange; -+let message_idx = message | arrange; -+let answer_join = answer_idx | join(message_idx, (_, rid, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, rid)); ++let answer_join = answer_idx | join(message, (_, rid, (_, _, who, _, _, _, _, _, _, _, _, _, _)) -> (who, rid)); +let answer_idx2 = answer_join | arrange; -+let person_idx = person | arrange; -+let answer = answer_idx2 | join(person_idx, (who, rid, (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (who, first, last))); ++let answer = answer_idx2 | join(person, (who, rid, (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (who, first, last))); +let answer_idx3 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx3; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is06.ddp b/interactive/tests/plan_pairs/expected/ldbc_is06.ddp index 1e8a400345..360b1601c4 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is06.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is06.ddp @@ -7,17 +7,13 @@ let forum = import "graph::forum" : (int, (List(int), int, int)); let root_of = import "graph::message.root" : (int, int); let answer_map = request | map(((rid, m), ()) -> (m, rid)); let answer_idx = answer_map | arrange; -let root_of_idx = root_of | arrange; -let answer_join = answer_idx | join(root_of_idx, (_, rid, root) -> (root, rid)); +let answer_join = answer_idx | join(root_of, (_, rid, root) -> (root, rid)); let answer_idx2 = answer_join | arrange; -let message_idx = message | arrange; -let answer_join2 = answer_idx2 | join(message_idx, (_, rid, (_, _, _, _, _, _, _, _, f, _, _, _, _)) -> (f, rid)); +let answer_join2 = answer_idx2 | join(message, (_, rid, (_, _, _, _, _, _, _, _, f, _, _, _, _)) -> (f, rid)); let answer_idx3 = answer_join2 | arrange; -let forum_idx = forum | arrange; -let answer_join3 = answer_idx3 | join(forum_idx, (f, rid, (title, _, moderator)) -> (moderator, (rid, f, title))); +let answer_join3 = answer_idx3 | join(forum, (f, rid, (title, _, moderator)) -> (moderator, (rid, f, title))); let answer_idx4 = answer_join3 | arrange; -let person_idx = person | arrange; -let answer = answer_idx4 | join(person_idx, (moderator, (rid, f, title), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (f, title, moderator, first, last))); +let answer = answer_idx4 | join(person, (moderator, (rid, f, title), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (f, title, moderator, first, last))); let answer_idx5 = answer | arrange; -- Renderer: publish the existing arrangement. output "answer" = answer_idx5; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is06.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is06.parsed--lowered.diff index 37aefc16c6..b029bfbe89 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is06.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is06.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,7 +1,23 @@ +@@ -1,7 +1,19 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -12,17 +12,13 @@ -output "answer" = answer | arrange; +let answer_map = request | map(((rid, m), ()) -> (m, rid)); +let answer_idx = answer_map | arrange; -+let root_of_idx = root_of | arrange; -+let answer_join = answer_idx | join(root_of_idx, (_, rid, root) -> (root, rid)); ++let answer_join = answer_idx | join(root_of, (_, rid, root) -> (root, rid)); +let answer_idx2 = answer_join | arrange; -+let message_idx = message | arrange; -+let answer_join2 = answer_idx2 | join(message_idx, (_, rid, (_, _, _, _, _, _, _, _, f, _, _, _, _)) -> (f, rid)); ++let answer_join2 = answer_idx2 | join(message, (_, rid, (_, _, _, _, _, _, _, _, f, _, _, _, _)) -> (f, rid)); +let answer_idx3 = answer_join2 | arrange; -+let forum_idx = forum | arrange; -+let answer_join3 = answer_idx3 | join(forum_idx, (f, rid, (title, _, moderator)) -> (moderator, (rid, f, title))); ++let answer_join3 = answer_idx3 | join(forum, (f, rid, (title, _, moderator)) -> (moderator, (rid, f, title))); +let answer_idx4 = answer_join3 | arrange; -+let person_idx = person | arrange; -+let answer = answer_idx4 | join(person_idx, (moderator, (rid, f, title), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (f, title, moderator, first, last))); ++let answer = answer_idx4 | join(person, (moderator, (rid, f, title), (first, last, _, _, _, _, _, _, _, _, _)) -> ((rid, 0), (f, title, moderator, first, last))); +let answer_idx5 = answer | arrange; +-- Renderer: publish the existing arrangement. +output "answer" = answer_idx5; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is07.ddp b/interactive/tests/plan_pairs/expected/ldbc_is07.ddp index c1d6c532a9..5492ea3a49 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is07.ddp +++ b/interactive/tests/plan_pairs/expected/ldbc_is07.ddp @@ -7,18 +7,15 @@ let by_parent = import "graph::message.by_parent" : (int, int); let friend = import "graph::friend" : (int, (int, int)); let reply_map = request | map(((rid, m), ()) -> (m, rid)); let reply_idx = reply_map | arrange; -let message_idx = message | arrange; -let reply_join = reply_idx | join(message_idx, (m, rid, (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (m, (rid, op))); +let reply_join = reply_idx | join(message, (m, rid, (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (m, (rid, op))); let reply_idx2 = reply_join | arrange; -let by_parent_idx = by_parent | arrange; -let reply_join2 = reply_idx2 | join(by_parent_idx, (_, (rid, op), id) -> (id, (rid, op))); +let reply_join2 = reply_idx2 | join(by_parent, (_, (rid, op), id) -> (id, (rid, op))); let reply_idx3 = reply_join2 | arrange; -let reply_join3 = reply_idx3 | join(message_idx, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); +let reply_join3 = reply_idx3 | join(message, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); let reply = reply_join3 | filter((kind, _) -> (kind, 1) eq) | map((_, row) -> row); let known_map = reply | map(((who, op), row) -> (who, (op, row))); let known_idx = known_map | arrange; -let friend_idx = friend | arrange; -let known_join = known_idx | join(friend_idx, (who, (op, row), (f, _)) -> ((f, op) eq, ((who, op), row))); +let known_join = known_idx | join(friend, (who, (op, row), (f, _)) -> ((f, op) eq, ((who, op), row))); let known_rows = known_join | filter((same, _) -> same) | map((_, (pair, row)) -> ((pair, row), ())); let known_idx2 = known_rows | arrange; let known_reduce = known_idx2 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); @@ -30,8 +27,7 @@ let marked_rows = marked_map2 + marked_neg; let marked_map3 = marked_rows | map(((who, _), row) -> (who, (row, 0))); let marked = marked_map + marked_map3; let marked_idx = marked | arrange; -let person_idx = person | arrange; -let ranked_join = marked_idx | join(person_idx, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); +let ranked_join = marked_idx | join(person, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); let ranked_idx = ranked_join | arrange; let ranked_reduce = ranked_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); let answer = ranked_reduce | flatmap((_, entries) -> entries) | map((rid, (rank, ((neg, who), (id, text, first, last, k)))) -> ((rid, rank), (id, text, neg neg, who, first, last, k))); diff --git a/interactive/tests/plan_pairs/expected/ldbc_is07.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/ldbc_is07.lowered--optimized.diff index 1019d56bae..be24587d34 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is07.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is07.lowered--optimized.diff @@ -1,19 +1,15 @@ --- lowered +++ optimized -@@ -13,17 +13,14 @@ - let by_parent_idx = by_parent | arrange; - let reply_join2 = reply_idx2 | join(by_parent_idx, (_, (rid, op), id) -> (id, (rid, op))); +@@ -12,14 +12,12 @@ + let reply_join2 = reply_idx2 | join(by_parent, (_, (rid, op), id) -> (id, (rid, op))); let reply_idx3 = reply_join2 | arrange; --let message_idx2 = message | arrange; --let reply_join3 = reply_idx3 | join(message_idx2, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); + let reply_join3 = reply_idx3 | join(message, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); -let reply_filter = reply_join3 | filter((kind, _) -> (kind, 1) eq); -let reply = reply_filter | map((_, row) -> row); -+let reply_join3 = reply_idx3 | join(message_idx, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); +let reply = reply_join3 | filter((kind, _) -> (kind, 1) eq) | map((_, row) -> row); let known_map = reply | map(((who, op), row) -> (who, (op, row))); let known_idx = known_map | arrange; - let friend_idx = friend | arrange; - let known_join = known_idx | join(friend_idx, (who, (op, row), (f, _)) -> ((f, op) eq, ((who, op), row))); + let known_join = known_idx | join(friend, (who, (op, row), (f, _)) -> ((f, op) eq, ((who, op), row))); -let known_filter = known_join | filter((same, _) -> same); -let known_map2 = known_filter | map((_, (pair, row)) -> ((pair, row), ())); -let known_idx2 = known_map2 | arrange; @@ -22,8 +18,8 @@ let known_reduce = known_idx2 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); let known = known_reduce | map(((pair, row), ()) -> (pair, row)); let marked_map = known | map(((who, _), row) -> (who, (row, 1))); -@@ -36,8 +33,7 @@ - let ranked_join = marked_idx | join(person_idx, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); +@@ -31,8 +29,7 @@ + let ranked_join = marked_idx | join(person, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); let ranked_idx = ranked_join | arrange; let ranked_reduce = ranked_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); -let ranked = ranked_reduce | flatmap((_, entries) -> entries); diff --git a/interactive/tests/plan_pairs/expected/ldbc_is07.optimized--projected.diff b/interactive/tests/plan_pairs/expected/ldbc_is07.optimized--projected.diff index 0891b264a7..34d002a79a 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is07.optimized--projected.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is07.optimized--projected.diff @@ -1,6 +1,6 @@ --- optimized +++ projected -@@ -22,12 +22,13 @@ +@@ -19,12 +19,13 @@ let known_rows = known_join | filter((same, _) -> same) | map((_, (pair, row)) -> ((pair, row), ())); let known_idx2 = known_rows | arrange; let known_reduce = known_idx2 | reduce((_, vals) -> vals map (((), _) -> ((), 1))); @@ -16,5 +16,5 @@ +let marked_map3 = marked_rows | map(((who, _), row) -> (who, (row, 0))); +let marked = marked_map + marked_map3; let marked_idx = marked | arrange; - let person_idx = person | arrange; - let ranked_join = marked_idx | join(person_idx, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); + let ranked_join = marked_idx | join(person, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); + let ranked_idx = ranked_join | arrange; diff --git a/interactive/tests/plan_pairs/expected/ldbc_is07.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/ldbc_is07.parsed--lowered.diff index 3445855110..9bb0a064c1 100644 --- a/interactive/tests/plan_pairs/expected/ldbc_is07.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/ldbc_is07.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,11 +1,43 @@ +@@ -1,11 +1,38 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let request = input 0 : ((int, int), ()); @@ -14,20 +14,16 @@ -let ranked = marked | join(person, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))) | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist) | flatmap((_, entries) -> entries); +let reply_map = request | map(((rid, m), ()) -> (m, rid)); +let reply_idx = reply_map | arrange; -+let message_idx = message | arrange; -+let reply_join = reply_idx | join(message_idx, (m, rid, (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (m, (rid, op))); ++let reply_join = reply_idx | join(message, (m, rid, (_, _, op, _, _, _, _, _, _, _, _, _, _)) -> (m, (rid, op))); +let reply_idx2 = reply_join | arrange; -+let by_parent_idx = by_parent | arrange; -+let reply_join2 = reply_idx2 | join(by_parent_idx, (_, (rid, op), id) -> (id, (rid, op))); ++let reply_join2 = reply_idx2 | join(by_parent, (_, (rid, op), id) -> (id, (rid, op))); +let reply_idx3 = reply_join2 | arrange; -+let message_idx2 = message | arrange; -+let reply_join3 = reply_idx3 | join(message_idx2, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); ++let reply_join3 = reply_idx3 | join(message, (id, (rid, op), (kind, created, who, _, text, _, _, _, _, _, _, _, _)) -> (kind, ((who, op), (rid, id, text, created)))); +let reply_filter = reply_join3 | filter((kind, _) -> (kind, 1) eq); +let reply = reply_filter | map((_, row) -> row); +let known_map = reply | map(((who, op), row) -> (who, (op, row))); +let known_idx = known_map | arrange; -+let friend_idx = friend | arrange; -+let known_join = known_idx | join(friend_idx, (who, (op, row), (f, _)) -> ((f, op) eq, ((who, op), row))); ++let known_join = known_idx | join(friend, (who, (op, row), (f, _)) -> ((f, op) eq, ((who, op), row))); +let known_filter = known_join | filter((same, _) -> same); +let known_map2 = known_filter | map((_, (pair, row)) -> ((pair, row), ())); +let known_idx2 = known_map2 | arrange; @@ -39,8 +35,7 @@ +let marked_map2 = marked_rows | map(((who, _), row) -> (who, (row, 0))); +let marked = marked_map + marked_map2; +let marked_idx = marked | arrange; -+let person_idx = person | arrange; -+let ranked_join = marked_idx | join(person_idx, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); ++let ranked_join = marked_idx | join(person, (who, ((rid, id, text, created), k), (first, last, _, _, _, _, _, _, _, _, _)) -> (rid, ((created neg, who), (id, text, first, last, k)))); +let ranked_idx = ranked_join | arrange; +let ranked_reduce = ranked_idx | reduce((_, vals) -> let lists = vals map ((v, d) -> (v, (0, d) range) cap_list map ((v, _) -> v)) in let flat = lists flatten in (flat.1, 1) enlist); +let ranked = ranked_reduce | flatmap((_, entries) -> entries); diff --git a/interactive/tests/plan_pairs/expected/txn_resolve.ddp b/interactive/tests/plan_pairs/expected/txn_resolve.ddp index 9d268242ce..2748050c13 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve.ddp +++ b/interactive/tests/plan_pairs/expected/txn_resolve.ddp @@ -9,8 +9,7 @@ let wid = intents | filter(((_, r, _), _) -> (r, 0) eq) | map(((a, _, b), (c)) - let wid_idx = wid | arrange; let rk = reads | map(((rid, k), (e)) -> ((k), (rid, e))); let rk_idx = rk | arrange; -let store_idx = store | arrange; -let base = rk_idx | join(store_idx, ((k), (rid, e), (sw, v)) -> ((k, rid, e), (sw neg, v))); +let base = rk_idx | join(store, ((k), (rid, e), (sw, v)) -> ((k, rid, e), (sw neg, v))); res: { -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. var rollback; @@ -45,7 +44,7 @@ let latest_map = committed | map(((wid), (k, v)) -> ((k), (wid neg, v))); let latest_idx = latest_map | arrange; let latest = latest_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let new_rows = latest | map(((k), (nw, v)) -> ((k), (nw neg, v))); -let old_rows = latest | join(store_idx, ((k), _, (sw, sv)) -> ((k), (sw, sv))); +let old_rows = latest | join(store, ((k), _, (sw, sv)) -> ((k), (sw, sv))); let delta_neg = old_rows | negate; let delta_rows = new_rows + delta_neg; -- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/txn_resolve.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/txn_resolve.lowered--optimized.diff index 3e3d17c25b..62feeceef5 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/txn_resolve.lowered--optimized.diff @@ -1,6 +1,6 @@ --- lowered +++ optimized -@@ -2,11 +2,11 @@ +@@ -2,48 +2,40 @@ -- Trace imports use provider arrangements; history advances to G = (0, []). let store = import "store::store" : ((int), (int, int)); let intents = input 0 : ((int, int, int), (int)); @@ -16,8 +16,7 @@ +let wid_idx = wid | arrange; let rk = reads | map(((rid, k), (e)) -> ((k), (rid, e))); let rk_idx = rk | arrange; - let store_idx = store | arrange; -@@ -14,37 +14,29 @@ + let base = rk_idx | join(store, ((k), (rid, e), (sw, v)) -> ((k, rid, e), (sw neg, v))); res: { -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. var rollback; @@ -62,13 +61,3 @@ let rb_idx = rb | arrange; let wbad = wid_idx | join(rb_idx, (wid, kv, ()) -> (wid, kv)); let committed_neg = wbad | negate; -@@ -53,8 +45,7 @@ - let latest_idx = latest_map | arrange; - let latest = latest_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); - let new_rows = latest | map(((k), (nw, v)) -> ((k), (nw neg, v))); --let store_idx2 = store | arrange; --let old_rows = latest | join(store_idx2, ((k), _, (sw, sv)) -> ((k), (sw, sv))); -+let old_rows = latest | join(store_idx, ((k), _, (sw, sv)) -> ((k), (sw, sv))); - let delta_neg = old_rows | negate; - let delta_rows = new_rows + delta_neg; - -- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/txn_resolve.optimized--projected.diff b/interactive/tests/plan_pairs/expected/txn_resolve.optimized--projected.diff index 90d27e57fc..c3cfe7a50e 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve.optimized--projected.diff +++ b/interactive/tests/plan_pairs/expected/txn_resolve.optimized--projected.diff @@ -1,6 +1,6 @@ --- optimized +++ projected -@@ -24,7 +24,7 @@ +@@ -23,7 +23,7 @@ let pairs = pairs_join | filter(((_, rid, _), (nw, _)) -> (nw neg, rid) lt); let best_rows = pairs + ::base; let best_idx = best_rows | arrange; diff --git a/interactive/tests/plan_pairs/expected/txn_resolve.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/txn_resolve.parsed--lowered.diff index 588a41e1de..d66f7345f2 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/txn_resolve.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,28 +1,63 @@ +@@ -1,28 +1,61 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let store = import "store::store" : ((int), (int, int)); @@ -15,8 +15,7 @@ let rk = reads | map(((rid, k), (e)) -> ((k), (rid, e))); -let base = rk | join(store, ((k), (rid, e), (sw, v)) -> ((k, rid, e), (sw neg, v))); +let rk_idx = rk | arrange; -+let store_idx = store | arrange; -+let base = rk_idx | join(store_idx, ((k), (rid, e), (sw, v)) -> ((k, rid, e), (sw neg, v))); ++let base = rk_idx | join(store, ((k), (rid, e), (sw, v)) -> ((k, rid, e), (sw neg, v))); res: { - let wr_bad = wid | join(rollback, (wid, kv, ()) -> (wid, kv)); - let writes = wid + (wr_bad | negate); @@ -71,9 +70,7 @@ +let latest_idx = latest_map | arrange; +let latest = latest_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let new_rows = latest | map(((k), (nw, v)) -> ((k), (nw neg, v))); --let old_rows = latest | join(store, ((k), _, (sw, sv)) -> ((k), (sw, sv))); -+let store_idx2 = store | arrange; -+let old_rows = latest | join(store_idx2, ((k), _, (sw, sv)) -> ((k), (sw, sv))); + let old_rows = latest | join(store, ((k), _, (sw, sv)) -> ((k), (sw, sv))); +let delta_neg = old_rows | negate; +let delta_rows = new_rows + delta_neg; +-- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/txn_resolve_by_key.ddp b/interactive/tests/plan_pairs/expected/txn_resolve_by_key.ddp index 34d8e7e377..0fc33cfa80 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve_by_key.ddp +++ b/interactive/tests/plan_pairs/expected/txn_resolve_by_key.ddp @@ -6,8 +6,7 @@ let wid = intents | filter(((_, r, _), _) -> (r, 0) eq) | map(((a, _, b), (c)) - let wid_idx = wid | arrange; let read_entries = intents | filter(((_, r, _), _) -> (r, 1) eq) | map(((a, _, b), (c)) -> ((b), (1, a, c))); let read_entries_idx = read_entries | arrange; -let store_idx = store | arrange; -let store_entries = read_entries_idx | join(store_idx, ((k), _, (sw, v)) -> ((k), (0, sw, v))); +let store_entries = read_entries_idx | join(store, ((k), _, (sw, v)) -> ((k), (0, sw, v))); res: { -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. var rollback; @@ -41,7 +40,7 @@ let latest_map = committed | map(((wid), (k, v)) -> ((k), (wid neg, v))); let latest_idx = latest_map | arrange; let latest = latest_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let new_rows = latest | map(((k), (nw, v)) -> ((k), (nw neg, v))); -let old_rows = latest | join(store_idx, ((k), _, (sw, sv)) -> ((k), (sw, sv))); +let old_rows = latest | join(store, ((k), _, (sw, sv)) -> ((k), (sw, sv))); let delta_neg = old_rows | negate; let delta_rows = new_rows + delta_neg; -- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/txn_resolve_by_key.lowered--optimized.diff b/interactive/tests/plan_pairs/expected/txn_resolve_by_key.lowered--optimized.diff index 6955d416d0..729238fc9e 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve_by_key.lowered--optimized.diff +++ b/interactive/tests/plan_pairs/expected/txn_resolve_by_key.lowered--optimized.diff @@ -1,6 +1,6 @@ --- lowered +++ optimized -@@ -2,21 +2,17 @@ +@@ -2,20 +2,16 @@ -- Trace imports use provider arrangements; history advances to G = (0, []). let store = import "store::store" : ((int), (int, int)); let intents = input 0 : ((int, int, int), (int)); @@ -14,8 +14,7 @@ +let wid_idx = wid | arrange; +let read_entries = intents | filter(((_, r, _), _) -> (r, 1) eq) | map(((a, _, b), (c)) -> ((b), (1, a, c))); let read_entries_idx = read_entries | arrange; - let store_idx = store | arrange; - let store_entries = read_entries_idx | join(store_idx, ((k), _, (sw, v)) -> ((k), (0, sw, v))); + let store_entries = read_entries_idx | join(store, ((k), _, (sw, v)) -> ((k), (0, sw, v))); res: { -- Time lanes: epoch, then 1 scope coordinates; this scope enters at zero. var rollback; @@ -26,7 +25,7 @@ let writes_neg = wr_bad | negate; let writes = ::wid + writes_neg; let write_entries = writes | map(((wid), (k, v)) -> ((k), (0, wid, v))); -@@ -37,7 +33,6 @@ +@@ -36,7 +32,6 @@ set rollback = rollback_reduce; } let rb = res::rollback; @@ -34,13 +33,3 @@ let rb_idx = rb | arrange; let wbad = wid_idx | join(rb_idx, (wid, kv, ()) -> (wid, kv)); let committed_neg = wbad | negate; -@@ -46,8 +41,7 @@ - let latest_idx = latest_map | arrange; - let latest = latest_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); - let new_rows = latest | map(((k), (nw, v)) -> ((k), (nw neg, v))); --let store_idx2 = store | arrange; --let old_rows = latest | join(store_idx2, ((k), _, (sw, sv)) -> ((k), (sw, sv))); -+let old_rows = latest | join(store_idx, ((k), _, (sw, sv)) -> ((k), (sw, sv))); - let delta_neg = old_rows | negate; - let delta_rows = new_rows + delta_neg; - -- Renderer: build an export arrangement. diff --git a/interactive/tests/plan_pairs/expected/txn_resolve_by_key.parsed--lowered.diff b/interactive/tests/plan_pairs/expected/txn_resolve_by_key.parsed--lowered.diff index 1a339c1914..08225ff3ab 100644 --- a/interactive/tests/plan_pairs/expected/txn_resolve_by_key.parsed--lowered.diff +++ b/interactive/tests/plan_pairs/expected/txn_resolve_by_key.parsed--lowered.diff @@ -1,6 +1,6 @@ --- parsed +++ lowered -@@ -1,15 +1,28 @@ +@@ -1,15 +1,27 @@ +-- Time lanes: epoch. +-- Trace imports use provider arrangements; history advances to G = (0, []). let store = import "store::store" : ((int), (int, int)); @@ -15,8 +15,7 @@ let read_entries = reads | map(((rid, k), (e)) -> ((k), (1, rid, e))); -let store_entries = read_entries | join(store, ((k), _, (sw, v)) -> ((k), (0, sw, v))); +let read_entries_idx = read_entries | arrange; -+let store_idx = store | arrange; -+let store_entries = read_entries_idx | join(store_idx, ((k), _, (sw, v)) -> ((k), (0, sw, v))); ++let store_entries = read_entries_idx | join(store, ((k), _, (sw, v)) -> ((k), (0, sw, v))); res: { - let wr_bad = wid | join(rollback, (wid, kv, ()) -> (wid, kv)); - let writes = wid + (wr_bad | negate); @@ -35,7 +34,7 @@ let ws = (entries map ((t, _, _) -> (t, 0) eq), entries) zip filter in let rs = (entries map ((t, _, _) -> (t, 1) eq), entries) zip filter in let judged = (ws, rs) cap_list map ((ws, (_, i, x)) -> -@@ -18,13 +31,26 @@ +@@ -18,13 +30,25 @@ let (bid, bv) = best in (((bid, -1) eq, (x, -1) ne, (bv, x) ne) select, ((i), 1))) in (judged map ((b, _) -> b), judged map ((_, o) -> o)) zip filter); @@ -58,9 +57,7 @@ +let latest_idx = latest_map | arrange; +let latest = latest_idx | reduce(limit 1, (_, vals) -> let first = vals head in (first.0, 1) enlist); let new_rows = latest | map(((k), (nw, v)) -> ((k), (nw neg, v))); --let old_rows = latest | join(store, ((k), _, (sw, sv)) -> ((k), (sw, sv))); -+let store_idx2 = store | arrange; -+let old_rows = latest | join(store_idx2, ((k), _, (sw, sv)) -> ((k), (sw, sv))); + let old_rows = latest | join(store, ((k), _, (sw, sv)) -> ((k), (sw, sv))); +let delta_neg = old_rows | negate; +let delta_rows = new_rows + delta_neg; +-- Renderer: build an export arrangement. From cb969f7c46e5363827694c7ef9cd3400052414c3 Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Tue, 10 Nov 2026 10:44:03 +0100 Subject: [PATCH 02/19] DDIR: test arranged parents rewritten by distinct Co-Authored-By: Claude Opus 5.5 --- interactive/src/lower.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/interactive/src/lower.rs b/interactive/src/lower.rs index f83f8148a2..e1e142da19 100644 --- a/interactive/src/lower.rs +++ b/interactive/src/lower.rs @@ -709,6 +709,19 @@ mod tree_tests { assert!(!s.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Arrange(_))))); } + #[test] + fn child_rearranges_a_parent_rewritten_by_record_distinct() { + let program = lower_tree(parse(r#" + let a = input 0 : (int, int); + let d = a | distinct; + s: { let m = ::d | min; } + output "o" = s::m; + "#)); + // A by-record distinct ends in a map, so the child must arrange its import. + let s = child(&program.root, "s"); + assert!(s.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Arrange(Ref::Import(_)))))); + } + #[test] fn keeps_explicit_arranges_and_scope_boundaries() { let program = lower_tree(parse(r#" From 72908a911d922f52d82bf27a3ed82ea06b999277 Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Tue, 10 Nov 2026 10:47:19 +0100 Subject: [PATCH 03/19] DDIR: Reduce takes a ReduceInput Node::Reduce names its inputs with a ReduceInput, either a signed merge or a cogroup. Nothing builds a non-single input yet. Ref walkers handle every input, consumers that need one input call unimplemented!. Co-Authored-By: Claude Opus 5.5 --- interactive/src/backend/mod.rs | 1 + interactive/src/explain/mod.rs | 12 ++-- interactive/src/lower.rs | 8 +-- interactive/src/passes/as_of.rs | 3 +- interactive/src/passes/dead_code.rs | 3 +- interactive/src/passes/projection.rs | 10 ++-- interactive/src/passes/structural.rs | 3 +- interactive/src/plan.rs | 8 +-- interactive/src/plan/compare.rs | 13 ++++- interactive/src/plan/ddp.rs | 4 +- interactive/src/reducers.rs | 11 +++- interactive/src/scope_ir.rs | 85 ++++++++++++++++++++++++---- interactive/src/shapes.rs | 2 +- interactive/tests/plan_pairs.rs | 3 +- 14 files changed, 124 insertions(+), 42 deletions(-) diff --git a/interactive/src/backend/mod.rs b/interactive/src/backend/mod.rs index e431679d95..a739e83d56 100644 --- a/interactive/src/backend/mod.rs +++ b/interactive/src/backend/mod.rs @@ -259,6 +259,7 @@ pub(crate) fn render_scope<'s, B: Backend>( Rendered::Collection(B::half_join(c, a, *strict, projection, level, (shape_of(stream), shape_of(arrangement)))) }, st::Node::Reduce { input, reducer, limit } => { + let input = input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")); let a = resolve(&items, &imports, &var_cols, input).arrange(); Rendered::Arrangement(B::reduce(a, reducer, *limit, shape_of(input))) }, diff --git a/interactive/src/explain/mod.rs b/interactive/src/explain/mod.rs index 353203755c..068924c984 100644 --- a/interactive/src/explain/mod.rs +++ b/interactive/src/explain/mod.rs @@ -21,7 +21,7 @@ //! of the depth structurally. use crate::ir::LinearOp; -use crate::scope_ir::{Bind, Export, Import, Item, Node, Program, Ref, Scope, Source, Var}; +use crate::scope_ir::{Bind, Export, Import, Item, Node, Program, ReduceInput, Ref, Scope, Source, Var}; /// A value-producing site in an original tree: the `path` of `Sub` item /// indices from the root, then the site within that scope. Sites are ops and @@ -87,7 +87,7 @@ fn clone_node(node: &Node, m: impl Fn(&Ref) -> Ref) -> Node { Node::Arrange(r) => Node::Arrange(m(r)), Node::Join { left, right, projection } => Node::Join { left: m(left), right: m(right), projection: projection.clone() }, Node::HalfJoin { stream, arrangement, strict, projection } => Node::HalfJoin { stream: m(stream), arrangement: m(arrangement), strict: *strict, projection: projection.clone() }, - Node::Reduce { input, reducer, limit } => Node::Reduce { input: m(input), reducer: reducer.clone(), limit: *limit }, + Node::Reduce { input, reducer, limit } => Node::Reduce { input: { let mut input = input.clone(); input.for_each_ref(|r| *r = m(r)); input }, reducer: reducer.clone(), limit: *limit }, Node::Inspect { input, label } => Node::Inspect { input: m(input), label: label.clone() }, } } @@ -140,7 +140,7 @@ fn clone_rec(orig: &Scope, out: &mut Scope, import_map: &[Ref], path: &[usize], // differ from round to round as values come and go: they are a site of their own. if let Node::Reduce { input, limit: Some(k), .. } = node { let presented = Node::Reduce { - input: map_ref(input, &locals, &subs, import_map, var_base), + input: ReduceInput::single(map_ref(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")), &locals, &subs, import_map, var_base)), reducer: Reducer::Expr(crate::parse::Reducer::Distinct.lambda()), limit: Some(*k), }; @@ -373,7 +373,7 @@ impl Sb { } fn reduce(&mut self, input: Ref, reducer: Reducer) -> Ref { let a = self.op(Node::Arrange(input)); - self.op(Node::Reduce { input: a, reducer, limit: None }) + self.op(Node::Reduce { input: ReduceInput::single(a), reducer, limit: None }) } fn variable(&mut self, name: &str) -> Ref { let v = self.s.vars.len(); @@ -1024,7 +1024,7 @@ impl<'a> Reverse<'a> { self.push(ex, path, input, dep_this); } Node::Reduce { input, limit: None, .. } => { - let target = resolve(self.orig, path, input); + let target = resolve(self.orig, path, input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))); let side = self.side(&target); let (dep, out_len) = align(ex, dep_this, path, target_path(&target)); let contrib = ex.emit_lookup_keyed(dep, &side, out_len); @@ -1035,7 +1035,7 @@ impl<'a> Reverse<'a> { // values it handed its lambda at those chains, and on every input row holding them up // to the demanded chain: with them, each round's first values are as in the reference. Node::Reduce { input, limit: Some(_), .. } => { - let target = resolve(self.orig, path, input); + let target = resolve(self.orig, path, input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))); let side = self.side(&target); let presented = self.side(&Target::Site(Addr { path: path.to_vec(), site: Site::Presented(i) })); let values = ex.emit_lookup_presented(dep_this, &presented, path.len()); diff --git a/interactive/src/lower.rs b/interactive/src/lower.rs index e1e142da19..85a47f89f4 100644 --- a/interactive/src/lower.rs +++ b/interactive/src/lower.rs @@ -425,7 +425,7 @@ impl ScopeLower { self.distinct.push(self.items.len()); r } else { self.arrange(r) }; - self.push(st::Node::Reduce { input: a, reducer: crate::ir::Reducer::Expr(red.lambda()), limit: red.limit() }) + self.push(st::Node::Reduce { input: st::ReduceInput::single(a), reducer: crate::ir::Reducer::Expr(red.lambda()), limit: red.limit() }) }, Expr::Inspect(e, l) => { let r = self.lower_expr(e); self.push(st::Node::Inspect { input: r, label: l.clone() }) }, Expr::Concat(es) => { let rs: Vec = es.iter().map(|e| self.lower_expr(e)).collect(); self.push(st::Node::Concat(rs)) }, @@ -681,7 +681,7 @@ mod tree_tests { let inputs = match item { st::Item::Op(st::Node::Join { left, right, .. }) => vec![left, right], st::Item::Op(st::Node::HalfJoin { arrangement, .. }) => vec![arrangement], - st::Item::Op(st::Node::Reduce { input, .. }) => vec![input], + st::Item::Op(st::Node::Reduce { input, .. }) => input.refs().collect(), _ => Vec::new(), }; for input in inputs { assert!(is_arranged(input, &program.root.items, &program.root.imports, &[]), "{item:?}"); } @@ -695,7 +695,7 @@ mod tree_tests { output "o" = x | min; "#)); assert!(!program.root.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Arrange(_))))); - assert!(program.root.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Reduce { input: Ref::Import(_), .. })))); + assert!(program.root.items.iter().any(|i| matches!(i, st::Item::Op(st::Node::Reduce { input, .. }) if matches!(input.as_single(), Some(Ref::Import(_)))))); } #[test] @@ -738,7 +738,7 @@ mod tree_tests { assert!(arranges.iter().any(|input| matches!(input, Ref::ChildExport(..)))); let inner = child(&program.root, "inner"); // The arranged parent item is entered as an arrangement, so the child reads it as is. - assert!(matches!(&inner.items[0], st::Item::Op(st::Node::Reduce { input: Ref::Import(_), .. }))); + assert!(matches!(&inner.items[0], st::Item::Op(st::Node::Reduce { input, .. }) if matches!(input.as_single(), Some(Ref::Import(_))))); assert!(!inner.items.iter().any(|item| matches!(item, st::Item::Op(st::Node::Arrange(_))))); } diff --git a/interactive/src/passes/as_of.rs b/interactive/src/passes/as_of.rs index 4cdbe55cd4..280bf27e0a 100644 --- a/interactive/src/passes/as_of.rs +++ b/interactive/src/passes/as_of.rs @@ -103,7 +103,8 @@ fn uses(s: &Scope) -> Vec> { add(arrangement, Use::Other); } Item::Op(Node::Linear { input, ops }) => add(input, if ops.iter().all(keeps_times) { Use::Linear(c) } else { Use::Other }), - Item::Op(Node::Arrange(r) | Node::Reduce { input: r, .. } | Node::Inspect { input: r, .. }) => add(r, Use::Other), + Item::Op(Node::Arrange(r) | Node::Inspect { input: r, .. }) => add(r, Use::Other), + Item::Op(Node::Reduce { input, .. }) => for r in input.refs() { add(r, Use::Other); }, Item::Op(Node::Join { left, right, .. }) => { add(left, Use::Other); add(right, Use::Other); } Item::Op(Node::Concat(refs)) => for r in refs { add(r, Use::Other); }, Item::Sub(child) => for imp in &child.imports { diff --git a/interactive/src/passes/dead_code.rs b/interactive/src/passes/dead_code.rs index 130d206312..6f63eeb1b5 100644 --- a/interactive/src/passes/dead_code.rs +++ b/interactive/src/passes/dead_code.rs @@ -64,7 +64,8 @@ fn analyze(scope: &Scope, exports: Option<&[bool]>) -> Live { if !live.items[i] { continue; } match node { Node::Linear { input, .. } | Node::Arrange(input) - | Node::Reduce { input, .. } | Node::Inspect { input, .. } => live.mark(input), + | Node::Inspect { input, .. } => live.mark(input), + Node::Reduce { input, .. } => for r in input.refs() { live.mark(r); }, Node::Join { left, right, .. } => { live.mark(left); live.mark(right); } Node::HalfJoin { stream, arrangement, .. } => { live.mark(stream); live.mark(arrangement); } Node::Concat(refs) => for r in refs { live.mark(r); }, diff --git a/interactive/src/passes/projection.rs b/interactive/src/passes/projection.rs index 807122bc53..a8b6783759 100644 --- a/interactive/src/passes/projection.rs +++ b/interactive/src/passes/projection.rs @@ -563,8 +563,8 @@ fn build_scope( )?; } Node::Reduce { input, .. } => { - let input = plan.at(input)?; - builder.opaque(&output, &[input]); + let inputs = input.refs().map(|r| plan.at(r)).collect::, _>>()?; + builder.opaque(&output, &inputs); } Node::Inspect { input, .. } => { // Inspection is observable even if its collection has @@ -764,7 +764,7 @@ fn rewrite_scope(scope: &mut st::Scope, plan: &PlannedScope, live: &[bool]) -> u (Item::Op(Node::Reduce { input, reducer, .. }), PlannedItem::Op { output, .. }) => { if needs_mask(&output.shape.1, &output.val, live) { let value = mask_part("input", &output.shape.1, &output.val, live); - let shape = &plan.at(input).expect("reduce input").shape; + let shape = &plan.at(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))).expect("reduce input").shape; *reducer = reducer.project(&Projection::parse(&value).expect("a value mask"), &shape.0, &shape.1); masked += output.val.iter().filter(|&&id| !live[id]).count(); } @@ -778,8 +778,8 @@ fn rewrite_scope(scope: &mut st::Scope, plan: &PlannedScope, live: &[bool]) -> u Item::Op(node) => match node { Node::Linear { input, .. } | Node::Arrange(input) - | Node::Reduce { input, .. } | Node::Inspect { input, .. } => remap_ref(input, &remap), + Node::Reduce { input, .. } => input.for_each_ref(|r| remap_ref(r, &remap)), Node::Join { left, right, .. } => { remap_ref(left, &remap); remap_ref(right, &remap); @@ -882,7 +882,7 @@ fn fuse_reduce_maps(scope: &mut st::Scope, shapes: &ScopeShapes, level: Level) - } if projections.is_empty() { continue; } let Item::Op(Node::Reduce { input, reducer, .. }) = &mut scope.items[j] else { unreachable!() }; - let Some(shape) = shapes.of(input) else { continue }; + let Some(shape) = shapes.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))) else { continue }; for projection in &projections { *reducer = reducer.project(projection, &shape.key, &shape.val); } changed += projections.len(); let Item::Op(Node::Linear { ops, .. }) = &mut scope.items[i] else { unreachable!() }; diff --git a/interactive/src/passes/structural.rs b/interactive/src/passes/structural.rs index 48d49bc604..fee852a485 100644 --- a/interactive/src/passes/structural.rs +++ b/interactive/src/passes/structural.rs @@ -71,7 +71,8 @@ pub(super) fn use_counts(scope: &Scope, dead: &[bool]) -> Vec { match item { Item::Op(node) => match node { Node::Linear { input, .. } | Node::Arrange(input) - | Node::Reduce { input, .. } | Node::Inspect { input, .. } => tally(input), + | Node::Inspect { input, .. } => tally(input), + Node::Reduce { input, .. } => input.refs().for_each(&mut tally), Node::Join { left, right, .. } => { tally(left); tally(right); }, Node::HalfJoin { stream, arrangement, .. } => { tally(stream); tally(arrangement); }, Node::Concat(refs) => for r in refs { tally(r); }, diff --git a/interactive/src/plan.rs b/interactive/src/plan.rs index 84d02a4dbf..2e5b7055c8 100644 --- a/interactive/src/plan.rs +++ b/interactive/src/plan.rs @@ -405,7 +405,7 @@ fn node(node: &Node, names: &Names) -> String { Node::Arrange(input) => format!("{} | arrange", names.of(input)), Node::Join { left, right, projection } => format!("{} | join({}, {})", names.of(left), names.of(right), source_lambda(projection)), Node::HalfJoin { stream, arrangement, strict, projection } => format!("{} | half_join({}, strict={strict}, {})", names.of(stream), names.of(arrangement), source_lambda(projection)), - Node::Reduce { input, reducer: r, limit } => format!("{} | {}", names.of(input), reducer(r, *limit)), + Node::Reduce { input, reducer: r, limit } => format!("{} | {}", names.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))), reducer(r, *limit)), Node::Inspect { input, label } => format!("{} | inspect({})", names.of(input), quote(label)), } } @@ -446,8 +446,8 @@ fn printed_node(node: &Node, names: &Names, shapes: &ScopeShapes, depth: usize, format!("{} | half_join({}, strict={strict}, {})", names.of(stream), names.of(arrangement), slots.lambda(projection, input, &format!("{at}/half_join"))) } Node::Reduce { input, reducer: Reducer::Expr(l), limit } => { - let input_shape = shapes.of(input).map(|s| Shape::Prod(vec![s.key, Shape::List(Box::new(Shape::Prod(vec![s.val, Shape::Int])))])); - format!("{} | reduce({}{})", names.of(input), ddp::limit_text(*limit), slots.lambda(l, input_shape, &format!("{at}/reduce"))) + let input_shape = shapes.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))).map(|s| Shape::Prod(vec![s.key, Shape::List(Box::new(Shape::Prod(vec![s.val, Shape::Int])))])); + format!("{} | reduce({}{})", names.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))), ddp::limit_text(*limit), slots.lambda(l, input_shape, &format!("{at}/reduce"))) } _ => self::node(node, names) } @@ -483,7 +483,7 @@ fn reads(node: &Node) -> Vec<(&Ref, &'static str)> { Node::Arrange(input) => vec![(input, "arrange/reuse")], Node::Join { left, right, .. } => vec![(left, "index"), (right, "index")], Node::HalfJoin { stream, arrangement, .. } => vec![(stream, "rows"), (arrangement, "index")], - Node::Reduce { input, .. } => vec![(input, "index")], + Node::Reduce { input, .. } => input.refs().map(|r| (r, "index")).collect(), } } diff --git a/interactive/src/plan/compare.rs b/interactive/src/plan/compare.rs index af1d094784..d41f429e5e 100644 --- a/interactive/src/plan/compare.rs +++ b/interactive/src/plan/compare.rs @@ -2,7 +2,7 @@ //! Scalar equality is equality of graphs compiled at the known input type, not sampled values. use crate::ir::{Lambda, LinearOp, Reducer}; -use crate::scope_ir::{Item, Node, Ref, Scope, Source}; +use crate::scope_ir::{Item, Node, ReduceInput, Ref, Scope, Source}; use crate::shapes::{ItemShapes, ScopeShapes}; use super::Report; @@ -28,6 +28,13 @@ struct Mapping { } impl Mapping { + fn same_reduce(&self, a: &ReduceInput, b: &ReduceInput) -> bool { + match (a, b) { + (ReduceInput::Merged(a), ReduceInput::Merged(b)) => a.len() == b.len() && a.iter().zip(b).all(|((a, x), (b, y))| x == y && self.same(a, b)), + (ReduceInput::Grouped(a), ReduceInput::Grouped(b)) => a.len() == b.len() && a.iter().zip(b).all(|(a, b)| self.same(a, b)), + _ => false, + } + } fn same(&self, a: &Ref, b: &Ref) -> bool { match (a, b) { (Ref::Import(a), Ref::Import(b)) => self.imports.get(*a) == Some(b), @@ -68,7 +75,7 @@ fn input_shapes(node: &Node, shapes: &ScopeShapes) -> Option> vec![Shape::Prod(vec![s.key, fields.first()?.clone(), a.val])] } Node::Reduce { input, .. } => { - let shape = shapes.of(input)?; + let shape = shapes.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")))?; vec![Shape::Prod(vec![shape.key, Shape::List(Box::new(Shape::Prod(vec![shape.val, Shape::Int])))])] } _ => Vec::new(), @@ -98,7 +105,7 @@ fn node(a: &Node, b: &Node, map: &Mapping, scalar: bool, inputs: &[corgi::Shape] (Node::Arrange(a), Node::Arrange(b)) => map.same(a, b), (Node::Join { left: a, right: b, projection: p }, Node::Join { left: c, right: d, projection: q }) => map.same(a, c) && map.same(b, d) && (!scalar || lambda(p, q, inputs.first())), (Node::HalfJoin { stream: a, arrangement: b, strict: s, projection: p }, Node::HalfJoin { stream: c, arrangement: d, strict: t, projection: q }) => map.same(a, c) && map.same(b, d) && s == t && (!scalar || lambda(p, q, inputs.first())), - (Node::Reduce { input: a, reducer: x, limit: s }, Node::Reduce { input: b, reducer: y, limit: t }) => map.same(a, b) && s == t && (!scalar || reducer(x, y, inputs.first())), + (Node::Reduce { input: a, reducer: x, limit: s }, Node::Reduce { input: b, reducer: y, limit: t }) => map.same_reduce(a, b) && s == t && (!scalar || reducer(x, y, inputs.first())), (Node::Inspect { input: a, label: x }, Node::Inspect { input: b, label: y }) => map.same(a, b) && x == y, _ => false, } diff --git a/interactive/src/plan/ddp.rs b/interactive/src/plan/ddp.rs index 789cb6f2b9..ddc6d08f22 100644 --- a/interactive/src/plan/ddp.rs +++ b/interactive/src/plan/ddp.rs @@ -423,11 +423,11 @@ impl Printer<'_> { Node::Reduce { input, reducer, limit } => { let word = match reducer { Reducer::Expr(l) => { - let input = shapes.of(input).map(|s| Shape::Prod(vec![s.key, Shape::List(Box::new(Shape::Prod(vec![s.val, Shape::Int])))])); + let input = shapes.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs"))).map(|s| Shape::Prod(vec![s.key, Shape::List(Box::new(Shape::Prod(vec![s.val, Shape::Int])))])); format!("reduce({}{})", limit_text(*limit), self.lambda(l, input)?) } }; - format!("{} | {word}", names.of(input)) + format!("{} | {word}", names.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")))) } Node::Inspect { input, label } => { if identifier(label) != *label { return Err(format!("inspect label {label:?} is not a DDP identifier")); } diff --git a/interactive/src/reducers.rs b/interactive/src/reducers.rs index f71e79a018..394c8dc75f 100644 --- a/interactive/src/reducers.rs +++ b/interactive/src/reducers.rs @@ -2,6 +2,7 @@ //! `vals` is nonempty, ordered, and holds `(value, nonzero diff)` pairs. use crate::ir::{Lambda, Reducer}; +use crate::scope_ir::ReduceInput; use crate::lambda::Projection; /// Distinct after its input has been keyed by the whole record. @@ -33,7 +34,10 @@ pub(crate) fn expand_distinct( let distinct = sites.peek() == Some(&i); if distinct { sites.next(); } let by_record = distinct && match &item { - Item::Op(Node::Reduce { input, .. }) => !shapes.of(input).is_some_and(|s| s.val == corgi::Shape::Unit), + Item::Op(Node::Reduce { input, .. }) => { + let input = input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")); + !shapes.of(input).is_some_and(|s| s.val == corgi::Shape::Unit) + } _ => false, }; match &mut item { @@ -68,7 +72,7 @@ pub(crate) fn expand_distinct( match &mut node { Node::Join { left, right, .. } => { arrange(left); arrange(right); } Node::HalfJoin { arrangement, .. } => arrange(arrangement), - Node::Reduce { input, .. } => arrange(input), + Node::Reduce { input, .. } => input.for_each_ref(&mut arrange), _ => {} } let r = Ref::Local(items.len()); @@ -78,13 +82,14 @@ pub(crate) fn expand_distinct( }; if distinct { let Item::Op(Node::Reduce { input, .. }) = item else { unreachable!() }; + let input = input.as_single().cloned().unwrap_or_else(|| unimplemented!("reduce over several inputs")); let input = if by_record { push(Node::Linear { input, ops: vec![LinearOp::Project(Lambda::new("let (k, v) = input in ((k, v), ())".into(), &corgi::Scope::default()))] }) } else { input }; // Both paths now have unit values: either they were known to be unit, // or the map above keyed the collection by its whole record. let reducer = Reducer::Expr(unit_distinct()); - let output = push(Node::Reduce { input, reducer, limit: None }); + let output = push(Node::Reduce { input: ReduceInput::single(input), reducer, limit: None }); if by_record { push(Node::Linear { input: output, ops: vec![LinearOp::Project(Lambda::new("let (kv, ()) = input in kv".into(), &corgi::Scope::default()))] }); } diff --git a/interactive/src/scope_ir.rs b/interactive/src/scope_ir.rs index ea47e6ed98..6d341fbbf2 100644 --- a/interactive/src/scope_ir.rs +++ b/interactive/src/scope_ir.rs @@ -35,7 +35,7 @@ //! imports targeting the same definition are the same entity, so facts //! learned at a definition propagate to every importer along its edges. -use crate::ir::{Lambda, LinearOp, Reducer}; +use crate::ir::{Diff, Lambda, LinearOp, Reducer}; type ItemId = usize; // index into `Scope::items` type ImportId = usize; // index into `Scope::imports` @@ -127,26 +127,78 @@ pub enum Node { HalfJoin { stream: Ref, arrangement: Ref, strict: bool, projection: Lambda }, /// `reducer`'s lambda over each key and its values. With `limit = Some(k)` it is handed only /// the key's first `k` values of non-zero net, in value order, whatever their sums. - Reduce { input: Ref, reducer: Reducer, limit: Option }, + /// + /// `input` names one or more arranged inputs, see [`ReduceInput`]. A `Grouped` input has no + /// limit. + Reduce { input: ReduceInput, reducer: Reducer, limit: Option }, Inspect { input: Ref, label: String }, } +/// The inputs of a `Reduce`, all arranged and all of one key shape. +#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +pub enum ReduceInput { + /// The signed union of the inputs: each key's values are the consolidated sum of every input's + /// updates, each multiplied by its input's sign, as if the inputs were concatenated (negative + /// ones negated) and arranged. All inputs share one row shape and every sign is `1` or `-1`. + /// `Merged([(x, 1)])` is the plain reduce of `x`. + Merged(Vec<(Ref, Diff)>), + /// Cogroup: the reducer is handed each key's values one list per input, `(key, (vals_0, .., + /// vals_{n-1}))`, each `vals_i` input `i`'s consolidated `(val, diff)` list in value order, + /// empty where the input holds nothing at the key. Equal values of different inputs never + /// merge. Inputs share a key shape. Their value shapes may differ. + Grouped(Vec), +} + +impl ReduceInput { + /// The plain reduce of `r`. + pub fn single(r: Ref) -> Self { ReduceInput::Merged(vec![(r, 1)]) } + /// The input of a plain reduce, `Merged([(r, 1)])`. + pub fn as_single(&self) -> Option<&Ref> { + match self { ReduceInput::Merged(v) if v.len() == 1 && v[0].1 == 1 => Some(&v[0].0), _ => None } + } + /// As [`Self::as_single`], mutably. + pub fn as_single_mut(&mut self) -> Option<&mut Ref> { + match self { ReduceInput::Merged(v) if v.len() == 1 && v[0].1 == 1 => Some(&mut v[0].0), _ => None } + } + /// The first input, which fixes the key shape, and for `Merged` the row shape. + pub fn first(&self) -> &Ref { + match self { ReduceInput::Merged(v) => &v[0].0, ReduceInput::Grouped(v) => &v[0] } + } + /// Every input, in order. + pub fn refs(&self) -> impl Iterator { + let (merged, grouped): (&[(Ref, Diff)], &[Ref]) = match self { + ReduceInput::Merged(v) => (v, &[]), + ReduceInput::Grouped(v) => (&[], v), + }; + merged.iter().map(|(r, _)| r).chain(grouped) + } + /// Applies `f` to every input, in order. + pub fn for_each_ref(&mut self, mut f: impl FnMut(&mut Ref)) { + match self { + ReduceInput::Merged(v) => for (r, _) in v { f(r) }, + ReduceInput::Grouped(v) => for r in v { f(r) }, + } + } +} + impl Node { pub(crate) fn refs(&self) -> impl Iterator { - let (first, second, rest): (_, _, &[_]) = match self { + let (first, second, rest, reduce): (_, _, &[_], _) = match self { Self::Linear { input, .. } | Self::Arrange(input) - | Self::Reduce { input, .. } | Self::Inspect { input, .. } => (Some(input), None, &[]), - Self::Join { left, right, .. } => (Some(left), Some(right), &[]), - Self::HalfJoin { stream, arrangement, .. } => (Some(stream), Some(arrangement), &[]), - Self::Concat(refs) => (None, None, refs), + | Self::Inspect { input, .. } => (Some(input), None, &[], None), + Self::Reduce { input, .. } => (None, None, &[], Some(input)), + Self::Join { left, right, .. } => (Some(left), Some(right), &[], None), + Self::HalfJoin { stream, arrangement, .. } => (Some(stream), Some(arrangement), &[], None), + Self::Concat(refs) => (None, None, refs, None), }; - first.into_iter().chain(second).chain(rest) + first.into_iter().chain(second).chain(rest).chain(reduce.into_iter().flat_map(ReduceInput::refs)) } pub(crate) fn for_each_ref(&mut self, mut f: impl FnMut(&mut Ref)) { match self { + Self::Reduce { input, .. } => input.for_each_ref(f), Self::Linear { input, .. } | Self::Arrange(input) - | Self::Reduce { input, .. } | Self::Inspect { input, .. } => f(input), + | Self::Inspect { input, .. } => f(input), Self::Join { left, right, .. } => { f(left); f(right); } Self::HalfJoin { stream, arrangement, .. } => { f(stream); f(arrangement); } Self::Concat(refs) => for r in refs { f(r); }, @@ -325,7 +377,13 @@ fn dump_scope_body(s: &Scope, indent: usize) { Node::Arrange(r) => format!("{} | arrange", fmt_ref(r)), Node::Join { left, right, .. } => format!("join({}, {})", fmt_ref(left), fmt_ref(right)), Node::HalfJoin { stream, arrangement, strict, .. } => format!("{} | half_join({}, {})", fmt_ref(stream), fmt_ref(arrangement), *strict as u8), - Node::Reduce { input, reducer, limit } => format!("{} | {:?} limit={limit:?}", fmt_ref(input), reducer), + Node::Reduce { input, reducer, limit } => { + let inputs = match input { + ReduceInput::Merged(v) => v.iter().map(|(r, s)| format!("{}{}", if *s < 0 { "-" } else { "" }, fmt_ref(r))).collect::>().join(" + "), + ReduceInput::Grouped(v) => format!("cogroup({})", v.iter().map(fmt_ref).collect::>().join(", ")), + }; + format!("{} | {:?} limit={limit:?}", inputs, reducer) + } Node::Inspect { input, label } => format!("{} | inspect({})", fmt_ref(input), label), }; println!("{}n{} = {};", pad2, i, desc); @@ -392,4 +450,11 @@ mod tests { assert!(matches!(prog.root.imports[0].from, Source::Input(0))); assert!(matches!(reach.binds[0].value, Ref::Local(1))); } + + #[test] + fn reduce_input_single_round_trips() { + assert_eq!(ReduceInput::single(Ref::Local(3)).as_single(), Some(&Ref::Local(3))); + assert_eq!(ReduceInput::Merged(vec![(Ref::Local(3), -1)]).as_single(), None); + assert_eq!(ReduceInput::Grouped(vec![Ref::Local(1), Ref::Local(2)]).refs().count(), 2); + } } diff --git a/interactive/src/shapes.rs b/interactive/src/shapes.rs index c54e57f779..07874d9c91 100644 --- a/interactive/src/shapes.rs +++ b/interactive/src/shapes.rs @@ -343,7 +343,7 @@ fn infer_node(node: &st::Node, shapes: &ScopeShapes, level: Level, at: &str, pro } } st::Node::Reduce { input, reducer, .. } => { - let c = shapes.of(input)?; + let c = shapes.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")))?; let Reducer::Expr(lambda) = reducer; let v = match reduce_shape(lambda, &c.key, &c.val) { Ok(v) => v, diff --git a/interactive/tests/plan_pairs.rs b/interactive/tests/plan_pairs.rs index 2259e85a7b..239f4dc3ed 100644 --- a/interactive/tests/plan_pairs.rs +++ b/interactive/tests/plan_pairs.rs @@ -75,7 +75,8 @@ fn check_scope(scope: &Scope, parent: Option<(&Scope, usize)>, labels: bool, ori match item { Item::Op(node) => match node { Node::Linear { input, .. } | Node::Arrange(input) - | Node::Reduce { input, .. } | Node::Inspect { input, .. } => check_ref(input, i), + | Node::Inspect { input, .. } => check_ref(input, i), + Node::Reduce { input, .. } => input.refs().for_each(|r| check_ref(r, i)), Node::Concat(refs) => for r in refs { check_ref(r, i); }, Node::Join { left, right, .. } => { check_ref(left, i); check_ref(right, i); } Node::HalfJoin { stream, arrangement, .. } => { check_ref(stream, i); check_ref(arrangement, i); } From 55dd5dc7c50a91f7f0812b128e14e31510f6536b Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Tue, 10 Nov 2026 10:52:11 +0100 Subject: [PATCH 04/19] DDIR: bracket lists of signed inputs for reduces A list [a, -b] before min, distinct, count, collect or reduce lowers to one reduce over Merged inputs, each arranged on its own with its sign. Shape inference takes the row shape from any known element. The runtime renders a merged reduce as concat, arrange, then the unary reduce, until an N-ary operator replaces it. Co-Authored-By: Claude Sonnet 5.5 --- interactive/src/backend/mod.rs | 22 +++- interactive/src/lower.rs | 13 ++ interactive/src/parse/mod.rs | 3 + interactive/src/parse/pipe.rs | 44 ++++++- interactive/src/plan/ddp/parsed.rs | 10 +- interactive/src/reducers.rs | 5 +- interactive/src/shapes.rs | 9 +- interactive/tests/variadic_reduce.rs | 178 +++++++++++++++++++++++++++ 8 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 interactive/tests/variadic_reduce.rs diff --git a/interactive/src/backend/mod.rs b/interactive/src/backend/mod.rs index a739e83d56..2239695e52 100644 --- a/interactive/src/backend/mod.rs +++ b/interactive/src/backend/mod.rs @@ -258,10 +258,24 @@ pub(crate) fn render_scope<'s, B: Backend>( let a = resolve(&items, &imports, &var_cols, arrangement).arrange(); Rendered::Collection(B::half_join(c, a, *strict, projection, level, (shape_of(stream), shape_of(arrangement)))) }, - st::Node::Reduce { input, reducer, limit } => { - let input = input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")); - let a = resolve(&items, &imports, &var_cols, input).arrange(); - Rendered::Arrangement(B::reduce(a, reducer, *limit, shape_of(input))) + st::Node::Reduce { input, reducer, limit } => match (input.as_single(), input) { + (Some(input), _) => { + let a = resolve(&items, &imports, &var_cols, input).arrange(); + Rendered::Arrangement(B::reduce(a, reducer, *limit, shape_of(input))) + }, + // A merged reduce is the reduce of the signed concatenation of its inputs. + (None, st::ReduceInput::Merged(inputs)) => { + let shape = shape_of(&inputs[0].0); + let mut parts = inputs.iter().map(|(r, sign)| { + let c = resolve(&items, &imports, &var_cols, r).collection(); + if *sign < 0 { B::linear(c, vec![LinearOp::Negate], level, shape_of(r)) } else { c } + }); + let first = parts.next().expect("a merged reduce has an input"); + let union = parts.fold(first, |acc, c| acc.concat(c)); + let a = Rendered::<'s, B>::Collection(union).arrange(); + Rendered::Arrangement(B::reduce(a, reducer, *limit, shape)) + }, + (None, st::ReduceInput::Grouped(_)) => unimplemented!("reduce over several inputs"), }, st::Node::Inspect { input, label } => { let c = resolve(&items, &imports, &var_cols, input).collection(); diff --git a/interactive/src/lower.rs b/interactive/src/lower.rs index 85a47f89f4..c97331fcc1 100644 --- a/interactive/src/lower.rs +++ b/interactive/src/lower.rs @@ -196,6 +196,7 @@ fn resolve_expr(expr: &mut Expr, here: &[String], item: Option<&str>, resolve_expr(r, here, item, scopes, plan); } Expr::Concat(parts) => for part in parts { resolve_expr(part, here, item, scopes, plan); }, + Expr::List(parts) => for (_, part) in parts { resolve_expr(part, here, item, scopes, plan); }, Expr::Input(..) | Expr::Import(_) | Expr::Name(_) | Expr::ResolvedPath { .. } => {}, } } @@ -252,6 +253,7 @@ fn expr_free_names(expr: &Expr, out: &mut BTreeSet) { | Expr::Inspect(e, _) | Expr::Arrange(e) => expr_free_names(e, out), Expr::Join(l, r, _) | Expr::HalfJoin(l, r, _, _) => { expr_free_names(l, out); expr_free_names(r, out); }, Expr::Concat(es) => { for e in es { expr_free_names(e, out); } }, + Expr::List(es) => { for (_, e) in es { expr_free_names(e, out); } }, } } @@ -418,7 +420,17 @@ impl ScopeLower { let rr = self.lower_expr(r); let ra = self.arrange(rr); self.push(st::Node::HalfJoin { stream, arrangement: ra, strict: *strict, projection: p.clone() }) }, + Expr::Reduce(e, red) if matches!(&**e, Expr::List(parts) if parts.len() != 1 || parts[0].0 < 0) => { + let Expr::List(parts) = &**e else { unreachable!() }; + // Each element is an input of its own, so its sign becomes the input's sign and no + // `negate` is built. A merged distinct is not a by-record site: no arrangement of + // the sum exists to be keyed by the record, and `Distinct` handles any values. + let inputs = parts.iter().map(|(sign, part)| { let r = self.lower_expr(part); (self.arrange(r), *sign) }).collect(); + self.push(st::Node::Reduce { input: st::ReduceInput::Merged(inputs), reducer: crate::ir::Reducer::Expr(red.lambda()), limit: red.limit() }) + }, Expr::Reduce(e, red)=> { + // `[e]` is `e`. + let e = match &**e { Expr::List(parts) => &parts[0].1, e => e }; let r = self.lower_expr(e); let a = if matches!(red, Reducer::Distinct) { // Once shapes are known, lower distinct by key or by whole record. @@ -428,6 +440,7 @@ impl ScopeLower { self.push(st::Node::Reduce { input: st::ReduceInput::single(a), reducer: crate::ir::Reducer::Expr(red.lambda()), limit: red.limit() }) }, Expr::Inspect(e, l) => { let r = self.lower_expr(e); self.push(st::Node::Inspect { input: r, label: l.clone() }) }, + Expr::List(_) => unreachable!("the parser admits a list only as the input of a reduce"), Expr::Concat(es) => { let rs: Vec = es.iter().map(|e| self.lower_expr(e)).collect(); self.push(st::Node::Concat(rs)) }, } } diff --git a/interactive/src/parse/mod.rs b/interactive/src/parse/mod.rs index 06d957a747..fcdf30653d 100644 --- a/interactive/src/parse/mod.rs +++ b/interactive/src/parse/mod.rs @@ -79,6 +79,9 @@ pub enum Expr { Inspect(Box, String), Concat(Vec), Arrange(Box), + /// `[e, -f, ..]`: the signed elements, each sign `1` or `-1`. Only a reduce reads one, as its + /// input (`Reduce(List(..), _)`), the sum of its elements. + List(Vec<(crate::ir::Diff, Expr)>), } #[derive(Debug)] diff --git a/interactive/src/parse/pipe.rs b/interactive/src/parse/pipe.rs index fc7540180d..1cfdd82a4c 100644 --- a/interactive/src/parse/pipe.rs +++ b/interactive/src/parse/pipe.rs @@ -41,6 +41,11 @@ //! `List` of `(val, diff)`. `| reduce(limit n, (k, vals) -> out)` hands the lambda only each //! key's first `n` values (`n` at least one), whatever their diffs; `min` is //! `reduce(limit 1, (_, vals) -> (vals head.0, 1) enlist)`. +//! - `[a, -b] | min` (also `distinct`, `count`, `collect`, `reduce(..)`) — reduce the signed sum of a +//! bracket list of collections, as `a - b | min` does but without arranging the sum. Each element +//! is an optional `-` and a pipe expression up to the next `,` or `]`, and the sign covers the +//! whole element. A list is no collection: only a reduce reads one, so it must be followed by one +//! of those stages. `[e]` is `e`. //! - `| filter((k, v) -> mask)` — keep rows where the lambda gives a nonzero `Int`. //! - `| flatmap((k, v) -> list)` — UNNEST: explode the `List` the lambda gives into one row per //! element, value `(pos, element)`. @@ -122,11 +127,13 @@ enum Token { Ident(String), Int(i64), Str(String), /// A slot written as a corgi lambda, `pat -> body`, kept as corgi source. Lambda { pat: String, body: String }, - LParen, RParen, LBrace, RBrace, + LParen, RParen, LBrace, RBrace, LBracket, RBracket, Comma, Semi, Colon, ColonColon, Eq, Pipe, Plus, Minus, Eof, } +const LIST_MISUSE: &str = "a list of collections is the input of a reduce"; + /// A shape before names in type declarations have been resolved. enum TypeShape { Unit, Int, Float, @@ -253,6 +260,8 @@ fn lex(input: &str) -> Vec { } }, ')' => { chars.next(); tokens.push(Token::RParen); }, + '[' => { chars.next(); tokens.push(Token::LBracket); }, + ']' => { chars.next(); tokens.push(Token::RBracket); }, '{' => { chars.next(); tokens.push(Token::LBrace); }, '}' => { chars.next(); tokens.push(Token::RBrace); }, ',' => { chars.next(); tokens.push(Token::Comma); }, @@ -523,8 +532,21 @@ impl Parser { /// An atom followed by stages, applied left to right: `| op`, `+ atom` and `- atom`. A run of /// `+`/`-` stages is one `Concat`. + /// + /// A bracket list `[e, -f]` is only the input of a reduce, so it must start the expression + /// and the next stage must be `| min`, `| distinct`, `| count`, `| collect` or `| reduce(`. fn parse_pipe_expr(&mut self) -> Expr { - let mut expr = self.parse_atom(); + let mut expr = if *self.peek() == Token::LBracket { + let list = self.parse_list(); + // The token stream ends in `Eof`, so a `Pipe` has a successor. + let reduces = *self.peek() == Token::Pipe && match &self.tokens[self.pos + 1] { + Token::Min | Token::Distinct | Token::Count | Token::Collect => true, + Token::Ident(word) => word == "reduce", + _ => false, + }; + assert!(reduces, "{LIST_MISUSE}"); + list + } else { self.parse_atom() }; let mut concat = false; loop { let part = match self.peek() { @@ -542,6 +564,23 @@ impl Parser { expr } + /// `[` element `,` element `]`, each element an optional `-` and a pipe expression that ends at + /// the next top-level `,` or `]`. The sign covers the whole element. + fn parse_list(&mut self) -> Expr { + self.expect(&Token::LBracket); + let mut elements = Vec::new(); + loop { + let sign = if *self.peek() == Token::Minus { self.next(); -1 } else { 1 }; + elements.push((sign, self.parse_pipe_expr())); + match self.next() { + Token::Comma => {}, + Token::RBracket => break, + other => panic!("Expected `,` or `]` in a list, got {:?}", other), + } + } + Expr::List(elements) + } + fn parse_atom(&mut self) -> Expr { match self.peek().clone() { Token::Input => { @@ -578,6 +617,7 @@ impl Parser { else { Expr::Name(parts.pop().unwrap()) } }, Token::LParen => { self.next(); let e = self.parse_pipe_expr(); self.expect(&Token::RParen); e }, + Token::LBracket => panic!("{LIST_MISUSE}"), other => panic!("Unexpected token in atom: {:?}", other), } } diff --git a/interactive/src/plan/ddp/parsed.rs b/interactive/src/plan/ddp/parsed.rs index 23185e9c4a..3a2f9c01e5 100644 --- a/interactive/src/plan/ddp/parsed.rs +++ b/interactive/src/plan/ddp/parsed.rs @@ -72,11 +72,13 @@ impl Printer<'_> { Expr::Join(left, right, l) => format!("{} | join({}, {})", self.expression(left)?, self.expression(right)?, self.parsed_lambda(l)?), Expr::HalfJoin(stream, arrangement, strict, l) => format!("{} | half_join({}, {}, {})", self.expression(stream)?, self.expression(arrangement)?, u8::from(*strict), self.parsed_lambda(l)?), Expr::Reduce(input, reducer) => { - let lambda = if matches!(reducer, crate::parse::Reducer::Distinct) { + // A list is no collection to key by its records, and `distinct` handles any values. + let by_record = matches!(reducer, crate::parse::Reducer::Distinct) && !matches!(**input, Expr::List(_)); + let lambda = if by_record { self.parsed_lambda(&crate::reducers::unit_distinct())? } else { self.parsed_lambda(&reducer.lambda())? }; let input = self.expression(input)?; - if matches!(reducer, crate::parse::Reducer::Distinct) { + if by_record { // Parsed syntax has no inferred shapes. Key by the whole record, // which also preserves unit-valued distinct's meaning. format!("{input} | map((k, v) -> ((k, v), ())) | reduce({lambda}) | map((kv, ()) -> kv)") @@ -90,6 +92,10 @@ impl Printer<'_> { } Expr::Inspect(input, label) => format!("{} | inspect({label})", self.expression(input)?), Expr::Concat(parts) => parts.iter().map(|part| self.atom(part)).collect::, _>>()?.join(" + "), + Expr::List(parts) => { + let parts = parts.iter().map(|(sign, part)| Ok(format!("{}{}", if *sign < 0 { "-" } else { "" }, self.expression(part)?))).collect::, String>>()?; + format!("[{}]", parts.join(", ")) + } }) } } diff --git a/interactive/src/reducers.rs b/interactive/src/reducers.rs index 394c8dc75f..1e70e979ba 100644 --- a/interactive/src/reducers.rs +++ b/interactive/src/reducers.rs @@ -35,7 +35,8 @@ pub(crate) fn expand_distinct( if distinct { sites.next(); } let by_record = distinct && match &item { Item::Op(Node::Reduce { input, .. }) => { - let input = input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")); + // Lowering registers only the plain reduce of one positive input as a site. + let input = input.as_single().expect("a distinct site reads one input"); !shapes.of(input).is_some_and(|s| s.val == corgi::Shape::Unit) } _ => false, @@ -82,7 +83,7 @@ pub(crate) fn expand_distinct( }; if distinct { let Item::Op(Node::Reduce { input, .. }) = item else { unreachable!() }; - let input = input.as_single().cloned().unwrap_or_else(|| unimplemented!("reduce over several inputs")); + let input = input.as_single().cloned().expect("a distinct site reads one input"); let input = if by_record { push(Node::Linear { input, ops: vec![LinearOp::Project(Lambda::new("let (k, v) = input in ((k, v), ())".into(), &corgi::Scope::default()))] }) } else { input }; diff --git a/interactive/src/shapes.rs b/interactive/src/shapes.rs index 07874d9c91..ad959f2e06 100644 --- a/interactive/src/shapes.rs +++ b/interactive/src/shapes.rs @@ -343,7 +343,14 @@ fn infer_node(node: &st::Node, shapes: &ScopeShapes, level: Level, at: &str, pro } } st::Node::Reduce { input, reducer, .. } => { - let c = shapes.of(input.as_single().unwrap_or_else(|| unimplemented!("reduce over several inputs")))?; + let st::ReduceInput::Merged(inputs) = input else { unimplemented!("reduce over several inputs") }; + // The inputs are summed, so any one whose shape is known gives the row shape. In a loop + // the others may be known only through this reduce. + let known: Vec = inputs.iter().filter_map(|(r, _)| shapes.of(r)).collect(); + let c = known.first()?.clone(); + if let Some(other) = known.iter().find(|o| o.key != c.key || o.val != c.val) { + return fail(format!("reduce over inputs ({}, {}) and ({}, {})", c.key, c.val, other.key, other.val)); + } let Reducer::Expr(lambda) = reducer; let v = match reduce_shape(lambda, &c.key, &c.val) { Ok(v) => v, diff --git a/interactive/tests/variadic_reduce.rs b/interactive/tests/variadic_reduce.rs new file mode 100644 index 0000000000..b6cc6ba011 --- /dev/null +++ b/interactive/tests/variadic_reduce.rs @@ -0,0 +1,178 @@ +//! Bracket lists: `[a, -b] | reduce` reduces the signed sum of its elements as one merged reduce. +//! +//! The tests check lowering, the answers against the same programs written as concatenations, +//! shape inference in loops, and the parse errors. + +use std::collections::BTreeMap; + +use interactive::scope_ir::{Item, Node, ReduceInput, Ref}; +use interactive::server::Server; + +type Rows = Vec<(String, String, i64)>; + +/// Run `src` on `epochs`, each a list of feed lines per input, through `workers` workers, ticking +/// after each epoch. Returns, per epoch, each output's sorted rows. +fn run(workers: usize, src: &str, passes: Option<&str>, epochs: Vec>>) -> Vec> { + let program = interactive::lower::lower_tree(interactive::parse::pipe::parse(src)); + let passes = passes.map(|p| interactive::passes::Config::parse(p).unwrap()); + let guards = timely::execute(timely::Config::process(workers), move |worker| { + let mut server = Server::new(); + if let Some(passes) = passes { server.set_passes(passes); } + server.install(worker, "p", &program).expect("install"); + let mut out = Vec::new(); + for epoch in &epochs { + for (input, rows) in epoch.iter().enumerate() { + let shard: Vec<&str> = rows.iter().skip(worker.index()).step_by(worker.peers()).map(String::as_str).collect(); + server.feed("p", input, &shard.join("\n"), None).expect("feed"); + } + server.tick(worker); + let snapshots = program.root.exports.iter().map(|e| { + let mut rows = server.snapshot(worker, &format!("p::{}", e.name)).expect("snapshot").rows(); + rows.sort(); + (e.name.clone(), rows) + }).collect(); + out.push(snapshots); + } + out + }).expect("workers"); + guards.join().into_iter().next().unwrap().unwrap() +} + +fn lines(rows: &[(i64, i64, i64)]) -> Vec { + rows.iter().map(|(k, v, d)| format!("{k} val={v} diff={d}")).collect() +} + +/// The panic text of parsing `src`. +fn parse_error(src: &str) -> String { + let src = src.to_string(); + let payload = std::panic::catch_unwind(move || { interactive::parse::pipe::parse(&src); }).expect_err("the program parses"); + payload.downcast_ref::().cloned().or_else(|| payload.downcast_ref::<&str>().map(|s| s.to_string())).expect("a text panic") +} + +const LIST_MISUSE: &str = "a list of collections is the input of a reduce"; + +#[test] +fn list_lowers_to_merged() { + let src = r#" + let a = input 0 : (int, int) | arrange; + let b = input 1 : (int, int) | arrange; + output "o" = [a, -b] | count; + "#; + let program = interactive::lower::lower_tree(interactive::parse::pipe::parse(src)); + let items = &program.root.items; + let arranges: Vec = (0..items.len()).filter(|i| matches!(&items[*i], Item::Op(Node::Arrange(_)))).collect(); + assert_eq!(arranges.len(), 2, "{items:?}"); + let reduces: Vec<&ReduceInput> = items.iter().filter_map(|i| match i { Item::Op(Node::Reduce { input, .. }) => Some(input), _ => None }).collect(); + assert_eq!(reduces.len(), 1); + assert_eq!(*reduces[0], ReduceInput::Merged(vec![(Ref::Local(arranges[0]), 1), (Ref::Local(arranges[1]), -1)])); +} + +#[test] +fn list_answers_match_concat() { + let epochs = vec![ + vec![lines(&[(1, 5, 1), (1, 7, 2), (2, 3, 1), (3, 1, 1)]), lines(&[(1, 5, 1), (3, 9, 1), (1, 6, 1)]), lines(&[(1, 7, 1), (2, 3, 1)])], + vec![lines(&[(1, 5, -1), (4, 4, 1)]), lines(&[(3, 9, -1), (2, 3, 1), (4, 4, 1)]), lines(&[(1, 7, -1), (3, 1, 1)])], + vec![lines(&[(1, 7, -2), (2, 3, -1)]), lines(&[(1, 5, -1), (1, 6, 1), (2, 3, -1)]), lines(&[(4, 4, 1), (1, 6, 1)])], + ]; + // The list, then the concatenation it denotes. A lambda inside an element must still lex. + let cases = [ + ("[a, -b] | count", "a - b | count"), + ("[a, -b] | min", "a - b | min"), + ("[a, -b] | collect", "a - b | collect"), + ("[a, -b] | reduce((k, vals) -> vals)", "a - b | reduce((k, vals) -> vals)"), + ("[a, -b] | reduce(limit 1, (k, vals) -> vals)", "a - b | reduce(limit 1, (k, vals) -> vals)"), + ("[-a] | count", "a | negate | count"), + ("[a, b - c] | distinct", "a + b - c | distinct"), + ("[a | map((k, v) -> (k, v)), -b] | distinct", "a | map((k, v) -> (k, v)) - b | distinct"), + ("[a, -b | filter((k, v) -> v)] | distinct", "a - (b | filter((k, v) -> v)) | distinct"), + ("[a] | distinct", "a | distinct"), + ]; + for workers in [1, 3] { + for (list, concat) in cases { + let program = |expr: &str| format!("let a = input 0 : (int, int); let b = input 1 : (int, int); let c = input 2 : (int, int); output \"o\" = {expr};"); + let expected = run(workers, &program(concat), None, epochs.clone()); + assert_eq!(run(workers, &program(list), None, epochs.clone()), expected, "{list} on {workers} workers"); + } + } +} + +#[test] +fn list_in_loop_infers_shape() { + // The list's reduce is the left operand of `+`, which pins stage precedence. + let src = r#" + let seed = input 0 : (int, int); + let blocked = input 1 : (int, int); + s: { set x = [::seed, -::blocked] | distinct + (x | map((k, v) -> (k, v))) | distinct; } + output "o" = s::x; + "#; + let epochs = vec![ + vec![lines(&[(1, 1, 1), (2, 2, 1), (3, 3, 1)]), lines(&[(2, 2, 1)])], + vec![lines(&[(4, 4, 1)]), lines(&[(1, 1, 1), (2, 2, -1)])], + ]; + let plain = r#" + let seed = input 0 : (int, int); + let blocked = input 1 : (int, int); + s: { set x = (::seed - ::blocked | distinct) + (x | map((k, v) -> (k, v))) | distinct; } + output "o" = s::x; + "#; + for workers in [1, 2] { + assert_eq!(run(workers, src, None, epochs.clone()), run(workers, &plain, None, epochs.clone())); + } + // No `var` declares x's shape: it comes from the list's elements. + let src = r#" + let seed = input 0 : (int, int); + s: { set x = [::seed, -x] | distinct; } + output "o" = s::x; + "#; + let mut program = interactive::lower::lower_tree(interactive::parse::pipe::parse(src)); + interactive::passes::optimize(&mut program); + let (_, problems) = interactive::shapes::infer(&program, &|_| None, 1); + assert!(problems.conflicts.is_empty(), "{:?}", problems.conflicts); +} + +#[test] +fn by_record_distinct_element_is_arranged() { + let src = r#" + let a = input 0 : (int, int); + let b = input 1 : (int, int); + output "o" = [a | distinct, -b] | distinct; + "#; + let program = interactive::lower::lower_tree(interactive::parse::pipe::parse(src)); + let items = &program.root.items; + let mut merged = 0; + for item in items { + let Item::Op(Node::Reduce { input: ReduceInput::Merged(inputs), .. }) = item else { continue }; + if inputs.len() < 2 { continue } + merged += 1; + for (r, _) in inputs { + let Ref::Local(i) = r else { panic!("{r:?}") }; + assert!(matches!(&items[*i], Item::Op(Node::Arrange(_) | Node::Reduce { .. })), "{:?}", items[*i]); + } + } + assert_eq!(merged, 1); + let epochs = vec![ + vec![lines(&[(1, 5, 2), (2, 3, 1), (3, 1, 1)]), lines(&[(1, 5, 1), (3, 9, 1)])], + vec![lines(&[(1, 5, -1), (4, 4, 1)]), lines(&[(2, 3, 1), (4, 4, 1)])], + vec![lines(&[(1, 5, -1), (2, 3, -1)]), lines(&[(1, 5, -1), (2, 3, -1)])], + ]; + let program = |expr: &str| format!("let a = input 0 : (int, int); let b = input 1 : (int, int); output \"o\" = {expr};"); + for workers in [1, 3] { + assert_eq!( + run(workers, &program("[a | distinct, -b] | distinct"), None, epochs.clone()), + run(workers, &program("(a | distinct) - b | distinct"), None, epochs.clone()), + ); + } +} + +#[test] +fn list_misuse_is_rejected() { + for src in [ + "let a = input 0 : (int, int); let b = input 1 : (int, int); let p = [a, -b];", + "let a = input 0 : (int, int); output \"o\" = [a];", + "let a = input 0 : (int, int); let b = input 1 : (int, int); output \"o\" = [a, -b] | map((k, v) -> (k, v));", + "let a = input 0 : (int, int); let b = input 1 : (int, int); output \"o\" = [a] + b;", + "let a = input 0 : (int, int); let b = input 1 : (int, int); output \"o\" = a + [b];", + ] { + assert_eq!(parse_error(src), LIST_MISUSE, "{src}"); + } +} From 1c5fe043f0e9a24f8ac47427e9a72d21d8066a2a Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Tue, 10 Nov 2026 10:56:44 +0100 Subject: [PATCH 05/19] differential: co_reduce_with_tactic over several arrangements A reduce driver over several arrangements of one trace type. It mirrors reduce_with_tactic and hands the tactic batches tagged by input, retiring the interval bounded by the meet of the inputs' progress. Co-Authored-By: Claude Opus 5.5 --- .../src/operators/co_reduce.rs | 179 ++++++++++++++++++ differential-dataflow/src/operators/mod.rs | 1 + 2 files changed, 180 insertions(+) create mode 100644 differential-dataflow/src/operators/co_reduce.rs diff --git a/differential-dataflow/src/operators/co_reduce.rs b/differential-dataflow/src/operators/co_reduce.rs new file mode 100644 index 0000000000..53d10d4513 --- /dev/null +++ b/differential-dataflow/src/operators/co_reduce.rs @@ -0,0 +1,179 @@ +//! A key-wise reduction over several co-arranged inputs. +//! +//! The driver mirrors [`reduce_with_tactic`](crate::operators::reduce::reduce_with_tactic), with one +//! source trace per input. Batches reach the tactic tagged by their input, `(i, batch)`, so any +//! [`ReduceTactic`] whose backend reads tagged batches runs unchanged. +//! +//! The interval retired is bounded by the meet of the inputs' progress. An input running ahead of +//! the others can hand the tactic batches holding times beyond the interval. The tactic must defer +//! the times it finds there, as it does output times. + +use timely::progress::frontier::Antichain; +use timely::progress::Timestamp; +use timely::dataflow::operators::CapabilitySet; +use timely::dataflow::operators::generic::OutputBuilder; +use timely::dataflow::operators::generic::builder_rc::OperatorBuilder; +use timely::dataflow::channels::pact::Pipeline; + +use crate::operators::arrange::{Arranged, TraceAgent}; +use crate::operators::reduce::ReduceTactic; +use crate::trace::{ExertionLogic, Trace, TraceReader}; + +/// Per-input state of the driver. +struct Side { + trace: Tr, + /// Received batches not yet handed to the tactic, with their capabilities, in order. + queued: Vec<(CapabilitySet, Tr::Batch, Antichain)>, + /// The upper of the last received batch, advanced past empty batches in the trace. + received: Antichain, + /// The bound through which batches have been handed to the tactic, a batch boundary. + handed: Antichain, +} + +impl Side { + fn new(trace: Tr) -> Self { + let min = Antichain::from_elem(::minimum()); + Side { trace, queued: Vec::new(), received: min.clone(), handed: min } + } +} + +/// Drives a key-wise reduction over `inputs`, at least one, using a supplied [`ReduceTactic`]. +/// +/// The tactic sees each batch tagged by the index of the input it came from. Its output at a time +/// `t` must be a function of each key's input accumulations at `t`. Beyond the contract of +/// [`ReduceTactic::retire`], it must defer every time at or beyond `upper` that a new input batch +/// holds, and leave its input unread only when no held time lies below `upper`. +pub fn co_reduce_with_tactic<'scope, Tr1, Tr2, T>( + inputs: Vec>, + name: &str, + mut tactic: T, +) -> Arranged<'scope, TraceAgent> +where + Tr1: TraceReader + 'static, + Tr2: Trace