Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unleash the treefrog #11

Merged
merged 11 commits into from
Dec 5, 2018
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
language: rust
before_script:
- rustup component add rustfmt-preview
rust:
- beta
- nightly
matrix:
- fast_finish: true
- allow_failures:
- nightly
script:
- cargo build
- cargo fmt --all -- --check
- cargo test --all
39 changes: 17 additions & 22 deletions src/bin/borrow_check.rs → examples/borrow_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ type Borrow = u32;
type Point = u32;

fn main() {

let subset = {

// Create a new iteration context, ...
let mut iteration1 = Iteration::new();

Expand All @@ -34,37 +32,36 @@ fn main() {

// .. and then start iterating rules!
while iteration1.changed() {

// remap fields to re-index by keys.
subset_r1p.from_map(&subset, |&(r1,r2,p)| ((r1,p),r2));
subset_r2p.from_map(&subset, |&(r1,r2,p)| ((r2,p),r1));
subset_p.from_map(&subset, |&(r1,r2,p)| (p,(r1,r2)));
subset_r1p.from_map(&subset, |&(r1, r2, p)| ((r1, p), r2));
subset_r2p.from_map(&subset, |&(r1, r2, p)| ((r2, p), r1));
subset_p.from_map(&subset, |&(r1, r2, p)| (p, (r1, r2)));

// R0: subset(R1, R2, P) :- outlives(R1, R2, P).
// Already loaded; outlives is static.

// R1: subset(R1, R3, P) :-
// subset(R1, R2, P),
// subset(R2, R3, P).
subset.from_join(&subset_r2p, &subset_r1p, |&(_r2,p),&r1,&r3| (r1,r3,p));
subset.from_join(&subset_r2p, &subset_r1p, |&(_r2, p), &r1, &r3| (r1, r3, p));

// R2: subset(R1, R2, Q) :-
// subset(R1, R2, P),
// cfg_edge(P, Q),
// region_live_at(R1, Q),
// region_live_at(R2, Q).

subset_1.from_join(&subset_p, &cfg_edge_p, |&_p, &(r1,r2), &q| ((r1,q),r2));
subset_2.from_join(&subset_1, &region_live_at, |&(r1,q),&r2,&()| ((r2,q),r1));
subset.from_join(&subset_2, &region_live_at, |&(r2,q),&r1,&()| (r1,r2,q));

subset_1.from_join(&subset_p, &cfg_edge_p, |&_p, &(r1, r2), &q| ((r1, q), r2));
subset_2.from_join(&subset_1, &region_live_at, |&(r1, q), &r2, &()| {
((r2, q), r1)
});
subset.from_join(&subset_2, &region_live_at, |&(r2, q), &r1, &()| (r1, r2, q));
}

subset_r1p.complete()
};

let requires = {

// Create a new iteration context, ...
let mut iteration2 = Iteration::new();

Expand All @@ -87,9 +84,8 @@ fn main() {

// .. and then start iterating rules!
while iteration2.changed() {

requires_rp.from_map(&requires, |&(r,b,p)| ((r,p),b));
requires_bp.from_map(&requires, |&(r,b,p)| ((b,p),r));
requires_rp.from_map(&requires, |&(r, b, p)| ((r, p), b));
requires_bp.from_map(&requires, |&(r, b, p)| ((b, p), r));

// requires(R, B, P) :- borrow_region(R, B, P).
// Already loaded; borrow_region is static.
Expand All @@ -105,16 +101,15 @@ fn main() {
// cfg_edge(P, Q),
// (region_live_at(R, Q); universal_region(R)).

requires_1.from_antijoin(&requires_bp, &killed, |&(b,p),&r| (p,(b,r)));
requires_2.from_join(&requires_1, &cfg_edge_p, |&_p, &(b,r), &q| ((r,q),b));
requires.from_join(&requires_2, &region_live_at, |&(r,q),&b,&()| (r,b,q));
requires_1.from_antijoin(&requires_bp, &killed, |&(b, p), &r| (p, (b, r)));
requires_2.from_join(&requires_1, &cfg_edge_p, |&_p, &(b, r), &q| ((r, q), b));
requires.from_join(&requires_2, &region_live_at, |&(r, q), &b, &()| (r, b, q));
}

requires.complete()
};

// borrow_live_at(B, P) :- requires(R, B, P), region_live_at(R, P)

// borrow_live_at(B, P) :- requires(R, B, P), universal_region(R).
// borrow_live_at(B, P) :- requires(R, B, P), region_live_at(R, P)

}
// borrow_live_at(B, P) :- requires(R, B, P), universal_region(R).
}
26 changes: 16 additions & 10 deletions src/bin/graspan1.rs → examples/graspan1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ extern crate datafrog;
use datafrog::Iteration;

fn main() {

let timer = ::std::time::Instant::now();

// Make space for input data.
let mut nodes = Vec::new();
let mut edges = Vec::new();

// Read input data from a handy file.
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::io::{BufRead, BufReader};

let filename = std::env::args().nth(1).unwrap();
let file = BufReader::new(File::open(filename).unwrap());
Expand All @@ -23,9 +22,13 @@ fn main() {
let dst: u32 = elts.next().unwrap().parse().expect("malformed dst");
let typ: &str = elts.next().unwrap();
match typ {
"n" => { nodes.push((dst, src)); },
"e" => { edges.push((src, dst)); },
unk => { panic!("unknown type: {}", unk)},
"n" => {
nodes.push((dst, src));
}
"e" => {
edges.push((src, dst));
}
unk => panic!("unknown type: {}", unk),
}
}
}
Expand All @@ -36,8 +39,8 @@ fn main() {
let mut iteration = Iteration::new();

// .. some variables, ..
let variable1 = iteration.variable::<(u32,u32)>("nodes");
let variable2 = iteration.variable::<(u32,u32)>("edges");
let variable1 = iteration.variable::<(u32, u32)>("nodes");
let variable2 = iteration.variable::<(u32, u32)>("edges");

// .. load them with some initial values, ..
variable1.insert(nodes.into());
Expand All @@ -46,11 +49,14 @@ fn main() {
// .. and then start iterating rules!
while iteration.changed() {
// N(a,c) <- N(a,b), E(b,c)
variable1.from_join(&variable1, &variable2, |_b, &a, &c| (c,a));
variable1.from_join(&variable1, &variable2, |_b, &a, &c| (c, a));
}

let reachable = variable1.complete();

println!("{:?}\tComputation complete (nodes_final: {})", timer.elapsed(), reachable.len());

println!(
"{:?}\tComputation complete (nodes_final: {})",
timer.elapsed(),
reachable.len()
);
}
45 changes: 25 additions & 20 deletions src/join.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
//! Join functionality.

use super::{Variable, Relation};
use super::{Relation, Variable};

pub fn join_into<Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
input1: &Variable<(Key, Val1)>,
input2: &Variable<(Key, Val2)>,
output: &Variable<Result>,
mut logic: impl FnMut(&Key, &Val1, &Val2)->Result) {

mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result,
) {
let mut results = Vec::new();

let recent1 = input1.recent.borrow();
let recent2 = input2.recent.borrow();

{ // scoped to let `closure` drop borrow of `results`.
{
// scoped to let `closure` drop borrow of `results`.

let mut closure = |k: &Key, v1: &Val1, v2: &Val2| results.push(logic(k,v1,v2));
let mut closure = |k: &Key, v1: &Val1, v2: &Val2| results.push(logic(k, v1, v2));

for batch2 in input2.stable.borrow().iter() {
join_helper(&recent1, &batch2, &mut closure);
Expand All @@ -36,40 +37,44 @@ pub fn antijoin_into<Key: Ord, Val: Ord, Result: Ord>(
input1: &Variable<(Key, Val)>,
input2: &Relation<Key>,
output: &Variable<Result>,
mut logic: impl FnMut(&Key, &Val)->Result) {

mut logic: impl FnMut(&Key, &Val) -> Result,
) {
let mut tuples2 = &input2[..];

let results = input1.recent.borrow().iter().filter(|(ref key, _)| {
tuples2 = gallop(tuples2, |k| k < key);
tuples2.first() != Some(key)
}).map(|(ref key, ref val)| logic(key, val)).collect::<Vec<_>>();
let results = input1
.recent
.borrow()
.iter()
.filter(|(ref key, _)| {
tuples2 = gallop(tuples2, |k| k < key);
tuples2.first() != Some(key)
})
.map(|(ref key, ref val)| logic(key, val))
.collect::<Vec<_>>();

output.insert(Relation::from_vec(results));
}

fn join_helper<K: Ord, V1, V2>(
mut slice1: &[(K,V1)],
mut slice2: &[(K,V2)],
mut result: impl FnMut(&K,&V1,&V2)) {

mut slice1: &[(K, V1)],
mut slice2: &[(K, V2)],
mut result: impl FnMut(&K, &V1, &V2),
) {
while !slice1.is_empty() && !slice2.is_empty() {

use std::cmp::Ordering;

// If the keys match produce tuples, else advance the smaller key until they might.
match slice1[0].0.cmp(&slice2[0].0) {
Ordering::Less => {
slice1 = gallop(slice1, |x| x.0 < slice2[0].0);
},
}
Ordering::Equal => {

// Determine the number of matching keys in each slice.
let count1 = slice1.iter().take_while(|x| x.0 == slice1[0].0).count();
let count2 = slice2.iter().take_while(|x| x.0 == slice2[0].0).count();

// Produce results from the cross-product of matches.
for index1 in 0 .. count1 {
for index1 in 0..count1 {
for s2 in slice2[..count2].iter() {
result(&slice1[0].0, &slice1[index1].1, &s2.1);
}
Expand All @@ -86,7 +91,7 @@ fn join_helper<K: Ord, V1, V2>(
}
}

pub fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T)->bool) -> &[T] {
pub fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] {
// if empty slice, or already >= element, return
if !slice.is_empty() && cmp(&slice[0]) {
let mut step = 1;
Expand Down
Loading