1
1
#![ cfg( test) ]
2
2
3
- use crate :: Relation ;
4
3
use crate :: Iteration ;
4
+ use crate :: Relation ;
5
5
use crate :: RelationLeaper ;
6
6
use proptest:: prelude:: * ;
7
7
use proptest:: { proptest, proptest_helper} ;
8
8
9
9
fn inputs ( ) -> impl Strategy < Value = Vec < ( u32 , u32 ) > > {
10
- prop:: collection:: vec ( ( 0_u32 ..100 , 0_u32 ..100 ) , 1 ..100 )
10
+ prop:: collection:: vec ( ( 0_u32 ..100 , 0_u32 ..100 ) , 1 ..500 )
11
11
}
12
12
13
- fn reachable_with_join ( edges : & [ ( u32 , u32 ) ] ) -> Relation < ( u32 , u32 ) > {
13
+ /// The original way to use datafrog -- computes reachable nodes from a set of edges
14
+ fn reachable_with_var_join ( edges : & [ ( u32 , u32 ) ] ) -> Relation < ( u32 , u32 ) > {
14
15
let edges = Relation :: from ( edges. iter ( ) . cloned ( ) ) ;
15
16
let mut iteration = Iteration :: new ( ) ;
16
17
@@ -28,6 +29,25 @@ fn reachable_with_join(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
28
29
reachable. complete ( )
29
30
}
30
31
32
+ /// Like `reachable`, but using a relation as an input to `from_join`
33
+ fn reachable_with_relation_join ( edges : & [ ( u32 , u32 ) ] ) -> Relation < ( u32 , u32 ) > {
34
+ let edges = Relation :: from ( edges. iter ( ) . cloned ( ) ) ;
35
+ let mut iteration = Iteration :: new ( ) ;
36
+
37
+ // NB. Changed from `reachable_with_var_join`:
38
+ let edges_by_successor = Relation :: from ( edges. iter ( ) . map ( |& ( n1, n2) | ( n2, n1) ) ) ;
39
+
40
+ let reachable = iteration. variable :: < ( u32 , u32 ) > ( "reachable" ) ;
41
+ reachable. insert ( edges) ;
42
+
43
+ while iteration. changed ( ) {
44
+ // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
45
+ reachable. from_join ( & reachable, & edges_by_successor, |& _, & n3, & n1| ( n1, n3) ) ;
46
+ }
47
+
48
+ reachable. complete ( )
49
+ }
50
+
31
51
fn reachable_with_leapfrog ( edges : & [ ( u32 , u32 ) ] ) -> Relation < ( u32 , u32 ) > {
32
52
let edges = Relation :: from ( edges. iter ( ) . cloned ( ) ) ;
33
53
let mut iteration = Iteration :: new ( ) ;
@@ -41,21 +61,68 @@ fn reachable_with_leapfrog(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
41
61
// reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
42
62
reachable. from_leapjoin (
43
63
& reachable,
44
- & mut [
45
- & mut edges_by_successor. extend_with ( |& ( n2, _) | n2) ,
46
- ] ,
64
+ & mut [ & mut edges_by_successor. extend_with ( |& ( n2, _) | n2) ] ,
47
65
|& ( _, n3) , & n1| ( n1, n3) ,
48
66
) ;
49
67
}
50
68
51
69
reachable. complete ( )
52
70
}
53
71
72
+ /// Computes a join where the values are summed -- uses iteration
73
+ /// variables (the original datafrog technique).
74
+ fn sum_join_via_var (
75
+ input1_slice : & [ ( u32 , u32 ) ] ,
76
+ input2_slice : & [ ( u32 , u32 ) ] ,
77
+ ) -> Relation < ( u32 , u32 ) > {
78
+ let mut iteration = Iteration :: new ( ) ;
79
+
80
+ let input1 = iteration. variable :: < ( u32 , u32 ) > ( "input1" ) ;
81
+ input1. insert ( Relation :: from ( input1_slice. iter ( ) . cloned ( ) ) ) ;
82
+
83
+ let input2 = iteration. variable :: < ( u32 , u32 ) > ( "input1" ) ;
84
+ input2. insert ( Relation :: from ( input2_slice. iter ( ) . cloned ( ) ) ) ;
85
+
86
+ let output = iteration. variable :: < ( u32 , u32 ) > ( "output" ) ;
87
+
88
+ while iteration. changed ( ) {
89
+ // output(K1, V1 * 100 + V2) :- input1(K1, V1), input2(K1, V2).
90
+ output. from_join ( & input1, & input2, |& k1, & v1, & v2| ( k1, v1 * 100 + v2) ) ;
91
+ }
92
+
93
+ output. complete ( )
94
+ }
95
+
96
+ /// Computes a join where the values are summed -- uses iteration
97
+ /// variables (the original datafrog technique).
98
+ fn sum_join_via_relation (
99
+ input1_slice : & [ ( u32 , u32 ) ] ,
100
+ input2_slice : & [ ( u32 , u32 ) ] ,
101
+ ) -> Relation < ( u32 , u32 ) > {
102
+ let input1 = Relation :: from ( input1_slice. iter ( ) . cloned ( ) ) ;
103
+ let input2 = Relation :: from ( input2_slice. iter ( ) . cloned ( ) ) ;
104
+ Relation :: from_join ( & input1, & input2, |& k1, & v1, & v2| ( k1, v1 * 100 + v2) )
105
+ }
106
+
54
107
proptest ! {
55
108
#[ test]
56
- fn reachable ( edges in inputs( ) ) {
57
- let reachable1 = reachable_with_join ( & edges) ;
109
+ fn reachable_leapfrog_vs_var_join ( edges in inputs( ) ) {
110
+ let reachable1 = reachable_with_var_join ( & edges) ;
58
111
let reachable2 = reachable_with_leapfrog( & edges) ;
59
112
assert_eq!( reachable1. elements, reachable2. elements) ;
60
113
}
114
+
115
+ #[ test]
116
+ fn reachable_rel_join_vs_var_join( edges in inputs( ) ) {
117
+ let reachable1 = reachable_with_var_join( & edges) ;
118
+ let reachable2 = reachable_with_relation_join( & edges) ;
119
+ assert_eq!( reachable1. elements, reachable2. elements) ;
120
+ }
121
+
122
+ #[ test]
123
+ fn sum_join_from_var_vs_rel( ( set1, set2) in ( inputs( ) , inputs( ) ) ) {
124
+ let output1 = sum_join_via_var( & set1, & set2) ;
125
+ let output2 = sum_join_via_relation( & set1, & set2) ;
126
+ assert_eq!( output1. elements, output2. elements) ;
127
+ }
61
128
}
0 commit comments