Skip to content

Commit

Permalink
Add multiplication operator and test behavior of aggregations with gr…
Browse files Browse the repository at this point in the history
…ouping expressions (#571)
  • Loading branch information
shadaj authored Apr 11, 2023
1 parent 6b2a12c commit b3e790c
Show file tree
Hide file tree
Showing 7 changed files with 369 additions and 28 deletions.
28 changes: 27 additions & 1 deletion hydroflow/tests/datalog_frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,31 @@ fn test_aggregations_and_comments() {
assert_eq!(&res, &[(3, 1), (10, 3)]);
}

#[multiplatform_test]
fn test_aggregations_group_by_expr() {
let (ints_send, ints) = hydroflow::util::unbounded_channel::<(usize, usize)>();
let (result, mut result_recv) = hydroflow::util::unbounded_channel::<(usize, usize)>();

let mut flow = datalog!(
r#"
.input ints `source_stream(ints)`
.output result `for_each(|v| result.send(v).unwrap())`
result(a % 2, sum(b)) :- ints(a, b)
"#
);

ints_send.send((1, 1)).unwrap();
ints_send.send((2, 1)).unwrap();
ints_send.send((3, 1)).unwrap();

flow.run_tick();

let mut res = collect_ready::<Vec<_>, _>(&mut result_recv);
res.sort_by_key(|v| v.0);
assert_eq!(&res, &[(0, 1), (1, 2)]);
}

#[multiplatform_test]
fn test_choose_strings() {
let (strings_send, strings) = hydroflow::util::unbounded_channel::<(String,)>();
Expand Down Expand Up @@ -870,6 +895,7 @@ fn test_expr_lhs() {
result(a + a) :- ints(a)
result(123 - a) :- ints(a)
result(123 % (a + 5)) :- ints(a)
result(a * 5) :- ints(a)
"#
);

Expand All @@ -879,7 +905,7 @@ fn test_expr_lhs() {

assert_eq!(
&*collect_ready::<Vec<_>, _>(&mut result_recv),
&[(123,), (124,), (2,), (122,), (3,)]
&[(123,), (124,), (2,), (122,), (3,), (5,)]
);
}

Expand Down
11 changes: 11 additions & 0 deletions hydroflow_datalog_core/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ pub mod datalog {
#[rust_sitter::leaf(text = "-")] (),
Box<IntExpr>,
),
#[rust_sitter::prec_left(2)]
Mul(
Box<IntExpr>,
#[rust_sitter::leaf(text = "*")] (),
Box<IntExpr>,
),
#[rust_sitter::prec_left(1)]
Mod(
Box<IntExpr>,
Expand All @@ -279,6 +285,11 @@ pub mod datalog {
idents.extend(r.idents());
idents
}
IntExpr::Mul(l, _, r) => {
let mut idents = l.idents();
idents.extend(r.idents());
idents
}
IntExpr::Mod(l, _, r) => {
let mut idents = l.idents();
idents.extend(r.idents());
Expand Down
18 changes: 18 additions & 0 deletions hydroflow_datalog_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,11 @@ pub(crate) fn gen_value_expr(
let r = gen_value_expr(r, lookup_ident, get_span);
parse_quote!(#l - #r)
}
IntExpr::Mul(l, _, r) => {
let l = gen_value_expr(l, lookup_ident, get_span);
let r = gen_value_expr(r, lookup_ident, get_span);
parse_quote!(#l * #r)
}
IntExpr::Mod(l, _, r) => {
let l = gen_value_expr(l, lookup_ident, get_span);
let r = gen_value_expr(r, lookup_ident, get_span);
Expand Down Expand Up @@ -963,6 +968,18 @@ mod tests {
);
}

#[test]
fn test_aggregations_group_by_expr() {
test_snapshots!(
r#"
.input ints `source_stream(ints)`
.output result `for_each(|v| result.send(v).unwrap())`
result(a % 2, sum(b)) :- ints(a, b)
"#
);
}

#[test]
fn test_non_copy_but_clone() {
test_snapshots!(
Expand All @@ -987,6 +1004,7 @@ mod tests {
result(a + a) :- ints(a)
result(123 - a) :- ints(a)
result(123 % (a + 5)) :- ints(a)
result(a * 5) :- ints(a)
"#
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
---
source: hydroflow_datalog_core/src/lib.rs
expression: "prettyplease::unparse(&wrapped)"
---
fn main() {
{
use hydroflow::{var_expr, var_args};
let mut df = hydroflow::scheduled::graph::Hydroflow::new();
df.__assign_meta_graph(
"{\"nodes\":[{\"value\":null,\"version\":0},{\"value\":null,\"version\":2},{\"value\":{\"Operator\":\"unique :: < 'tick > ()\"},\"version\":1},{\"value\":null,\"version\":2},{\"value\":null,\"version\":2},{\"value\":{\"Operator\":\"unique :: < 'tick > ()\"},\"version\":1},{\"value\":{\"Handoff\":{}},\"version\":3},{\"value\":{\"Operator\":\"source_stream (ints)\"},\"version\":1},{\"value\":{\"Operator\":\"for_each (| v | result . send (v) . unwrap ())\"},\"version\":1},{\"value\":{\"Operator\":\"map (| row : (_ , _ ,) | ((row . 0 % 2 ,) , (row . 1 ,)))\"},\"version\":1},{\"value\":{\"Operator\":\"group_by :: < 'tick , (_ ,) , (Option < _ > ,) > (| | (None ,) , | old : & mut (Option < _ > ,) , val : (_ ,) | { old . 0 = if let Some (prev) = old . 0 . take () { Some (prev + val . 0) } else { Some (val . 0) } ; })\"},\"version\":1},{\"value\":{\"Operator\":\"map (| (g , a) | (g . 0 , a . 0 . unwrap () ,))\"},\"version\":1}],\"graph\":[{\"value\":null,\"version\":0},{\"value\":[{\"idx\":7,\"version\":1},{\"idx\":2,\"version\":1}],\"version\":3},{\"value\":null,\"version\":2},{\"value\":[{\"idx\":11,\"version\":1},{\"idx\":5,\"version\":1}],\"version\":3},{\"value\":[{\"idx\":6,\"version\":3},{\"idx\":10,\"version\":1}],\"version\":3},{\"value\":null,\"version\":2},{\"value\":[{\"idx\":5,\"version\":1},{\"idx\":8,\"version\":1}],\"version\":3},{\"value\":null,\"version\":2},{\"value\":[{\"idx\":10,\"version\":1},{\"idx\":11,\"version\":1}],\"version\":1},{\"value\":[{\"idx\":9,\"version\":1},{\"idx\":6,\"version\":3}],\"version\":3},{\"value\":[{\"idx\":2,\"version\":1},{\"idx\":9,\"version\":1}],\"version\":3}],\"ports\":[{\"value\":null,\"version\":0},{\"value\":[\"Elided\",\"Elided\"],\"version\":3},{\"value\":null,\"version\":0},{\"value\":[\"Elided\",\"Elided\"],\"version\":3},{\"value\":[\"Elided\",\"Elided\"],\"version\":3},{\"value\":null,\"version\":0},{\"value\":[\"Elided\",\"Elided\"],\"version\":3},{\"value\":null,\"version\":0},{\"value\":[\"Elided\",\"Elided\"],\"version\":1},{\"value\":[\"Elided\",\"Elided\"],\"version\":3},{\"value\":[\"Elided\",\"Elided\"],\"version\":3}],\"node_subgraph\":[{\"value\":null,\"version\":0},{\"value\":null,\"version\":0},{\"value\":{\"idx\":2,\"version\":1},\"version\":1},{\"value\":null,\"version\":0},{\"value\":null,\"version\":0},{\"value\":{\"idx\":1,\"version\":1},\"version\":1},{\"value\":null,\"version\":0},{\"value\":{\"idx\":2,\"version\":1},\"version\":1},{\"value\":{\"idx\":1,\"version\":1},\"version\":1},{\"value\":{\"idx\":2,\"version\":1},\"version\":1},{\"value\":{\"idx\":1,\"version\":1},\"version\":1},{\"value\":{\"idx\":1,\"version\":1},\"version\":1}],\"subgraph_nodes\":[{\"value\":null,\"version\":0},{\"value\":[{\"idx\":10,\"version\":1},{\"idx\":11,\"version\":1},{\"idx\":5,\"version\":1},{\"idx\":8,\"version\":1}],\"version\":1},{\"value\":[{\"idx\":7,\"version\":1},{\"idx\":2,\"version\":1},{\"idx\":9,\"version\":1}],\"version\":1}],\"subgraph_stratum\":[{\"value\":null,\"version\":0},{\"value\":1,\"version\":1},{\"value\":0,\"version\":1}],\"node_varnames\":[{\"value\":null,\"version\":0},{\"value\":null,\"version\":0},{\"value\":\"ints_insert\",\"version\":1},{\"value\":null,\"version\":0},{\"value\":null,\"version\":0},{\"value\":\"result_insert\",\"version\":1}]}",
);
df.__assign_diagnostics("[]");
let (hoff_6v3_send, hoff_6v3_recv) = df
.make_edge::<
_,
hydroflow::scheduled::handoff::VecHandoff<_>,
>("handoff GraphNodeId(6v3)");
let mut sg_2v1_node_7v1_stream = {
#[inline(always)]
fn check_stream<
Stream: hydroflow::futures::stream::Stream<Item = Item>,
Item,
>(
stream: Stream,
) -> ::std::pin::Pin<
::std::boxed::Box<impl hydroflow::futures::stream::Stream<Item = Item>>,
> {
::std::boxed::Box::pin(stream)
}
check_stream(ints)
};
let sg_2v1_node_2v1_uniquedata = df
.add_state(
::std::cell::RefCell::new(
hydroflow::lang::monotonic_map::MonotonicMap::<
_,
hydroflow::rustc_hash::FxHashSet<_>,
>::default(),
),
);
df.add_subgraph_stratified(
"Subgraph GraphSubgraphId(2v1)",
0,
var_expr!(),
var_expr!(hoff_6v3_send),
move |context, var_args!(), var_args!(hoff_6v3_send)| {
let hoff_6v3_send = hydroflow::pusherator::for_each::ForEach::new(|v| {
hoff_6v3_send.give(Some(v));
});
let op_7v1 = std::iter::from_fn(|| {
match hydroflow::futures::stream::Stream::poll_next(
sg_2v1_node_7v1_stream.as_mut(),
&mut std::task::Context::from_waker(&context.waker()),
) {
std::task::Poll::Ready(maybe) => maybe,
std::task::Poll::Pending => None,
}
});
let op_7v1 = {
#[inline(always)]
pub fn check_op_7v1<Input: ::std::iter::Iterator<Item = Item>, Item>(
input: Input,
) -> impl ::std::iter::Iterator<Item = Item> {
input
}
check_op_7v1(op_7v1)
};
let op_2v1 = op_7v1
.filter(|item| {
let mut borrow = context
.state_ref(sg_2v1_node_2v1_uniquedata)
.borrow_mut();
let set = borrow
.try_insert_with(
(context.current_tick(), context.current_stratum()),
hydroflow::rustc_hash::FxHashSet::default,
);
if !set.contains(item) {
set.insert(::std::clone::Clone::clone(item));
true
} else {
false
}
});
let op_2v1 = {
#[inline(always)]
pub fn check_op_2v1<Input: ::std::iter::Iterator<Item = Item>, Item>(
input: Input,
) -> impl ::std::iter::Iterator<Item = Item> {
input
}
check_op_2v1(op_2v1)
};
let op_9v1 = op_2v1.map(|row: (_, _)| ((row.0 % 2,), (row.1,)));
let op_9v1 = {
#[inline(always)]
pub fn check_op_9v1<Input: ::std::iter::Iterator<Item = Item>, Item>(
input: Input,
) -> impl ::std::iter::Iterator<Item = Item> {
input
}
check_op_9v1(op_9v1)
};
#[inline(always)]
fn check_pivot_run<
Pull: ::std::iter::Iterator<Item = Item>,
Push: hydroflow::pusherator::Pusherator<Item = Item>,
Item,
>(pull: Pull, push: Push) {
hydroflow::pusherator::pivot::Pivot::new(pull, push).run();
}
check_pivot_run(op_9v1, hoff_6v3_send);
},
);
let sg_1v1_node_5v1_uniquedata = df
.add_state(
::std::cell::RefCell::new(
hydroflow::lang::monotonic_map::MonotonicMap::<
_,
hydroflow::rustc_hash::FxHashSet<_>,
>::default(),
),
);
df.add_subgraph_stratified(
"Subgraph GraphSubgraphId(1v1)",
1,
var_expr!(hoff_6v3_recv),
var_expr!(),
move |context, var_args!(hoff_6v3_recv), var_args!()| {
let mut hoff_6v3_recv = hoff_6v3_recv.borrow_mut_swap();
let hoff_6v3_recv = hoff_6v3_recv.drain(..);
let op_10v1 = {
#[inline(always)]
fn check_input<Iter: ::std::iter::Iterator<Item = (A, B)>, A, B>(
iter: Iter,
) -> impl ::std::iter::Iterator<Item = (A, B)> {
iter
}
check_input(hoff_6v3_recv)
.fold(
hydroflow::rustc_hash::FxHashMap::<
(_,),
(Option<_>,),
>::default(),
|mut ht, kv| {
let entry = ht.entry(kv.0).or_insert_with(|| (None,));
#[allow(clippy::redundant_closure_call)]
(|old: &mut (Option<_>,), val: (_,)| {
old
.0 = if let Some(prev) = old.0.take() {
Some(prev + val.0)
} else {
Some(val.0)
};
})(entry, kv.1);
ht
},
)
.into_iter()
};
let op_10v1 = {
#[inline(always)]
pub fn check_op_10v1<
Input: ::std::iter::Iterator<Item = Item>,
Item,
>(input: Input) -> impl ::std::iter::Iterator<Item = Item> {
input
}
check_op_10v1(op_10v1)
};
let op_11v1 = op_10v1.map(|(g, a)| (g.0, a.0.unwrap()));
let op_11v1 = {
#[inline(always)]
pub fn check_op_11v1<
Input: ::std::iter::Iterator<Item = Item>,
Item,
>(input: Input) -> impl ::std::iter::Iterator<Item = Item> {
input
}
check_op_11v1(op_11v1)
};
let op_5v1 = op_11v1
.filter(|item| {
let mut borrow = context
.state_ref(sg_1v1_node_5v1_uniquedata)
.borrow_mut();
let set = borrow
.try_insert_with(
(context.current_tick(), context.current_stratum()),
hydroflow::rustc_hash::FxHashSet::default,
);
if !set.contains(item) {
set.insert(::std::clone::Clone::clone(item));
true
} else {
false
}
});
let op_5v1 = {
#[inline(always)]
pub fn check_op_5v1<Input: ::std::iter::Iterator<Item = Item>, Item>(
input: Input,
) -> impl ::std::iter::Iterator<Item = Item> {
input
}
check_op_5v1(op_5v1)
};
let op_8v1 = hydroflow::pusherator::for_each::ForEach::new(|v| {
result.send(v).unwrap()
});
let op_8v1 = {
#[inline(always)]
pub fn check_op_8v1<
Input: hydroflow::pusherator::Pusherator<Item = Item>,
Item,
>(
input: Input,
) -> impl hydroflow::pusherator::Pusherator<Item = Item> {
input
}
check_op_8v1(op_8v1)
};
#[inline(always)]
fn check_pivot_run<
Pull: ::std::iter::Iterator<Item = Item>,
Push: hydroflow::pusherator::Pusherator<Item = Item>,
Item,
>(pull: Pull, push: Push) {
hydroflow::pusherator::pivot::Pivot::new(pull, push).run();
}
check_pivot_run(op_5v1, op_8v1);
},
);
df
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
source: hydroflow_datalog_core/src/lib.rs
expression: flat_graph_ref.surface_syntax_string()
---
2v1 = unique :: < 'tick > ();
5v1 = unique :: < 'tick > ();
7v1 = source_stream (ints);
8v1 = for_each (| v | result . send (v) . unwrap ());
9v1 = map (| row : (_ , _ ,) | ((row . 0 % 2 ,) , (row . 1 ,)));
10v1 = group_by :: < 'tick , (_ ,) , (Option < _ > ,) > (| | (None ,) , | old : & mut (Option < _ > ,) , val : (_ ,) | { old . 0 = if let Some (prev) = old . 0 . take () { Some (prev + val . 0) } else { Some (val . 0) } ; });
11v1 = map (| (g , a) | (g . 0 , a . 0 . unwrap () ,));

7v1 -> 2v1;
11v1 -> 5v1;
5v1 -> 8v1;
10v1 -> 11v1;
9v1 -> 10v1;
2v1 -> 9v1;

Loading

0 comments on commit b3e790c

Please sign in to comment.