souffle  2.0.2-371-g6315b36
Index.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2019, 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 Index.h
12  *
13  * Interpreter index with generic interface.
14  *
15  ***********************************************************************/
16 #pragma once
17 
18 #include "interpreter/Util.h"
19 #include "souffle/RamTypes.h"
25 #include <array>
26 #include <atomic>
27 #include <cassert>
28 #include <cstdint>
29 #include <cstring>
30 #include <iosfwd>
31 #include <iterator>
32 #include <memory>
33 #include <utility>
34 #include <vector>
35 
36 namespace souffle::interpreter {
37 /**
38  * An order to be enforced for storing tuples within
39  * indexes. The order is defined by the sequence of
40  * component to be considered in sorting tuples.
41  */
42 class Order {
43  using Attribute = uint32_t;
44  using AttributeOrder = std::vector<Attribute>;
46 
47 public:
48  Order() = default;
49  Order(AttributeOrder pos) : order(std::move(pos)) {
50  assert(valid());
51  }
52 
53  // Creates a natural order for the given arity.
54  static Order create(size_t arity) {
55  Order res;
56  res.order.resize(arity);
57  for (size_t i = 0; i < arity; i++) {
58  res.order[i] = i;
59  }
60  return res;
61  }
62 
63  size_t size() const {
64  return order.size();
65  }
66 
67  /**
68  * Determines whether this order is a valid order.
69  */
70  bool valid() const {
71  // Check that all indices are in range.
72  for (int i : order) {
73  if (i < 0 || i >= int(order.size())) {
74  return false;
75  }
76  }
77  // Check that there are no duplicates.
78  for (size_t i = 0; i < order.size(); i++) {
79  for (size_t j = i + 1; j < order.size(); j++) {
80  if (order[i] == order[j]) {
81  return false;
82  }
83  }
84  }
85  return true;
86  }
87 
88  /**
89  * Encode the tuple with order
90  */
91  template <size_t Arity>
92  Tuple<RamDomain, Arity> encode(const Tuple<RamDomain, Arity>& entry) const {
93  Tuple<RamDomain, Arity> res{};
94  for (size_t i = 0; i < Arity; ++i) {
95  res[i] = entry[order[i]];
96  }
97  return res;
98  }
99 
100  /**
101  * Decode the tuple by order
102  */
103  template <size_t Arity>
106  for (size_t i = 0; i < Arity; ++i) {
107  res[order[i]] = entry[i];
108  }
109  return res;
110  }
111 
112  const AttributeOrder& getOrder() const {
113  return this->order;
114  }
115 
116  bool operator==(const Order& other) const {
117  return order == other.order;
118  }
119 
120  bool operator!=(const Order& other) const {
121  return !(*this == other);
122  }
123 
124  Attribute operator[](const size_t idx) const {
125  return order[idx];
126  }
127 
128  friend std::ostream& operator<<(std::ostream& out, const Order& order);
129 };
130 
131 inline std::ostream& operator<<(std::ostream& out, const Order& order) {
132  return out << "[" << join(order.order) << "]";
133 }
134 
135 /**
136  * A dummy wrapper for indexViews.
137  */
138 struct ViewWrapper {
139  virtual ~ViewWrapper() = default;
140 };
141 
142 /**
143  * An index is an abstraction of a data structure
144  */
145 template <size_t _Arity, template <size_t> typename Structure>
146 class Index {
147 public:
148  static constexpr size_t Arity = _Arity;
149  using Data = Structure<Arity>;
150  using Tuple = typename souffle::Tuple<RamDomain, Arity>;
151  using iterator = typename Data::iterator;
152  using Hints = typename Data::operation_hints;
153 
154  Index(Order order) : order(std::move(order)) {}
155 
156 protected:
159 
160 public:
161  /**
162  * A view on a relation caching local access patterns (not thread safe!).
163  * Each thread should create and use its own view for accessing relations
164  * to exploit access patterns via operation hints.
165  */
166  class View : public ViewWrapper {
167  mutable Hints hints;
168  const Data& data;
169 
170  public:
171  View(const Data& data) : data(data) {}
172 
173  /** Tests whether the given entry is contained in this index. */
174  bool contains(const Tuple& entry) {
175  return data.contains(entry, hints);
176  }
177 
178  /** Tests whether any element in the given range is contained in this index. */
179  bool contains(const Tuple& low, const Tuple& high) {
180  return !range(low, high).empty();
181  }
182 
183  /** Obtains a pair of iterators representing the given range within this index. */
185  return {data.lower_bound(low, hints), data.upper_bound(high, hints)};
186  }
187  };
188 
189 public:
190  /**
191  * Requests the creation of a view on this index.
192  */
193  View createView() {
194  return View(this->data);
195  }
196 
197  iterator begin() const {
198  return data.begin();
199  }
200 
201  iterator end() const {
202  return data.end();
203  }
204 
205  /**
206  * Obtains the lex order of this index.
207  */
208  Order getOrder() const {
209  return order;
210  }
211 
212  /**
213  * Tests whether this index is empty or not.
214  */
215  bool empty() const {
216  return data.empty();
217  }
218 
219  /**
220  * Obtains the number of elements stored in this index.
221  */
222  size_t size() const {
223  return data.size();
224  }
225 
226  /**
227  * Inserts a tuple into this index.
228  */
229  bool insert(const Tuple& tuple) {
230  return data.insert(order.encode(tuple));
231  }
232 
233  /**
234  * Inserts all elements of the given index.
235  */
236  void insert(const Index<Arity, Structure>& src) {
237  for (const auto& tuple : src) {
238  this->insert(tuple);
239  }
240  }
241 
242  /**
243  * Tests whether the given tuple is present in this index or not.
244  */
245  bool contains(const Tuple& tuple) const {
246  return data.contains(tuple);
247  }
248 
249  /**
250  * Tests whether this index contains any tuple within the given bounds.
251  */
252  bool contains(const Tuple& low, const Tuple& high) const {
253  return !range(low, high).empty();
254  }
255 
256  /**
257  * Returns a pair of iterators covering the entire index content.
258  */
260  return {data.begin(), data.end()};
261  }
262 
263  /**
264  * Returns a pair of iterators covering elements in the range [low,high)
265  */
266  souffle::range<iterator> range(const Tuple& low, const Tuple& high) const {
267  return {data.lower_bound(low), data.upper_bound(high)};
268  }
269 
270  /**
271  * Retruns a partitioned list of iterators for parallel computation
272  */
273  std::vector<souffle::range<iterator>> partitionScan(int partitionCount) const {
274  auto chunks = data.partition(partitionCount);
275  std::vector<souffle::range<iterator>> res;
276  res.reserve(chunks.size());
277  for (const auto& cur : chunks) {
278  res.push_back({cur.begin(), cur.end()});
279  }
280  return res;
281  }
282 
283  /**
284  * Returns a partitioned list of iterators coving elements in range [low, high]
285  */
286  std::vector<souffle::range<iterator>> partitionRange(
287  const Tuple& low, const Tuple& high, int partitionCount) const {
288  auto ranges = this->range(low, high);
289  auto chunks = ranges.partition(partitionCount);
290  std::vector<souffle::range<iterator>> res;
291  res.reserve(chunks.size());
292  for (const auto& cur : chunks) {
293  res.push_back({cur.begin(), cur.end()});
294  }
295  return res;
296  }
297 
298  /**
299  * Clears the content of this index, turning it empty.
300  */
301  void clear() {
302  data.clear();
303  }
304 };
305 
306 /**
307  * A partial specialize template for nullary indexes.
308  * No complex data structure is required.
309  */
310 template <template <size_t> typename Structure>
311 class Index<0, Structure> {
312 public:
313  static constexpr size_t Arity = 0;
314  using Tuple = typename souffle::Tuple<RamDomain, 0>;
315 
316 protected:
317  // indicates whether the one single element is present or not.
318  std::atomic<bool> data{false};
319 
320 public:
321  Index(Order /* order */) {}
322 
323  // Specialized iterator class for nullary.
324  class iterator : public std::iterator<std::forward_iterator_tag, Tuple> {
325  bool value;
326  const Tuple dummy{};
327 
328  public:
329  iterator(bool v = false) : value(v) {}
330 
331  const Tuple& operator*() {
332  return dummy;
333  }
334 
335  bool operator==(const iterator& other) const {
336  return other.value == value;
337  }
338 
339  bool operator!=(const iterator& other) const {
340  return other.value != value;
341  }
342 
343  iterator& operator++() {
344  if (value) {
345  value = false;
346  }
347  return *this;
348  }
349  };
350 
351  iterator begin() const {
352  return iterator(data);
353  }
354  iterator end() const {
355  return iterator();
356  }
357 
358  // The nullary index view -- does not require any hints.
359  struct View : public ViewWrapper {
360  const std::atomic<bool>& data;
361 
362  public:
363  View(const std::atomic<bool>& data) : data(data) {}
364 
365  bool contains(const Tuple& /* t */) const {
366  return data;
367  }
368 
369  bool contains(const Tuple& /* l */, const Tuple& /* h */) const {
370  return data;
371  }
372 
373  souffle::range<iterator> range(const Tuple& /* l */, const Tuple& /* h */) const {
374  return {iterator(data), iterator()};
375  }
376  };
377 
378 public:
379  View createView() {
380  return View(this->data);
381  }
382 
383  Order getOrder() const {
384  return Order({0});
385  }
386 
387  bool empty() const {
388  return !data;
389  }
390 
391  size_t size() const {
392  return data ? 1 : 0;
393  }
394 
395  bool insert(const Tuple& /* t */) {
396  return data = true;
397  }
398 
399  void insert(const Index& src) {
400  data = src.data;
401  }
402 
403  bool contains(const Tuple& /* t */) const {
404  return data;
405  }
406 
407  bool contains(const Tuple& /* l */, const Tuple& /* h */) const {
408  return data;
409  }
410 
412  return {this->begin(), this->end()};
413  }
414 
415  souffle::range<iterator> range(const Tuple& /* l */, const Tuple& /* h */) const {
416  return {this->begin(), this->end()};
417  }
418 
419  std::vector<souffle::range<iterator>> partitionScan(int /* partitionCount */) const {
420  std::vector<souffle::range<iterator>> res;
421  res.push_back(scan());
422  return res;
423  }
424 
425  std::vector<souffle::range<iterator>> partitionRange(
426  const Tuple& /* l */, const Tuple& /* h */, int /* partitionCount */) const {
427  return this->partitionScan(0);
428  }
429 
430  void clear() {
431  data = false;
432  }
433 };
434 
435 /**
436  * For EqrelIndex we do inheritence since EqrelIndex only diff with one extra function.
437  */
438 class EqrelIndex : public interpreter::Index<2, Eqrel> {
439 public:
441 
442  /**
443  * Extend another index.
444  *
445  * Extend this index with another index, expanding this equivalence relation.
446  * The supplied relation is the old knowledge, whilst this relation only contains
447  * explicitly new knowledge. After this operation the "implicitly new tuples" are now
448  * explicitly inserted this relation.
449  */
450  void extend(EqrelIndex* otherIndex) {
451  this->data.extend(otherIndex->data);
452  }
453 };
454 
455 } // namespace souffle::interpreter
souffle::interpreter::Order::getOrder
const AttributeOrder & getOrder() const
Definition: Index.h:124
souffle::interpreter::Index< 0, Structure >::Tuple
typename souffle::Tuple< RamDomain, 0 > Tuple
Definition: Index.h:320
souffle::interpreter::Order::create
static Order create(size_t arity)
Definition: Index.h:66
souffle::interpreter::Index::View::data
const Data & data
Definition: Index.h:174
souffle::interpreter::Order::operator==
bool operator==(const Order &other) const
Definition: Index.h:128
souffle::interpreter::Order::operator!=
bool operator!=(const Order &other) const
Definition: Index.h:132
souffle::range
A utility class enabling representation of ranges by pairing two iterator instances marking lower and...
Definition: ContainerUtil.h:313
souffle::interpreter::ViewWrapper::~ViewWrapper
virtual ~ViewWrapper()=default
souffle::interpreter::Order::valid
bool valid() const
Determines whether this order is a valid order.
Definition: Index.h:82
souffle::interpreter::EqrelIndex
For EqrelIndex we do inheritence since EqrelIndex only diff with one extra function.
Definition: Index.h:444
souffle::interpreter::Index::View::range
souffle::range< iterator > range(const Tuple &low, const Tuple &high)
Obtains a pair of iterators representing the given range within this index.
Definition: Index.h:190
souffle::interpreter::Index::empty
bool empty() const
Tests whether this index is empty or not.
Definition: Index.h:221
low
d d low
Definition: htmlJsChartistMin.h:15
souffle::interpreter::operator<<
std::ostream & operator<<(std::ostream &out, const Order &order)
Definition: Index.h:137
high
d high
Definition: htmlJsChartistMin.h:15
souffle::interpreter::Index::contains
bool contains(const Tuple &tuple) const
Tests whether the given tuple is present in this index or not.
Definition: Index.h:251
souffle::interpreter::Index::Arity
static constexpr size_t Arity
Definition: Index.h:154
MiscUtil.h
souffle::interpreter::Index< 0, Structure >::iterator::dummy
const Tuple dummy
Definition: Index.h:332
j
var j
Definition: htmlJsChartistMin.h:15
souffle::interpreter::Order
An order to be enforced for storing tuples within indexes.
Definition: Index.h:48
souffle::interpreter::ViewWrapper
A dummy wrapper for indexViews.
Definition: Index.h:144
souffle::EquivalenceRelation::extend
void extend(const EquivalenceRelation< TupleType > &other)
Extend this relation with another relation, expanding this equivalence relation The supplied relation...
Definition: EquivalenceRelation.h:152
souffle::interpreter::Order::operator[]
Attribute operator[](const size_t idx) const
Definition: Index.h:136
souffle::interpreter::Index::scan
souffle::range< iterator > scan() const
Returns a pair of iterators covering the entire index content.
Definition: Index.h:265
souffle::interpreter::Order::Order
Order()=default
souffle::interpreter
Definition: BrieIndex.cpp:22
souffle::interpreter::Index
An index is an abstraction of a data structure.
Definition: Index.h:152
souffle::interpreter::Index::end
iterator end() const
Definition: Index.h:207
souffle::interpreter::Order::AttributeOrder
std::vector< Attribute > AttributeOrder
Definition: Index.h:56
UnionFind.h
souffle::interpreter::Index::Hints
typename Data::operation_hints Hints
Definition: Index.h:158
i
size_t i
Definition: json11.h:663
ContainerUtil.h
souffle::interpreter::Order::operator<<
friend std::ostream & operator<<(std::ostream &out, const Order &order)
Definition: Index.h:137
souffle::interpreter::Index::View::hints
Hints hints
Definition: Index.h:173
souffle::join
detail::joined_sequence< Iter, Printer > join(const Iter &a, const Iter &b, const std::string &sep, const Printer &p)
Creates an object to be forwarded to some output stream for printing sequences of elements interspers...
Definition: StreamUtil.h:175
souffle::interpreter::Index::clear
void clear()
Clears the content of this index, turning it empty.
Definition: Index.h:307
souffle::interpreter::Order::order
AttributeOrder order
Definition: Index.h:57
souffle::interpreter::Index::Tuple
typename souffle::Tuple< RamDomain, Arity > Tuple
Definition: Index.h:156
souffle::interpreter::Index< 0, Structure >::View::data
const std::atomic< bool > & data
Definition: Index.h:366
souffle::interpreter::Order::decode
Tuple< RamDomain, Arity > decode(const Tuple< RamDomain, Arity > &entry) const
Decode the tuple by order.
Definition: Index.h:116
souffle::Tuple
std::array< A, N > Tuple
Definition: RamTypes.h:36
souffle::interpreter::Index::insert
bool insert(const Tuple &tuple)
Inserts a tuple into this index.
Definition: Index.h:235
souffle::interpreter::Index::iterator
typename Data::iterator iterator
Definition: Index.h:157
EquivalenceRelation.h
souffle::interpreter::EqrelIndex::extend
void extend(EqrelIndex *otherIndex)
Extend another index.
Definition: Index.h:456
souffle::interpreter::Index::size
size_t size() const
Obtains the number of elements stored in this index.
Definition: Index.h:228
souffle::interpreter::Index::Data
Structure< Arity > Data
Definition: Index.h:155
souffle::interpreter::Order::size
size_t size() const
Definition: Index.h:75
souffle::interpreter::Index::getOrder
Order getOrder() const
Obtains the lex order of this index.
Definition: Index.h:214
souffle::interpreter::Index::createView
View createView()
Requests the creation of a view on this index.
Definition: Index.h:199
souffle::interpreter::Index::View
A view on a relation caching local access patterns (not thread safe!).
Definition: Index.h:172
souffle::interpreter::Index::partitionScan
std::vector< souffle::range< iterator > > partitionScan(int partitionCount) const
Retruns a partitioned list of iterators for parallel computation.
Definition: Index.h:279
std
Definition: Brie.h:3053
RamTypes.h
souffle::interpreter::Index::View::View
View(const Data &data)
Definition: Index.h:177
StreamUtil.h
souffle::interpreter::Index::order
Order order
Definition: Index.h:163
souffle::interpreter::Index::range
souffle::range< iterator > range(const Tuple &low, const Tuple &high) const
Returns a pair of iterators covering elements in the range [low,high)
Definition: Index.h:272
souffle::interpreter::Index::partitionRange
std::vector< souffle::range< iterator > > partitionRange(const Tuple &low, const Tuple &high, int partitionCount) const
Returns a partitioned list of iterators coving elements in range [low, high].
Definition: Index.h:292
souffle::interpreter::Index::Index
Index(Order order)
Definition: Index.h:160
souffle::interpreter::Index::begin
iterator begin() const
Definition: Index.h:203
souffle::interpreter::Index::data
Data data
Definition: Index.h:164
Util.h
souffle::interpreter::Order::Attribute
uint32_t Attribute
Definition: Index.h:55
souffle::EquivalenceRelation
Definition: EquivalenceRelation.h:50
souffle::tuple
Defines a tuple for the OO interface such that relations with varying columns can be accessed.
Definition: SouffleInterface.h:443
souffle::interpreter::Index::View::contains
bool contains(const Tuple &entry)
Tests whether the given entry is contained in this index.
Definition: Index.h:180
souffle::interpreter::Order::encode
Tuple< RamDomain, Arity > encode(const Tuple< RamDomain, Arity > &entry) const
Encode the tuple with order.
Definition: Index.h:104