souffle  2.0.2-371-g6315b36
Public Member Functions
souffle::synthesiser::IndirectRelation Class Reference

#include <Relation.h>

Inheritance diagram for souffle::synthesiser::IndirectRelation:
Inheritance graph
Collaboration diagram for souffle::synthesiser::IndirectRelation:
Collaboration graph

Public Member Functions

void computeIndices () override
 Generate index set for a indirect indexed relation. More...
 
void generateTypeStruct (std::ostream &out) override
 Generate type struct of a indirect indexed relation. More...
 
std::string getTypeName () override
 Generate type name of a indirect indexed relation. More...
 
 IndirectRelation (const ram::Relation &ramRel, const MinIndexSelection &indexSet, bool isProvenance)
 
- Public Member Functions inherited from souffle::ram::Relation
Relationclone () const override
 Create a clone (i.e. More...
 
unsigned getArity () const
 Get arity of relation. More...
 
const std::vector< std::string > & getAttributeNames () const
 Get attribute names. More...
 
const std::vector< std::string > & getAttributeTypes () const
 Get attribute types. More...
 
unsigned getAuxiliaryArity () const
 Get number of auxiliary attributes. More...
 
const std::string & getName () const
 Get name. More...
 
RelationRepresentation getRepresentation () const
 Relation representation type. More...
 
bool isNullary () const
 Is nullary relation. More...
 
bool isTemp () const
 Is temporary relation (for semi-naive evaluation) More...
 
bool operator< (const Relation &other) const
 Compare two relations via their name. More...
 
 Relation (std::string name, size_t arity, size_t auxiliaryArity, std::vector< std::string > attributeNames, std::vector< std::string > attributeTypes, RelationRepresentation representation)
 
- Public Member Functions inherited from souffle::ram::Node
virtual void apply (const NodeMapper &)
 Apply the mapper to all child nodes. More...
 
virtual std::vector< const Node * > getChildNodes () const
 Obtain list of all embedded child nodes. More...
 
bool operator!= (const Node &other) const
 Inequality check for two RAM nodes. More...
 
bool operator== (const Node &other) const
 Equivalence check for two RAM nodes. More...
 
virtual void rewrite (const Node *oldNode, Own< Node > newNode)
 Rewrite a child node. More...
 
virtual ~Node ()=default
 

Additional Inherited Members

- Protected Member Functions inherited from souffle::ram::Relation
bool equal (const Node &node) const override
 Equality check for two RAM nodes. More...
 
void print (std::ostream &out) const override
 Print RAM node. More...
 
- Protected Attributes inherited from souffle::ram::Relation
const size_t arity
 Arity, i.e., number of attributes. More...
 
const std::vector< std::string > attributeNames
 Name of attributes. More...
 
const std::vector< std::string > attributeTypes
 Type of attributes. More...
 
const size_t auxiliaryArity
 Number of auxiliary attributes (e.g. More...
 
const std::string name
 Name of relation. More...
 
const RelationRepresentation representation
 Data-structure representation. More...
 

Detailed Description

Definition at line 134 of file Relation.h.

Constructor & Destructor Documentation

◆ IndirectRelation()

souffle::synthesiser::IndirectRelation::IndirectRelation ( const ram::Relation ramRel,
const MinIndexSelection indexSet,
bool  isProvenance 
)
inline

Definition at line 136 of file Relation.h.

137  : Relation(ramRel, indexSet, isProvenance) {}

Member Function Documentation

◆ computeIndices()

void souffle::synthesiser::IndirectRelation::computeIndices ( )
override

Generate index set for a indirect indexed relation.

Definition at line 513 of file Relation.cpp.

513  {
514  assert(!isProvenance && "indirect indexes cannot used for provenance");
515 
516  // Generate and set indices
517  MinIndexSelection::OrderCollection inds = indices.getAllOrders();
518 
519  // generate a full index if no indices exist
520  assert(!inds.empty() && "no full index in relation");
521 
522  // check for full index
523  for (size_t i = 0; i < inds.size(); i++) {
524  auto& ind = inds[i];
525  if (ind.size() == getArity()) {
526  masterIndex = i;
527  break;
528  }
529  }
530  assert(masterIndex < inds.size() && "no full index in relation");
531  computedIndices = inds;
532 }

References i.

◆ generateTypeStruct()

void souffle::synthesiser::IndirectRelation::generateTypeStruct ( std::ostream &  out)
override

Generate type struct of a indirect indexed relation.

Definition at line 559 of file Relation.cpp.

559  {
560  size_t arity = getArity();
561  const auto& inds = getIndices();
562  auto types = relation.getAttributeTypes();
563  size_t numIndexes = inds.size();
564  std::map<MinIndexSelection::LexOrder, int> indexToNumMap;
565 
566  // struct definition
567  out << "struct " << getTypeName() << " {\n";
568  out << "static constexpr Relation::arity_type Arity = " << arity << ";\n";
569 
570  // stored tuple type
571  out << "using t_tuple = Tuple<RamDomain, " << arity << ">;\n";
572 
573  // table and lock required for storing actual data for indirect indices
574  out << "Table<t_tuple> dataTable;\n";
575  out << "Lock insert_lock;\n";
576 
577  // btree types
578  for (size_t i = 0; i < inds.size(); i++) {
579  auto ind = inds[i];
580 
581  if (i < getMinIndexSelection().getAllOrders().size()) {
582  indexToNumMap[getMinIndexSelection().getAllOrders()[i]] = i;
583  }
584 
585  std::vector<std::string> typecasts;
586  typecasts.reserve(types.size());
587 
588  for (auto type : types) {
589  switch (type[0]) {
590  case 'f': typecasts.push_back("ramBitCast<RamFloat>"); break;
591  case 'u': typecasts.push_back("ramBitCast<RamUnsigned>"); break;
592  default: typecasts.push_back("ramBitCast<RamSigned>");
593  }
594  }
595 
596  std::string comparator = "t_comparator_" + std::to_string(i);
597 
598  out << "struct " << comparator << "{\n";
599  out << " int operator()(const t_tuple *a, const t_tuple *b) const {\n";
600  out << " return ";
601  std::function<void(size_t)> gencmp = [&](size_t i) {
602  size_t attrib = ind[i];
603  const auto& typecast = typecasts[attrib];
604  out << "(" << typecast << "((*a)[" << attrib << "]) <" << typecast << " ((*b)[" << attrib
605  << "])) ? -1 : ((" << typecast << "((*a)[" << attrib << "]) > " << typecast << "((*b)["
606  << attrib << "])) ? 1 :(";
607  if (i + 1 < ind.size()) {
608  gencmp(i + 1);
609  } else {
610  out << "0";
611  }
612  out << "))";
613  };
614  gencmp(0);
615  out << ";\n }\n";
616  out << "bool less(const t_tuple *a, const t_tuple *b) const {\n";
617  out << " return ";
618  std::function<void(size_t)> genless = [&](size_t i) {
619  size_t attrib = ind[i];
620  const auto& typecast = typecasts[attrib];
621  out << typecast << " ((*a)[" << attrib << "]) < " << typecast << "((*b)[" << attrib << "])";
622  if (i + 1 < ind.size()) {
623  out << "|| (" << typecast << "((*a)[" << attrib << "]) == " << typecast << "((*b)[" << attrib
624  << "]) && (";
625  genless(i + 1);
626  out << "))";
627  }
628  };
629  genless(0);
630  out << ";\n }\n";
631  out << "bool equal(const t_tuple *a, const t_tuple *b) const {\n";
632  out << "return ";
633  std::function<void(size_t)> geneq = [&](size_t i) {
634  size_t attrib = ind[i];
635  const auto& typecast = typecasts[attrib];
636  out << typecast << "((*a)[" << attrib << "]) == " << typecast << "((*b)[" << attrib << "])";
637  if (i + 1 < ind.size()) {
638  out << "&&";
639  geneq(i + 1);
640  }
641  };
642  geneq(0);
643  out << ";\n }\n";
644  out << "};\n";
645 
646  if (ind.size() == arity) {
647  out << "using t_ind_" << i << " = btree_set<const t_tuple*," << comparator << ">;\n";
648  } else {
649  out << "using t_ind_" << i << " = btree_multiset<const t_tuple*," << comparator << ">;\n";
650  }
651 
652  out << "t_ind_" << i << " ind_" << i << ";\n";
653  }
654 
655  // typedef deref iterators
656  for (size_t i = 0; i < numIndexes; i++) {
657  out << "using iterator_" << i << " = IterDerefWrapper<typename t_ind_" << i << "::iterator>;\n";
658  }
659  out << "using iterator = iterator_" << masterIndex << ";\n";
660 
661  // Create a struct storing the context hints for each index
662  out << "struct context {\n";
663  for (size_t i = 0; i < numIndexes; i++) {
664  out << "t_ind_" << i << "::operation_hints hints_" << i << "_lower;\n";
665  out << "t_ind_" << i << "::operation_hints hints_" << i << "_upper;\n";
666  }
667  out << "};\n";
668  out << "context createContext() { return context(); }\n";
669 
670  // insert methods
671  out << "bool insert(const t_tuple& t) {\n";
672  out << "context h;\n";
673  out << "return insert(t, h);\n";
674  out << "}\n";
675 
676  out << "bool insert(const t_tuple& t, context& h) {\n";
677  out << "const t_tuple* masterCopy = nullptr;\n";
678  out << "{\n";
679  out << "auto lease = insert_lock.acquire();\n";
680  out << "if (contains(t, h)) return false;\n";
681  out << "masterCopy = &dataTable.insert(t);\n";
682  out << "ind_" << masterIndex << ".insert(masterCopy, h.hints_" << masterIndex << "_lower);\n";
683  out << "}\n";
684  for (size_t i = 0; i < numIndexes; i++) {
685  if (i != masterIndex) {
686  out << "ind_" << i << ".insert(masterCopy, h.hints_" << i << "_lower"
687  << ");\n";
688  }
689  }
690  out << "return true;\n";
691  out << "}\n";
692 
693  out << "bool insert(const RamDomain* ramDomain) {\n";
694  out << "RamDomain data[" << arity << "];\n";
695  out << "std::copy(ramDomain, ramDomain + " << arity << ", data);\n";
696  out << "const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);\n";
697  out << "context h;\n";
698  out << "return insert(tuple, h);\n";
699  out << "}\n"; // end of insert(RamDomain*)
700 
701  std::vector<std::string> decls;
702  std::vector<std::string> params;
703  for (size_t i = 0; i < arity; i++) {
704  decls.push_back("RamDomain a" + std::to_string(i));
705  params.push_back("a" + std::to_string(i));
706  }
707  out << "bool insert(" << join(decls, ",") << ") {\n";
708  out << "RamDomain data[" << arity << "] = {" << join(params, ",") << "};\n";
709  out << "return insert(data);\n";
710  out << "}\n"; // end of insert(RamDomain x1, RamDomain x2, ...)
711 
712  // contains methods
713  out << "bool contains(const t_tuple& t, context& h) const {\n";
714  out << "return ind_" << masterIndex << ".contains(&t, h.hints_" << masterIndex << "_lower"
715  << ");\n";
716  out << "}\n";
717 
718  out << "bool contains(const t_tuple& t) const {\n";
719  out << "context h;\n";
720  out << "return contains(t, h);\n";
721  out << "}\n";
722 
723  // size method
724  out << "std::size_t size() const {\n";
725  out << "return ind_" << masterIndex << ".size();\n";
726  out << "}\n";
727 
728  // find methods
729  out << "iterator find(const t_tuple& t, context& h) const {\n";
730  out << "return ind_" << masterIndex << ".find(&t, h.hints_" << masterIndex << "_lower"
731  << ");\n";
732  out << "}\n";
733 
734  out << "iterator find(const t_tuple& t) const {\n";
735  out << "context h;\n";
736  out << "return find(t, h);\n";
737  out << "}\n";
738 
739  // empty lowerUpperRange method
740  out << "range<iterator> lowerUpperRange_0(const t_tuple& lower, const t_tuple& upper, context& h) const "
741  "{\n";
742 
743  out << "return range<iterator>(ind_" << masterIndex << ".begin(),ind_" << masterIndex << ".end());\n";
744  out << "}\n";
745 
746  out << "range<iterator> lowerUpperRange_0(const t_tuple& lower, const t_tuple& upper) const {\n";
747 
748  out << "return range<iterator>(ind_" << masterIndex << ".begin(),ind_" << masterIndex << ".end());\n";
749  out << "}\n";
750 
751  // lowerUpperRange methods for each pattern which is used to search this relation
752  for (auto search : getMinIndexSelection().getSearches()) {
753  auto& lexOrder = getMinIndexSelection().getLexOrder(search);
754  size_t indNum = indexToNumMap[lexOrder];
755 
756  out << "range<iterator_" << indNum << "> lowerUpperRange_" << search;
757  out << "(const t_tuple& lower, const t_tuple& upper, context& h) const {\n";
758 
759  // count size of search pattern
760  size_t eqSize = 0;
761  for (size_t column = 0; column < arity; column++) {
762  if (search[column] == analysis::AttributeConstraint::Equal) {
763  eqSize++;
764  }
765  }
766 
767  out << "t_comparator_" << indNum << " comparator;\n";
768  out << "int cmp = comparator(&lower, &upper);\n";
769 
770  // use the more efficient find() method if the search pattern is full
771  if (eqSize == arity) {
772  // if lower == upper we can just do a find
773  out << "if (cmp == 0) {\n";
774  out << " auto pos = find(lower, h);\n";
775  out << " auto fin = end();\n";
776  out << " if (pos != fin) {fin = pos; ++fin;}\n";
777  out << " return make_range(pos, fin);\n";
778  out << "}\n";
779  }
780  // if lower > upper then we have an empty range
781  out << "if (cmp > 0) {\n";
782  out << " return range<iterator_" << indNum << ">(ind_" << indNum << ".end(), ind_" << indNum
783  << ".end());\n";
784  out << "}\n";
785 
786  // otherwise do the default method
787  out << "return range<iterator_" << indNum << ">(ind_" << indNum << ".lower_bound(&lower, h.hints_"
788  << indNum << "_lower"
789  << "), ind_" << indNum << ".upper_bound(&upper, h.hints_" << indNum << "_upper"
790  << "));\n";
791 
792  out << "}\n";
793 
794  out << "range<iterator_" << indNum << "> lowerUpperRange_" << search;
795  out << "(const t_tuple& lower, const t_tuple& upper) const {\n";
796 
797  out << "context h;\n";
798  out << "return lowerUpperRange_" << search << "(lower, upper, h);\n";
799  out << "}\n";
800  }
801 
802  // empty method
803  out << "bool empty() const {\n";
804  out << "return ind_" << masterIndex << ".empty();\n";
805  out << "}\n";
806 
807  // partition method
808  out << "std::vector<range<iterator>> partition() const {\n";
809  out << "std::vector<range<iterator>> res;\n";
810  out << "for (const auto& cur : ind_" << masterIndex << ".getChunks(400)) {\n";
811  out << " res.push_back(make_range(derefIter(cur.begin()), derefIter(cur.end())));\n";
812  out << "}\n";
813  out << "return res;\n";
814  out << "}\n";
815 
816  // purge method
817  out << "void purge() {\n";
818  for (size_t i = 0; i < numIndexes; i++) {
819  out << "ind_" << i << ".clear();\n";
820  }
821  out << "dataTable.clear();\n";
822  out << "}\n";
823 
824  // begin and end iterators
825  out << "iterator begin() const {\n";
826  out << "return ind_" << masterIndex << ".begin();\n";
827  out << "}\n";
828 
829  out << "iterator end() const {\n";
830  out << "return ind_" << masterIndex << ".end();\n";
831  out << "}\n";
832 
833  // printStatistics method
834  out << "void printStatistics(std::ostream& o) const {\n";
835  for (size_t i = 0; i < numIndexes; i++) {
836  out << "o << \" arity " << arity << " indirect b-tree index " << i << " lex-order " << inds[i]
837  << "\\n\";\n";
838  out << "ind_" << i << ".printStats(o);\n";
839  }
840  out << "}\n";
841 
842  // end struct
843  out << "};\n";
844 }

References i, souffle::join(), relation, TCB_SPAN_NAMESPACE_NAME::detail::size(), and types.

Here is the call graph for this function:

◆ getTypeName()

std::string souffle::synthesiser::IndirectRelation::getTypeName ( )
override

Generate type name of a indirect indexed relation.

Definition at line 535 of file Relation.cpp.

535  {
536  // collect all attributes used in the lex-order
537  std::unordered_set<uint32_t> attributesUsed;
538  for (auto& ind : getIndices()) {
539  for (auto& attr : ind) {
540  attributesUsed.insert(attr);
541  }
542  }
543 
544  std::stringstream res;
545  res << "t_btree_" << getTypeAttributeString(relation.getAttributeTypes(), attributesUsed);
546 
547  for (auto& ind : getIndices()) {
548  res << "__" << join(ind, "_");
549  }
550 
551  for (auto& search : getMinIndexSelection().getSearches()) {
552  res << "__" << search;
553  }
554 
555  return res.str();
556 }

References souffle::join(), and relation.

Here is the call graph for this function:

The documentation for this class was generated from the following files:
souffle::interpreter::comparator
typename index_utils::get_full_index< Arity >::type::comparator comparator
Definition: Util.h:216
TCB_SPAN_NAMESPACE_NAME::detail::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.h:198
souffle::ram::Relation::arity
const size_t arity
Arity, i.e., number of attributes.
Definition: Relation.h:139
souffle::synthesiser::IndirectRelation::getTypeName
std::string getTypeName() override
Generate type name of a indirect indexed relation.
Definition: Relation.cpp:535
relation
Relation & relation
Definition: Reader.h:130
types
std::vector< Own< ast::Type > > types
Definition: ComponentInstantiation.cpp:64
souffle::ram::Relation::Relation
Relation(std::string name, size_t arity, size_t auxiliaryArity, std::vector< std::string > attributeNames, std::vector< std::string > attributeTypes, RelationRepresentation representation)
Definition: Relation.h:42
souffle::ram::Relation::getArity
unsigned getArity() const
Get arity of relation.
Definition: Relation.h:86
i
size_t i
Definition: json11.h:663
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::ram::analysis::MinIndexSelection::OrderCollection
std::vector< LexOrder > OrderCollection
Definition: Index.h:217
std::type
ElementType type
Definition: span.h:640