souffle  2.0.2-371-g6315b36
ram_statement_equal_clone_test.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2020, The Souffle Developers. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file ram_statement_equal_clone_test.cpp
12  *
13  * Tests equal and clone function of Statement classes.
14  *
15  ***********************************************************************/
16 
17 #include "tests/test.h"
18 
19 #include "FunctorOps.h"
20 #include "RelationTag.h"
21 #include "ram/Break.h"
22 #include "ram/Clear.h"
23 #include "ram/Condition.h"
24 #include "ram/Constraint.h"
25 #include "ram/DebugInfo.h"
26 #include "ram/EmptinessCheck.h"
27 #include "ram/ExistenceCheck.h"
28 #include "ram/Exit.h"
29 #include "ram/Expression.h"
30 #include "ram/Extend.h"
31 #include "ram/Filter.h"
32 #include "ram/IO.h"
33 #include "ram/IntrinsicOperator.h"
34 #include "ram/LogRelationTimer.h"
35 #include "ram/LogSize.h"
36 #include "ram/LogTimer.h"
37 #include "ram/Loop.h"
38 #include "ram/Negation.h"
39 #include "ram/Operation.h"
40 #include "ram/Parallel.h"
41 #include "ram/ParallelChoice.h"
42 #include "ram/Project.h"
43 #include "ram/Query.h"
44 #include "ram/Relation.h"
45 #include "ram/Scan.h"
46 #include "ram/Sequence.h"
47 #include "ram/SignedConstant.h"
48 #include "ram/Statement.h"
49 #include "ram/SubroutineReturn.h"
50 #include "ram/Swap.h"
51 #include "ram/TupleElement.h"
52 #include "ram/UndefValue.h"
54 #include <algorithm>
55 #include <map>
56 #include <memory>
57 #include <string>
58 #include <utility>
59 #include <vector>
60 
61 namespace souffle::ram {
62 
63 namespace test {
64 
65 TEST(IO1, CloneAndEquals) {
66  // IO A ()
67  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
68  std::map<std::string, std::string> ioEmptyA;
69  std::map<std::string, std::string> ioEmptyB;
70  IO a("A", std::move(ioEmptyA));
71  IO b("A", std::move(ioEmptyB));
72  EXPECT_EQ(a, b);
73  EXPECT_NE(&a, &b);
74 
75  IO* c = a.clone();
76  EXPECT_EQ(a, *c);
77  EXPECT_NE(&a, c);
78  delete c;
79 }
80 
81 TEST(Clear, CloneAndEquals) {
82  // CLEAR A
83  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
84  Clear a("A");
85  Clear b("A");
86  EXPECT_EQ(a, b);
87  EXPECT_NE(&a, &b);
88 
89  Clear* c = a.clone();
90  EXPECT_EQ(a, *c);
91  EXPECT_NE(&a, c);
92  delete c;
93 }
94 
95 TEST(Extend, CloneAndEquals) {
96  // MERGE B WITH A
97  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
98  Relation B("B", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
99  Extend a("B", "A");
100  Extend b("B", "A");
101  EXPECT_EQ(a, b);
102  EXPECT_NE(&a, &b);
103 
104  Extend* c = a.clone();
105  EXPECT_EQ(a, *c);
106  EXPECT_NE(&a, c);
107  delete c;
108 }
109 
110 TEST(Swap, CloneAndEquals) {
111  // SWAP(A,B)
112  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
113  Relation B("B", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
114  Swap a("A", "B");
115  Swap b("A", "B");
116  EXPECT_EQ(a, b);
117  EXPECT_NE(&a, &b);
118 
119  Swap* c = a.clone();
120  EXPECT_EQ(a, *c);
121  EXPECT_NE(&a, c);
122  delete c;
123 }
124 
125 TEST(Query, CloneAndEquals) {
126  Relation A("A", 3, 1, {"a", "b", "c"}, {"i", "s", "i"}, RelationRepresentation::DEFAULT);
127  Relation B("B", 2, 1, {"a", "c"}, {"i", "i"}, RelationRepresentation::DEFAULT);
128  /*
129  * QUERY
130  * FOR t0 IN A
131  * PROJECT (t0.0, t0.2) INTO B
132  */
133  VecOwn<Expression> a_expressions;
134  a_expressions.emplace_back(new TupleElement(0, 0));
135  a_expressions.emplace_back(new TupleElement(0, 2));
136  auto a_project = mk<Project>("B", std::move(a_expressions));
137  auto a_scan = mk<Scan>("A", 0, std::move(a_project), "");
138 
139  VecOwn<Expression> b_expressions;
140  b_expressions.emplace_back(new TupleElement(0, 0));
141  b_expressions.emplace_back(new TupleElement(0, 2));
142  auto b_project = mk<Project>("B", std::move(b_expressions));
143  auto b_scan = mk<Scan>("A", 0, std::move(b_project), "");
144 
145  Query a(std::move(a_scan));
146  Query b(std::move(b_scan));
147  EXPECT_EQ(a, b);
148  EXPECT_NE(&a, &b);
149 
150  Query* c = a.clone();
151  EXPECT_EQ(a, *c);
152  EXPECT_NE(&a, c);
153  delete c;
154 
155  /*
156  * QUERY
157  * PARALLEL CHOICE t1 IN A WHERE (t1.0 = 0)
158  * RETURN (t1.2)
159  */
160  VecOwn<Expression> d_return_value;
161  d_return_value.emplace_back(new TupleElement(1, 0));
162  auto d_return = mk<SubroutineReturn>(std::move(d_return_value));
163  // condition t1.0 = 0
164  auto d_cond = mk<Constraint>(BinaryConstraintOp::EQ, mk<TupleElement>(1, 0), mk<SignedConstant>(0));
165  auto d_parallel_choice = mk<ParallelChoice>("A", 1, std::move(d_cond), std::move(d_return), "");
166 
167  VecOwn<Expression> e_return_value;
168  e_return_value.emplace_back(new TupleElement(1, 0));
169  auto e_return = mk<SubroutineReturn>(std::move(e_return_value));
170  // condition t1.0 = 0
171  auto e_cond = mk<Constraint>(BinaryConstraintOp::EQ, mk<TupleElement>(1, 0), mk<SignedConstant>(0));
172  auto e_parallel_choice = mk<ParallelChoice>("A", 1, std::move(e_cond), std::move(e_return), "");
173  Query d(std::move(d_parallel_choice));
174  Query e(std::move(e_parallel_choice));
175  EXPECT_EQ(d, e);
176  EXPECT_NE(&d, &e);
177 
178  Query* f = d.clone();
179  EXPECT_EQ(d, *f);
180  EXPECT_NE(&d, f);
181  delete f;
182 }
183 
184 TEST(Sequence, CloneAndEquals) {
185  // no statements in the sequence
186  Sequence a;
187  Sequence b;
188  EXPECT_EQ(a, b);
189  EXPECT_NE(&a, &b);
190 
191  Sequence* c = a.clone();
192  EXPECT_EQ(a, *c);
193  EXPECT_NE(&a, c);
194  delete c;
195 
196  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
197  // one statement in the sequence
198  // CLEAR A
199  Sequence d(mk<Clear>("A"));
200  Sequence e(mk<Clear>("A"));
201  EXPECT_EQ(d, e);
202  EXPECT_NE(&d, &e);
203 
204  Sequence* f = d.clone();
205  EXPECT_EQ(d, *f);
206  EXPECT_NE(&d, f);
207  delete f;
208 
209  // multiple statements in the sequence
210  // IO A ()
211  // CLEAR A
212  std::map<std::string, std::string> g_load_IODir;
213  std::map<std::string, std::string> h_load_IODir;
214  Sequence g(mk<IO>("A", std::move(g_load_IODir)), mk<Clear>("A"));
215  Sequence h(mk<IO>("A", std::move(h_load_IODir)), mk<Clear>("A"));
216  EXPECT_EQ(g, h);
217  EXPECT_NE(&g, &h);
218 
219  Sequence* i = g.clone();
220  EXPECT_EQ(g, *i);
221  EXPECT_NE(&g, i);
222  delete i;
223 }
224 
225 TEST(Parallel, CloneAndEquals) {
226  Relation A("A", 3, 1, {"a", "b", "c"}, {"i", "s", "i"}, RelationRepresentation::DEFAULT);
227  Relation B("B", 2, 1, {"a", "c"}, {"i", "i"}, RelationRepresentation::DEFAULT);
228 
229  /* PARALLEL
230  * QUERY
231  * FOR t0 IN A
232  * IF (t0.0 > 0)
233  * PROJECT (t0.0, t0.2) INTO B
234  * END PARALLEL
235  * */
236 
237  VecOwn<Expression> a_expressions;
238  a_expressions.emplace_back(new TupleElement(0, 0));
239  a_expressions.emplace_back(new TupleElement(0, 2));
240  auto a_project = mk<Project>("B", std::move(a_expressions));
241  auto a_cond =
242  mk<Filter>(mk<Constraint>(BinaryConstraintOp::GE, mk<TupleElement>(0, 0), mk<SignedConstant>(0)),
243  std::move(a_project), "");
244  auto a_scan = mk<Scan>("A", 0, std::move(a_cond), "");
245  auto a_query = mk<Query>(std::move(a_scan));
246  Parallel a(std::move(a_query));
247 
248  VecOwn<Expression> b_expressions;
249  b_expressions.emplace_back(new TupleElement(0, 0));
250  b_expressions.emplace_back(new TupleElement(0, 2));
251  auto b_project = mk<Project>("B", std::move(b_expressions));
252  auto b_cond =
253  mk<Filter>(mk<Constraint>(BinaryConstraintOp::GE, mk<TupleElement>(0, 0), mk<SignedConstant>(0)),
254  std::move(b_project), "");
255  auto b_scan = mk<Scan>("A", 0, std::move(b_cond), "");
256  auto b_query = mk<Query>(std::move(b_scan));
257  Parallel b(std::move(b_query));
258 
259  EXPECT_EQ(a, b);
260  EXPECT_NE(&a, &b);
261 
262  Parallel* c = a.clone();
263  EXPECT_EQ(a, *c);
264  EXPECT_NE(&a, c);
265  delete c;
266 }
267 TEST(Loop, CloneAndEquals) {
268  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
269  Relation B("B", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
270  /*
271  * LOOP
272  * QUERY
273  * FOR t0 IN A
274  * IF t0.0 = 4 BREAK
275  * PROJECT (t0.0) INTO B
276  * END LOOP
277  * */
278  VecOwn<Expression> a_expressions;
279  a_expressions.emplace_back(new TupleElement(0, 0));
280  auto a_project = mk<Project>("B", std::move(a_expressions));
281  auto a_break =
282  mk<Break>(mk<Constraint>(BinaryConstraintOp::EQ, mk<TupleElement>(0, 0), mk<SignedConstant>(4)),
283  std::move(a_project), "");
284  auto a_scan = mk<Scan>("A", 0, std::move(a_break), "");
285  auto a_query = mk<Query>(std::move(a_scan));
286  Loop a(std::move(a_query));
287 
288  VecOwn<Expression> b_expressions;
289  b_expressions.emplace_back(new TupleElement(0, 0));
290  auto b_project = mk<Project>("B", std::move(b_expressions));
291  auto b_break =
292  mk<Break>(mk<Constraint>(BinaryConstraintOp::EQ, mk<TupleElement>(0, 0), mk<SignedConstant>(4)),
293  std::move(b_project), "");
294  auto b_scan = mk<Scan>("A", 0, std::move(b_break), "");
295  auto b_query = mk<Query>(std::move(b_scan));
296  Loop b(std::move(b_query));
297  EXPECT_EQ(a, b);
298  EXPECT_NE(&a, &b);
299 
300  Loop* c = a.clone();
301  EXPECT_EQ(a, *c);
302  EXPECT_NE(&a, c);
303  delete c;
304 }
305 TEST(Exit, CloneAndEquals) {
306  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
307  // EXIT (A = ∅)
308  Exit a(mk<EmptinessCheck>("A"));
309  Exit b(mk<EmptinessCheck>("A"));
310  EXPECT_EQ(a, b);
311  EXPECT_NE(&a, &b);
312 
313  Exit* c = a.clone();
314  EXPECT_EQ(a, *c);
315  EXPECT_NE(&a, c);
316  delete c;
317 }
318 
319 TEST(LogRelationTimer, CloneAndEquals) {
320  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
321  /*
322  * START_TIMER ON A "file.dl [8:1-8:8]"
323  * IO A()
324  * END_TIMER
325  * */
326  std::map<std::string, std::string> a_IODir;
327  std::map<std::string, std::string> b_IODir;
328  LogRelationTimer a(mk<IO>("A", std::move(a_IODir)), "file.dl [8:1-8:8]", "A");
329  LogRelationTimer b(mk<IO>("A", std::move(b_IODir)), "file.dl [8:1-8:8]", "A");
330  EXPECT_EQ(a, b);
331  EXPECT_NE(&a, &b);
332 
333  LogRelationTimer* c = a.clone();
334  EXPECT_EQ(a, *c);
335  EXPECT_NE(&a, c);
336  delete c;
337 }
338 
339 TEST(LogTimer, CloneAndEquals) {
340  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
341  /*
342  * START_TIMER "@runtime"
343  * IO .. (..)
344  * END_TIMER
345  * */
346  std::map<std::string, std::string> a_IODir;
347  std::map<std::string, std::string> b_IODir;
348  LogTimer a(mk<IO>("A", std::move(a_IODir)), "@runtime");
349  LogTimer b(mk<IO>("A", std::move(a_IODir)), "@runtime");
350  EXPECT_EQ(a, b);
351  EXPECT_NE(&a, &b);
352 
353  LogTimer* c = a.clone();
354  EXPECT_EQ(a, *c);
355  EXPECT_NE(&a, c);
356  delete c;
357 }
358 
359 TEST(DebugInfo, CloneAndEquals) {
360  Relation edge(
361  "edge", 4, 1, {"src", "dest", "a", "b"}, {"i", "i", "i", "i"}, RelationRepresentation::DEFAULT);
362  Relation path(
363  "path", 4, 1, {"src", "dest", "a", "b"}, {"i", "i", "i", "i"}, RelationRepresentation::DEFAULT);
364  /* BEGIN_DEBUG "path(x,y,1,(@level_num_0+1)) :- \n edge(x,y,_,@level_num_0).\nin file /edge.dl
365  * [17:1-17:26];" QUERY FOR t0 IN edge IF (NOT (edge = ∅)) IF (NOT (t0.0,t0.1,⊥,⊥) ∈ path) PROJECT (t0.0,
366  * t0.1, number(1), (t0.3+number(1))) INTO path END DEBUG
367  * */
368  VecOwn<Expression> a_project_list;
369  a_project_list.emplace_back(new TupleElement(0, 0));
370  a_project_list.emplace_back(new TupleElement(0, 1));
371  a_project_list.emplace_back(new SignedConstant(1));
372  VecOwn<Expression> a_project_add;
373  a_project_add.emplace_back(new TupleElement(0, 3));
374  a_project_add.emplace_back(new SignedConstant(1));
375  a_project_list.emplace_back(new IntrinsicOperator(FunctorOp::ADD, std::move(a_project_add)));
376  auto a_project = mk<Project>("path", std::move(a_project_list));
377  VecOwn<Expression> a_filter1_list;
378  a_filter1_list.emplace_back(new TupleElement(0, 0));
379  a_filter1_list.emplace_back(new TupleElement(0, 1));
380  a_filter1_list.emplace_back(new UndefValue);
381  a_filter1_list.emplace_back(new UndefValue);
382  auto a_existence_check1 = mk<ExistenceCheck>("path", std::move(a_filter1_list));
383  auto a_cond1 = mk<Negation>(std::move(a_existence_check1));
384  auto a_filter1 = mk<Filter>(std::move(a_cond1), std::move(a_project), "");
385  auto a_cond2 = mk<Negation>(mk<EmptinessCheck>("edge"));
386  auto a_filter2 = mk<Filter>(std::move(a_cond2), std::move(a_filter1), "");
387  auto a_scan = mk<Scan>("edge", 0, std::move(a_filter2), "");
388  auto a_query = mk<Query>(std::move(a_scan));
389  DebugInfo a(std::move(a_query),
390  "path(x,y,1,(@level_num_0+1)) :- \n edge(x,y,_,@level_num_0).\nin file /edge.dl [17:1-17:26];");
391 
392  VecOwn<Expression> b_project_list;
393  b_project_list.emplace_back(new TupleElement(0, 0));
394  b_project_list.emplace_back(new TupleElement(0, 1));
395  b_project_list.emplace_back(new SignedConstant(1));
396  VecOwn<Expression> b_project_add;
397  b_project_add.emplace_back(new TupleElement(0, 3));
398  b_project_add.emplace_back(new SignedConstant(1));
399  b_project_list.emplace_back(new IntrinsicOperator(FunctorOp::ADD, std::move(b_project_add)));
400  auto b_project = mk<Project>("path", std::move(b_project_list));
401  VecOwn<Expression> b_filter1_list;
402  b_filter1_list.emplace_back(new TupleElement(0, 0));
403  b_filter1_list.emplace_back(new TupleElement(0, 1));
404  b_filter1_list.emplace_back(new UndefValue);
405  b_filter1_list.emplace_back(new UndefValue);
406  auto b_existence_check1 = mk<ExistenceCheck>("path", std::move(b_filter1_list));
407  auto b_cond1 = mk<Negation>(std::move(b_existence_check1));
408  auto b_filter1 = mk<Filter>(std::move(b_cond1), std::move(b_project), "");
409  auto b_cond2 = mk<Negation>(mk<EmptinessCheck>("edge"));
410  auto b_filter2 = mk<Filter>(std::move(b_cond2), std::move(b_filter1), "");
411  auto b_scan = mk<Scan>("edge", 0, std::move(b_filter2), "");
412  auto b_query = mk<Query>(std::move(b_scan));
413  DebugInfo b(std::move(b_query),
414  "path(x,y,1,(@level_num_0+1)) :- \n edge(x,y,_,@level_num_0).\nin file /edge.dl [17:1-17:26];");
415 
416  EXPECT_EQ(a, b);
417  EXPECT_NE(&a, &b);
418 
419  DebugInfo* c = a.clone();
420  EXPECT_EQ(a, *c);
421  EXPECT_NE(&a, c);
422  delete c;
423 }
424 
425 TEST(LogSize, CloneAndEquals) {
426  Relation A("A", 1, 1, {"x"}, {"i"}, RelationRepresentation::DEFAULT);
427  LogSize a("A", "Log message");
428  LogSize b("A", "Log message");
429  EXPECT_EQ(a, b);
430  EXPECT_NE(&a, &b);
431 
432  LogSize* c = a.clone();
433  EXPECT_EQ(a, *c);
434  EXPECT_NE(&a, c);
435  delete c;
436 }
437 } // end namespace test
438 } // namespace souffle::ram
BinaryConstraintOps.h
Constraint.h
souffle::ram::Swap
Swap operation with respect to two relations.
Definition: Swap.h:43
souffle::ram::Query
A relational algebra query.
Definition: Query.h:50
Scan.h
Exit.h
Negation.h
Project.h
souffle::ram::Query::clone
Query * clone() const override
Create a clone (i.e.
Definition: Query.h:65
Clear.h
LogTimer.h
souffle::ram::Loop
Execute statement until statement terminates loop via an exit statement.
Definition: Loop.h:48
souffle::ram::Exit
Exit statement for a loop.
Definition: Exit.h:48
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: test.h:191
souffle::ram::Parallel
Parallel block of statements.
Definition: Parallel.h:49
souffle::ram::Extend
Extend equivalence relation.
Definition: Extend.h:41
e
l j a showGridBackground &&c b raw series this eventEmitter e
Definition: htmlJsChartistMin.h:15
ParallelChoice.h
souffle::BinaryConstraintOp::EQ
@ EQ
LogRelationTimer.h
souffle::ram::SignedConstant
Represents a signed constant.
Definition: SignedConstant.h:40
Filter.h
souffle::ram::LogTimer
Execution time logger for a statement.
Definition: LogTimer.h:55
DebugInfo.h
EmptinessCheck.h
Swap.h
souffle::ram::TupleElement
Access element from the current tuple in a tuple environment.
Definition: TupleElement.h:42
souffle::ram
Definition: AstToRamTranslator.h:54
i
size_t i
Definition: json11.h:663
souffle::ram::Clear
Delete tuples of a relation.
Definition: Clear.h:50
RelationTag.h
souffle::ram::Relation
An abstract class for performing indexed operations.
Definition: Relation.h:40
Relation.h
souffle::BinaryConstraintOp::GE
@ GE
Condition.h
ExistenceCheck.h
IO.h
test.h
Break.h
souffle::ram::DebugInfo
Debug statement.
Definition: DebugInfo.h:47
EXPECT_NE
#define EXPECT_NE(a, b)
Definition: test.h:195
souffle::ram::IntrinsicOperator
Operator that represents an intrinsic (built-in) functor.
Definition: IntrinsicOperator.h:42
souffle::ram::test::TEST
TEST(True, CloneAndEquals)
Definition: ram_condition_equal_clone_test.cpp:54
TupleElement.h
b
l j a showGridBackground &&c b raw series this eventEmitter b
Definition: htmlJsChartistMin.h:15
Operation.h
Query.h
souffle::RelationRepresentation::DEFAULT
@ DEFAULT
Sequence.h
Statement.h
SignedConstant.h
d
else d
Definition: htmlJsChartistMin.h:15
souffle::ram::UndefValue
An undefined expression.
Definition: UndefValue.h:36
SubroutineReturn.h
FunctorOps.h
Expression.h
UndefValue.h
Loop.h
souffle::ram::Sequence::clone
Sequence * clone() const override
Create a clone (i.e.
Definition: Sequence.h:45
souffle::FunctorOp::ADD
@ ADD
Binary Functor Operators.
souffle::ram::LogSize
Log relation size and a logging message.
Definition: LogSize.h:38
souffle::ram::Sequence
Sequence of RAM statements.
Definition: Sequence.h:37
LogSize.h
souffle::VecOwn
std::vector< Own< A > > VecOwn
Definition: ContainerUtil.h:45
IntrinsicOperator.h
souffle::ram::LogRelationTimer
Execution time logger for a statement.
Definition: LogRelationTimer.h:55
Parallel.h
Extend.h