souffle  2.0.2-371-g6315b36
eqrel_datastructure_test.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2018, The Souffle Developers and/or its affiliates. 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 eqrel_datastructure_test.cpp
12  *
13  * A test case testing the miscellaneous auxilliary data structures
14  * PiggyList, RandomInsertPiggyList, DisjointSet, SparseDisjointSet, and LambdaBTree
15  *
16  ***********************************************************************/
17 
18 #include "tests/test.h"
19 
23 #include <atomic>
24 #include <cstddef>
25 #include <functional>
26 #include <iostream>
27 #include <string>
28 #include <unordered_map>
29 #include <utility>
30 #include <vector>
31 
32 #ifdef _OPENMP
33 #include <omp.h>
34 #endif
35 
38 
39 namespace souffle {
40 namespace test {
41 
42 /** Piggy List that allows creation at arbitrary elements **/
43 TEST(RandomInsertPiggyTest, Scoping) {
44  // simply test that namespaces were setup correctly (compile time)
46 }
47 
48 TEST(RandomInsertPiggyTest, Insertion) {
49  // insert a bunch of stuff and check the size is valid?
51  EXPECT_EQ(pl.size(), 0);
52 
53  pl.insertAt(0, 99);
54  EXPECT_EQ(pl.get(0), 99);
55  EXPECT_EQ(pl.size(), 1);
56 
57  pl.insertAt(1000, 33);
58  EXPECT_EQ(pl.get(1000), 33);
59  EXPECT_EQ(pl.size(), 2);
60 }
61 
62 TEST(RandomInsertPiggyTest, DoubleClear) {
63  // err.. prior versions have had the bug where clear caused double-free errors (as we don't set the
64  // container to null) This should *crash* the test-suite if this is the case, but I also try to check the
65  // contents here
67  pl.insertAt(0, 3213);
68  pl.insertAt(1, 3213);
69  pl.insertAt(2, 3213);
70  pl.insertAt(3, 3213);
71  EXPECT_EQ(pl.size(), 4);
72  pl.clear();
73  EXPECT_EQ(pl.size(), 0);
74  pl.clear();
75  EXPECT_EQ(pl.size(), 0);
76  pl.insertAt(0, 1);
77  EXPECT_EQ(pl.size(), 1);
78 }
79 
80 #ifdef _OPENMP
81 TEST(RandomInsertPiggyTest, ParallelInsert) {
82  constexpr size_t limit = 10000;
84 
85 // insert in parallel (no element should be overridden, because this breaks the datastructure)
86 #pragma omp parallel for
87  for (size_t i = 0; i < limit; ++i) {
88  pl.insertAt(i, i);
89  }
90 
91  EXPECT_EQ(limit, pl.size());
92  for (size_t i = 0; i < limit; ++i) {
93  EXPECT_EQ(pl.get(i), i);
94  }
95 }
96 #endif
97 
98 /** Regular Old Piggy List **/
99 TEST(PiggyTest, Scoping) {
100  // simply test that namespaces were setup correctly (compile time)
102 }
103 
104 TEST(PiggyTest, Append) {
106  EXPECT_EQ(pl.size(), 0);
107  pl.append(99);
108  EXPECT_EQ(pl.size(), 1);
109  pl.append(99);
110  pl.append(99);
111  EXPECT_EQ(pl.size(), 3);
112  EXPECT_EQ(pl.get(0), 99);
113  EXPECT_EQ(pl.get(1), 99);
114  EXPECT_EQ(pl.get(2), 99);
115 
116  // larger than BLOCKSIZE
117  constexpr size_t N = 10000;
118 
119  for (size_t i = 0; i < N; ++i) {
120  pl.append(2);
121  }
122  EXPECT_EQ(pl.size(), N + 3);
123  // make sure that all of our inserties are exacties
124  for (size_t i = 3; i < N + 3; ++i) {
125  EXPECT_EQ(pl.get(i), 2);
126  }
127 }
128 
129 TEST(PiggyTest, ElementCreation) {
130  // test that we can use makeNode() and set the values properly
132  pl.get(pl.createNode()) = 99;
133  EXPECT_EQ(pl.size(), 1);
134  EXPECT_EQ(pl.get(0), 99);
135 }
136 
137 TEST(PiggyTest, Iteration) {
139  constexpr size_t N = 10000;
140  for (size_t i = 0; i < N; ++i) {
141  pl.append(i);
142  }
143  size_t counter = 0;
144  for (size_t e : pl) {
145  EXPECT_EQ(e, counter++);
146  }
147 }
148 
149 TEST(PiggyTest, CopyCtor) {
151  constexpr size_t N = 10000;
152  for (size_t i = 0; i < N; ++i) {
153  pl.append(i);
154  }
155 
157  EXPECT_EQ(pl.size(), pl2.size());
158 
159  // check every element is equal and same order
160  for (size_t i = 0; i < N; ++i) {
161  EXPECT_EQ(pl.get(i), pl2.get(i));
162  EXPECT_EQ(pl.get(i), i);
163  }
164 
165  auto pl1It = pl.begin();
166  auto pl2It = pl2.begin();
167 
168  while (true) {
169  // yep, they both finished at the same time
170  if (pl1It == pl.end() && pl2It == pl2.end()) {
171  break;
172  }
173 
174  // uhoh, they didn't both finish at the same time
175  if (pl1It == pl.end() || pl2It == pl2.end()) {
176  EXPECT_FALSE(true && "whoops, looks like the iterators are broken");
177  }
178 
179  EXPECT_EQ(*pl1It, *pl2It);
180 
181  ++pl1It;
182  ++pl2It;
183  }
184 
185  // change contents of pl1 and makesure they don't change in pl2
186  pl.get(2) = 99;
187  EXPECT_EQ(pl.get(2), 99);
188  EXPECT_EQ(pl2.get(2), 2);
189 
190  // check clearing one doesn't invalidate the other
191  pl.clear();
192  EXPECT_EQ(pl.size(), 0);
193  EXPECT_EQ(pl2.size(), N);
194  pl2.clear();
195  EXPECT_EQ(pl.size(), 0);
196  EXPECT_EQ(pl2.size(), 0);
197 }
198 
199 TEST(PiggyTest, DoubleClear) {
200  // err.. prior versions have had the bug where clear caused double-free errors (as we don't set the
201  // container to null) This should *crash* the test-suite if this is the case, but I also try to check the
202  // contents here
204  pl.append(3213);
205  pl.append(3213);
206  pl.append(3213);
207  pl.append(3213);
208  EXPECT_EQ(pl.size(), 4);
209  pl.clear();
210  EXPECT_EQ(pl.size(), 0);
211  pl.clear();
212  EXPECT_EQ(pl.size(), 0);
213  pl.append(1);
214  EXPECT_EQ(pl.size(), 1);
215 }
216 
217 #ifdef _OPENMP
218 TEST(PiggyTest, ParallelElementSpawning) {
219  constexpr size_t N = 10000;
221 
222 #pragma omp parallel for
223  for (size_t i = 0; i < N; ++i) {
224  size_t pos = pl.createNode();
225  pl.get(pos) = pos;
226  }
227  EXPECT_EQ(N, pl.size());
228 
229  for (size_t i = 0; i < N; ++i) {
230  EXPECT_EQ(i, pl.get(i));
231  }
232 }
233 
234 TEST(PiggyTest, ParallelAppend) {
235  constexpr size_t N = 10000;
237 
238 #pragma omp parallel for
239  for (size_t i = 0; i < N; ++i) {
240  pl.append(i);
241  }
242  EXPECT_EQ(N, pl.size());
243 
244  std::set<size_t> verifier;
245  for (size_t i = 0; i < N; ++i) {
246  verifier.emplace(pl.get(i));
247  }
248  // check there aren't any duplicate elements
249  EXPECT_EQ(verifier.size(), N);
250  // check every element within the inserted range exists
251  for (size_t e : verifier) {
252  EXPECT_TRUE(e < N);
253  }
254 }
255 
256 #endif // ifdef _OPENMP
257 
258 /** The underlying Disjoint Set (essentially Anderson '91 Find-Union, but dynamic) **/
259 TEST(DjTest, Scoping) {
261 }
262 
263 TEST(DjTest, MakeNode) {
265  EXPECT_EQ(ds.size(), 0);
266  souffle::block_t n = ds.makeNode();
267  // parent should be itself
269  // rank should be 0
271  EXPECT_EQ(ds.size(), 1);
272 
274  // parent should be itself
275  EXPECT_EQ(DisjointSet::b2p(n2), 1);
276  // rank should be 0
278  EXPECT_EQ(ds.size(), 2);
279 }
280 
281 TEST(DjTest, TestUnion) {
282  // check whether the unioning works to see if the elements are properly in the same set
284 
290  EXPECT_EQ(ds.size(), 5);
291 
292  // test running same set doesn't accidentally union them
293  EXPECT_FALSE(ds.sameSet(n1, n2));
294  EXPECT_FALSE(ds.sameSet(n1, n2));
295  EXPECT_FALSE(ds.sameSet(n1, n2));
296  EXPECT_FALSE(ds.sameSet(n1, n2));
297 
298  ds.unionNodes(n1, n2);
299  EXPECT_TRUE(ds.sameSet(n1, n2));
300  EXPECT_FALSE(ds.sameSet(n3, n2));
301 
302  ds.unionNodes(n3, n4);
303  ds.unionNodes(n3, n5);
304  ds.unionNodes(n1, n5);
305 
306  // ensure that nodes that weren't explicitly connected are in fact connected
307  EXPECT_TRUE(ds.sameSet(n1, n4));
308  // and their symmetric
309  EXPECT_TRUE(ds.sameSet(n4, n1));
310 
311  // size shouldn't change
312  EXPECT_EQ(ds.size(), 5);
313 }
314 
315 TEST(DjTest, Clear) {
317 
318  ds.clear();
319  EXPECT_EQ(ds.size(), 0);
320 
321  // get ready 2 double free y'all
322  for (size_t i = 0; i < 10000; ++i) {
323  ds.makeNode();
324  }
325  ds.unionNodes(1, 2);
326  ds.clear();
327  ds.clear();
328 }
329 
330 #ifdef _OPENMP
331 TEST(DjTest, ParallelScaling) {
332  // insert, union, and stuff in parallel, then check things are in the valid sets
333 
335  constexpr size_t N = 10000;
336 
337 #pragma omp parallel for
338  for (size_t i = 0; i < N; ++i) {
339  ds.makeNode();
340  }
341  // check we didn't miss any
342  EXPECT_EQ(ds.size(), N);
343 
344 // union everything
345 #pragma omp parallel for
346  for (size_t i = 0; i < N - 1; ++i) {
347  ds.unionNodes(i, i + 1);
348  }
349  EXPECT_EQ(ds.size(), N);
350 
351  // iterate through and check that the findNode is always the same
352  parent_t rep = ds.findNode(0);
353  for (size_t i = 0; i < N; ++i) {
354  EXPECT_EQ(rep, ds.findNode(i));
355  }
356 }
357 #endif // ifdef _OPENMP
358 
359 /** The SparseDisjointSet that is used by the EquivalenceRelation **/
360 TEST(SparseDjTest, Scoping) {
362 }
363 
364 TEST(SparseDjTest, MakeNode) {
366  EXPECT_EQ(sds.size(), 0);
367 
368  sds.makeNode(99);
369  EXPECT_EQ(sds.size(), 1);
370 
371  // whilst this shouldn't happen in regular use, it *shouldn't* create a new node
372  sds.makeNode(99);
373  EXPECT_EQ(sds.size(), 1);
374 
375  constexpr size_t N = 10000;
376  for (size_t i = 0; i < N; ++i) {
377  sds.makeNode(i);
378  }
379 
380  EXPECT_EQ(sds.size(), N);
381 }
382 
383 TEST(SparseDjTest, TestUnion) {
384  // check whether the unioning works to see if the elements are properly in the same set
386 
387  sds.makeNode(20);
388  sds.makeNode(32);
389 
390  EXPECT_FALSE(sds.contains(20, 32));
391  sds.unionNodes(20, 32);
392  EXPECT_TRUE(sds.contains(20, 32));
393 
394  EXPECT_EQ(sds.size(), 2);
395 
396  sds.makeNode(33);
397  EXPECT_FALSE(sds.contains(20, 33));
398  sds.unionNodes(32, 33);
399  EXPECT_TRUE(sds.contains(20, 33));
400  EXPECT_EQ(sds.size(), 3);
401 }
402 
403 TEST(SparseDjTest, SignedData) {
404  // test when the sparse dj set stores different signed-ness to the internally stored data
406 
407  EXPECT_EQ(sds.size(), 0);
408  sds.makeNode(9999);
409  EXPECT_EQ(sds.size(), 1);
410 }
411 
412 #ifdef _OPENMP
413 TEST(SparseDjTest, ParallelDense) {
415  // store the dense and sparse values
417 
418  constexpr size_t N = 1000000;
419 
420  std::vector<size_t> data_source;
421  for (size_t i = 0; i < N; ++i) {
422  data_source.push_back(i);
423  }
424  std::shuffle(data_source.begin(), data_source.end(), std::random_device());
425 
426  // call toDense for a load of sparse values, and hope to god they're the same
427 #pragma omp parallel for
428  for (size_t i = 0; i < N; ++i) {
429  size_t val = data_source[i];
430  size_t a = sds.toDense(val);
431  size_t b = sds.toDense(val);
432  pl.append(std::make_pair(a, val));
433  pl.append(std::make_pair(b, val));
434  }
435 
436  // check each sparse value (pair.second) maps to a single dense value as per the piggylist
437  std::unordered_map<size_t, size_t> mapper;
438  for (size_t i = 0; i < pl.size(); ++i) {
439  size_t sparse = pl.get(i).second;
440  size_t dense = pl.get(i).first;
441 
442  if (mapper.count(sparse) == 1) {
443  if (mapper[sparse] != dense) {
444  // GDB trap
445  throw std::runtime_error(
446  "invalid state detected, different dense values for same sparse values");
447  }
448  } else {
449  mapper.emplace(sparse, dense);
450  }
451  }
452 
453  EXPECT_EQ(N, mapper.size());
454 }
455 #endif
456 
457 #ifdef _OPENMP
458 TEST(SparseDjTest, ParallelScaling) {
459  // insert, union, and stuff in parallel, then check things are in the valid sets
461  constexpr size_t N = 1000000;
462 
463 #pragma omp parallel for
464  for (size_t i = 0; i < N; ++i) {
465  // make things which are relatively sparse (hence why we mul by 50)
466  sds.makeNode(i * 50);
467  }
468 
469  EXPECT_EQ(sds.size(), N);
470  // union everything
471 #pragma omp parallel for
472  for (size_t i = 0; i < N - 1; ++i) {
473  sds.unionNodes(i * 50, (i + 1) * 50);
474  }
475 
476  EXPECT_EQ(sds.size(), N);
477  for (size_t i = 0; i < N - 1; ++i) {
478  EXPECT_TRUE(sds.contains(i * 50, (i + 1) * 50));
479  }
480  EXPECT_EQ(sds.size(), N);
481 }
482 
483 TEST(SparseDjTest, ParallelTest) {
485  constexpr size_t N = 1000000;
486 
487 #pragma omp parallel for
488  for (size_t i = 0; i < N; ++i) {
489  sds.unionNodes(i, i);
490  }
491 
492  EXPECT_EQ(sds.size(), N);
493 }
494 
495 #endif // ifdef _OPENMP
496 
497 typedef std::pair<size_t, size_t> TestPair;
498 using TestLambdaTree = souffle::LambdaBTreeSet<TestPair, std::function<TestPair::second_type(TestPair&)>,
500 
501 /** The LambdaBTree - essentially a ripoff to the Btree, but allows a function to be called on successful
502  * insert. I just am gonna test a subset of it, because I can argue that BTree already tests the basic stuff
503  * **/
504 TEST(LambdaBTreeTest, Scoping) {
505  // lambda btree set current has some hard coded stuff h1
506  TestLambdaTree t;
507 }
508 
509 TEST(LambdaBTreeTest, Insert) {
510  // insert some stuff and make sure the sideeffects are correct (as observed within the lambda), and also
511  // that the elements are contained
512 
513  // the ticket machine that sets the second argument (for now our functor will just postincrent to assign)
514  std::atomic<size_t> assigner(0);
515 
516  TestLambdaTree t;
517  EXPECT_EQ(t.size(), 0);
518 
519  std::function<TestPair::second_type(TestPair&)> update_fn = [&](TestPair& tp) {
520  tp.second = assigner.fetch_add(1);
521  return tp.second;
522  };
523 
524  TestPair toInsert = {55, -1};
525  // inserting the ticketed value
526  EXPECT_EQ(t.insert(toInsert, update_fn), 0);
527 
528  EXPECT_EQ(t.size(), 1);
529 
530  // the second argument should be ignored because its unknown until you fetch it!
531  EXPECT_TRUE(t.contains({55, 1329139123}));
532 
533  // post increment of 0 is zero.
534  EXPECT_EQ(((*t.find({55, 3232})).second), 0);
535 
536  TestPair insert2 = {43, 22};
537  // insert should also return the value
538  EXPECT_EQ(t.insert(insert2, update_fn), 1);
539  EXPECT_TRUE(t.contains({43, 1329139123}));
540  // post increment now should equal 1
541  EXPECT_EQ(((*t.find({43, 3232})).second), 1);
542  EXPECT_EQ(t.size(), 2);
543 
544  // now lets insert something that already exists (the anterior is all that matters)
545  TestPair alreadyExistsPair = {55, 12313123};
546  EXPECT_EQ(t.insert(alreadyExistsPair,
547  [&](TestPair&) {
548  EXPECT_TRUE(false &&
549  "newly inserted function called for an element that already exists!");
550  // some dummy value
551  return 3223;
552  }),
553  0);
554 
555  EXPECT_EQ(t.size(), 2);
556 }
557 
558 #ifdef _OPENMP
559 TEST(LambdaBTreeTest, ParallelInsert) {
560  // check whether doing the above works, but in parallel
561  // we must ensure that duplicate elements inserted in parallel stiiilll should only result in singly
562  // elements inserted
563 
564  constexpr size_t N = 10000;
565  {
566  // the ticket machine that sets the second argument (for now our functor will just postincrent to
567  // assign)
568  std::atomic<size_t> assigner(0);
569  std::function<TestPair::second_type(TestPair&)> update_fn = [&](TestPair& tp) {
570  tp.second = assigner.fetch_add(1);
571  return tp.second;
572  };
573 
574  TestLambdaTree t;
575 
576 #pragma omp parallel for
577  for (size_t i = 0; i < N; ++i) {
578  TestPair tp = {i, 123132};
579  t.insert(tp, update_fn);
580  }
581 
582  // assert that every number in [0, N) are covered in the posterior of the stored pairs
583  std::set<TestPair::second_type> covering;
584 
585  // iterating through the tree should be in order
586  size_t i = 0;
587  for (auto p : t) {
588  EXPECT_EQ(p.first, i++);
589  covering.emplace(p.second);
590  }
591  // and have the right number of elements
592  EXPECT_EQ(i, N);
593 
594  // assert that everything is unique (i.e. a set)
595  EXPECT_EQ(covering.size(), N);
596  for (size_t i = 0; i < N; ++i) {
597  EXPECT_EQ(covering.count(i), 1);
598  }
599  }
600 
601  // now our second test is setting duplicates concurrently (we try and maximise the potentiality of
602  // duplication, by trying to make the threads make the same number at the same time)
603  size_t num_threads = omp_get_max_threads();
604  {
605  // shadowing the N to make one that's trimmed by thread number (don't want things non-divisible by the
606  // thread count!)
607  const size_t N2 = (N / num_threads) * num_threads;
608 
609  std::atomic<size_t> assigner(0);
610  std::function<TestPair::second_type(TestPair&)> update_fn = [&](TestPair& tp) {
611  tp.second = assigner.fetch_add(1);
612  return tp.second;
613  };
614 
615  TestLambdaTree t;
616 #pragma omp parallel for
617  for (size_t i = 0; i < N2; ++i) {
618  TestPair tp = {i / num_threads, 213812309};
619  // by doing this, we pretty much make the same insertion num_thread times, for the next num_thread
620  // loops
621  t.insert(tp, update_fn);
622  }
623 
624  EXPECT_EQ(t.size(), N2 / num_threads);
625  // iterating through the tree should be in order
626  size_t i = 0;
627  for (auto p : t) {
628  EXPECT_EQ(p.first, i++);
629  }
630 
631  // we check the assigner atomic, and see if its not larger than the number of times it should have
632  // been called (N2/8) times. a violation of this would occur when we try and call the functor twice
633  // for the number of threads
634  EXPECT_EQ(assigner.load(), N2 / num_threads);
635 
636  // unfortunately, the above test couuuuld fail if two were called for the same element, then skipped
637  // for another... so I go through and check anyway.
638  std::vector<bool> verifier(N2 / num_threads, false);
639  for (auto p : t) {
640  if (verifier.at(p.second)) {
641  EXPECT_TRUE(false && "duplicate posteriors found within the lambdatree");
642  }
643  // set it to true unconditionally to indicate that we've seen a set value for this posterior.
644  verifier.at(p.second) = true;
645  }
646  }
647 }
648 #endif // ifdef _OPENMP
649 
650 #ifdef _OPENMP
651 TEST(LambdaBTree, ContendParallel) {
652  // in this tree, we store a mapping from a sparse to a dense value
653  // a dense value is uniquely allocated to a sparse value (which is the anterior of the pair passed into
654  // insert).
655  TestLambdaTree tlt;
656 
657  std::atomic<size_t> counter{0};
658 
659  constexpr size_t N = 100;
660  const std::function<size_t(TestPair&)> fun = [&](TestPair& p) {
661  p.second = counter++;
662  return p.second;
663  };
664 
665  // shuffle the vector around to make us insert non-incremental pairs (seems to make it more common...?)
666  std::vector<size_t> data_source;
667  for (size_t i = 0; i < N; ++i) {
668  data_source.push_back(i);
669  }
670  std::shuffle(data_source.begin(), data_source.end(), std::random_device());
671 
672 #pragma omp parallel for
673  for (size_t i = 0; i < N; ++i) {
674  size_t val = data_source[i];
675  // two pairs, the second part of the pair is updated within the functor if it doesn't exist
676  // in both cases, the now-existing value is returned.
677  std::pair<size_t, size_t> paira = {val, -1};
678  std::pair<size_t, size_t> pairb = {val, -1};
679  size_t a = tlt.insert(paira, fun);
680  size_t b = tlt.insert(pairb, fun);
681 
682  if (a != b) {
683  std::cout << "Different values observed for key " << val << ": " << a << " vs. " << b << "\n";
684  tlt.printTree();
685  throw std::runtime_error("Error detected!");
686  }
687  }
688 
689  if (N != tlt.size()) {
690  throw std::runtime_error("Wrong tree size!");
691  }
692 
693  EXPECT_EQ(N, tlt.size());
694 
695  std::cout << "number of times the functor has been called: " << counter.load() << std::endl;
696  EXPECT_EQ(N, counter.load());
697 }
698 #endif
699 
700 } // namespace test
701 } // namespace souffle
souffle::PiggyList::get
T & get(size_t index) const
Retrieve a reference to the stored value at index.
Definition: PiggyList.h:235
BTree.h
souffle::parent_t
uint64_t parent_t
Definition: UnionFind.h:41
EXPECT_TRUE
#define EXPECT_TRUE(a)
Definition: test.h:189
souffle::PiggyList::size
size_t size() const
Well, returns the number of nodes exist within the list + number of nodes queued to be inserted The r...
Definition: PiggyList.h:181
souffle::SparseDisjointSet
Definition: UnionFind.h:258
souffle::DisjointSet::clear
void clear()
Clears the DisjointSet of all nodes Invalidates all iterators.
Definition: UnionFind.h:140
souffle::RandomInsertPiggyList::insertAt
void insertAt(size_t index, T value)
Definition: PiggyList.h:90
souffle::RandomInsertPiggyList::get
T & get(size_t index) const
Definition: PiggyList.h:83
souffle::SparseDisjointSet::size
std::size_t size()
Definition: UnionFind.h:331
souffle::DisjointSet::findNode
parent_t findNode(parent_t x)
Equivalent to the find() function in union/find Find the highest ancestor of the provided node - flat...
Definition: UnionFind.h:97
souffle::SparseDisjointSet::toDense
parent_t toDense(const SparseDomain in)
Retrieve dense encoding, adding it in if non-existent.
Definition: UnionFind.h:281
souffle::PiggyList::begin
iterator begin()
Definition: PiggyList.h:295
souffle::DisjointSet::sameSet
bool sameSet(parent_t x, parent_t y)
Check whether the two indices are in the same set.
Definition: UnionFind.h:150
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: test.h:191
e
l j a showGridBackground &&c b raw series this eventEmitter e
Definition: htmlJsChartistMin.h:15
souffle::SparseDisjointSet::unionNodes
void unionNodes(SparseDomain x, SparseDomain y)
Definition: UnionFind.h:327
souffle::test::TestLambdaTree
souffle::LambdaBTreeSet< TestPair, std::function< TestPair::second_type(TestPair &)>, souffle::EqrelMapComparator< TestPair > > TestLambdaTree
Definition: eqrel_datastructure_test.cpp:513
souffle::PiggyList::append
size_t append(T element)
Definition: PiggyList.h:189
souffle::DisjointSet::makeNode
block_t makeNode()
Create a node with its parent as itself, rank 0.
Definition: UnionFind.h:198
souffle::PiggyList::createNode
size_t createNode()
Definition: PiggyList.h:210
n
var n
Definition: htmlJsChartistMin.h:15
souffle::detail::LambdaBTree::insert
Functor::result_type insert(Key &k, const Functor &f)
Inserts the given key into this tree.
Definition: LambdaBTree.h:87
souffle::SparseDisjointSet::contains
bool contains(SparseDomain v1, SparseDomain v2)
Definition: UnionFind.h:355
LambdaBTree.h
UnionFind.h
i
size_t i
Definition: json11.h:663
souffle::PiggyList
Definition: PiggyList.h:143
souffle::PiggyList::clear
void clear()
Clear all elements from the PiggyList.
Definition: PiggyList.h:246
souffle::block_t
uint64_t block_t
Definition: UnionFind.h:47
souffle::SparseDisjointSet::makeNode
void makeNode(SparseDomain val)
Definition: UnionFind.h:345
PiggyList.h
souffle::EqrelMapComparator
Definition: UnionFind.h:237
souffle::DisjointSet::unionNodes
void unionNodes(parent_t x, parent_t y)
Union the two specified index nodes.
Definition: UnionFind.h:165
test.h
souffle::RandomInsertPiggyList::clear
void clear()
Definition: PiggyList.h:110
souffle::detail::btree::size
size_type size() const
Definition: BTree.h:1321
souffle::detail::btree::find
iterator find(const Key &k) const
Locates the given key within this tree and returns an iterator referencing its position.
Definition: BTree.h:1772
b
l j a showGridBackground &&c b raw series this eventEmitter b
Definition: htmlJsChartistMin.h:15
souffle::detail::btree::contains
bool contains(const Key &k) const
Determines whether the given element is a member of this tree.
Definition: BTree.h:1756
StreamUtil.h
souffle::DisjointSet::b2p
static parent_t b2p(const block_t inblock)
Extract parent from block.
Definition: UnionFind.h:212
souffle::RandomInsertPiggyList::size
size_t size() const
Definition: PiggyList.h:75
souffle::test::TestPair
std::pair< size_t, size_t > TestPair
Definition: eqrel_datastructure_test.cpp:511
souffle::DisjointSet::b2r
static rank_t b2r(const block_t inblock)
Extract rank from block.
Definition: UnionFind.h:221
souffle
Definition: AggregateOp.h:25
souffle::RandomInsertPiggyList
A PiggyList that allows insertAt functionality.
Definition: PiggyList.h:37
souffle::DisjointSet
Structure that emulates a Disjoint Set, i.e.
Definition: UnionFind.h:54
souffle::PiggyList::end
iterator end()
Definition: PiggyList.h:298
souffle::LambdaBTreeSet
A b-tree based set implementation.
Definition: LambdaBTree.h:584
souffle::DisjointSet::size
size_t size()
Return the number of elements in this disjoint set (not the number of pairs)
Definition: UnionFind.h:76
EXPECT_FALSE
#define EXPECT_FALSE(a)
Definition: test.h:190
souffle::test::TEST
TEST(EqRelTest, Scoping)
Definition: binary_relation_test.cpp:51
p
a horizontalBars(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x, b.normalized.series, o, c.extend({}, a.axisX,{highLow:d, referenceValue:0})):a.axisX.type.call(c, c.Axis.units.x, b.normalized.series, o, c.extend({}, a.axisX,{highLow:d, referenceValue:0})), l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y, b.normalized.series, o,{ticks:k}):a.axisY.type.call(c, c.Axis.units.y, b.normalized.series, o, a.axisY)) var p
Definition: htmlJsChartistMin.h:15