From 20ec1b4948ffc8d6b6255bc03489ab60f5cdb6fe Mon Sep 17 00:00:00 2001 From: Julien Henry Date: Mon, 6 Nov 2023 03:30:36 -0500 Subject: [PATCH 01/18] implement automatic lubs in RAM --- src/RelationTag.h | 2 - src/ast/Attribute.cpp | 12 +- src/ast/Attribute.h | 7 + src/ast/Relation.h | 9 + src/ast/transform/SemanticChecker.cpp | 11 +- src/ast2ram/ClauseTranslator.h | 2 + src/ast2ram/provenance/UnitTranslator.cpp | 27 +- src/ast2ram/seminaive/UnitTranslator.cpp | 256 +++++++++++++++--- src/ast2ram/seminaive/UnitTranslator.h | 3 +- src/ast2ram/utility/Utils.cpp | 8 + src/ast2ram/utility/Utils.h | 3 + src/include/souffle/datastructure/BTree.h | 26 +- .../souffle/datastructure/BTreeDelete.h | 26 +- src/include/souffle/datastructure/BTreeUtil.h | 4 +- src/interpreter/BTreeDeleteIndex.cpp | 13 +- src/interpreter/BTreeIndex.cpp | 14 +- src/interpreter/Engine.cpp | 108 ++++---- src/interpreter/EqrelIndex.cpp | 3 +- src/interpreter/Index.h | 25 +- src/interpreter/Node.h | 25 +- src/interpreter/ProvenanceIndex.cpp | 14 +- src/interpreter/Relation.h | 31 +-- src/interpreter/Util.h | 222 ++++++++------- .../tests/interpreter_relation_test.cpp | 16 +- src/interpreter/tests/ram_relation_test.cpp | 14 +- src/parser/parser.yy | 5 + src/parser/scanner.ll | 1 + src/ram/Relation.h | 21 +- .../tests/ram_condition_equal_clone_test.cpp | 10 +- .../tests/ram_relation_equal_clone_test.cpp | 4 +- .../tests/ram_statement_equal_clone_test.cpp | 38 +-- src/ram/transform/MakeIndex.cpp | 26 +- src/ram/transform/MakeIndex.h | 7 +- src/synthesiser/Relation.cpp | 70 +++-- src/synthesiser/Relation.h | 7 +- src/synthesiser/Synthesiser.cpp | 2 +- tests/interface/CMakeLists.txt | 2 + tests/interface/lub/CMakeLists.txt | 43 +++ tests/interface/lub/Values.csv | 6 + tests/interface/lub/functors.cpp | 40 +++ tests/interface/lub/lub.dl | 135 +++++++++ tests/interface/lub/lub.err | 0 tests/interface/lub/lub.out | 0 tests/semantic/leq/leq.dl | 36 ++- 44 files changed, 909 insertions(+), 425 deletions(-) create mode 100644 tests/interface/lub/CMakeLists.txt create mode 100644 tests/interface/lub/Values.csv create mode 100644 tests/interface/lub/functors.cpp create mode 100644 tests/interface/lub/lub.dl create mode 100644 tests/interface/lub/lub.err create mode 100644 tests/interface/lub/lub.out diff --git a/src/RelationTag.h b/src/RelationTag.h index 5a850972533..c6d51ca00a3 100644 --- a/src/RelationTag.h +++ b/src/RelationTag.h @@ -58,7 +58,6 @@ enum class RelationRepresentation { BTREE, // use btree data-structure BTREE_DELETE, // use btree_delete data-structure EQREL, // use union data-structure - PROVENANCE, // use custom btree data-structure with provenance extras INFO, // info relation for provenance }; @@ -168,7 +167,6 @@ inline std::ostream& operator<<(std::ostream& os, RelationRepresentation represe case RelationRepresentation::BTREE_DELETE: return os << "btree_delete"; case RelationRepresentation::BRIE: return os << "brie"; case RelationRepresentation::EQREL: return os << "eqrel"; - case RelationRepresentation::PROVENANCE: return os << "provenance"; case RelationRepresentation::INFO: return os << "info"; case RelationRepresentation::DEFAULT: return os; } diff --git a/src/ast/Attribute.cpp b/src/ast/Attribute.cpp index a06fdab5d8e..0b698d7c94e 100644 --- a/src/ast/Attribute.cpp +++ b/src/ast/Attribute.cpp @@ -14,7 +14,10 @@ namespace souffle::ast { Attribute::Attribute(std::string n, QualifiedName t, SrcLocation loc) - : Node(std::move(loc)), name(std::move(n)), typeName(std::move(t)) {} + : Node(std::move(loc)), name(std::move(n)), typeName(std::move(t)), merger(std::nullopt) {} + +Attribute::Attribute(std::string n, QualifiedName t, std::optional merger, SrcLocation loc) + : Node(std::move(loc)), name(std::move(n)), typeName(std::move(t)), merger(std::move(merger)) {} void Attribute::setTypeName(QualifiedName name) { typeName = std::move(name); @@ -22,15 +25,18 @@ void Attribute::setTypeName(QualifiedName name) { void Attribute::print(std::ostream& os) const { os << name << ":" << typeName; + if (merger) { + os << ":" << *merger; + } } bool Attribute::equal(const Node& node) const { const auto& other = asAssert(node); - return name == other.name && typeName == other.typeName; + return name == other.name && typeName == other.typeName && merger == other.merger; } Attribute* Attribute::cloning() const { - return new Attribute(name, typeName, getSrcLoc()); + return new Attribute(name, typeName, merger, getSrcLoc()); } } // namespace souffle::ast diff --git a/src/ast/Attribute.h b/src/ast/Attribute.h index ecea916c63f..66e2f6a95c7 100644 --- a/src/ast/Attribute.h +++ b/src/ast/Attribute.h @@ -35,6 +35,7 @@ namespace souffle::ast { class Attribute : public Node { public: Attribute(std::string n, QualifiedName t, SrcLocation loc = {}); + Attribute(std::string n, QualifiedName t, std::optional merger, SrcLocation loc = {}); /** Return attribute name */ const std::string& getName() const { @@ -49,6 +50,10 @@ class Attribute : public Node { /** Set type name */ void setTypeName(QualifiedName name); + const std::optional& getMerger() const { + return merger; + } + protected: void print(std::ostream& os) const override; @@ -63,6 +68,8 @@ class Attribute : public Node { /** Type name */ QualifiedName typeName; + + std::optional merger; }; } // namespace souffle::ast diff --git a/src/ast/Relation.h b/src/ast/Relation.h index 4fb1aade201..c90a89065b2 100644 --- a/src/ast/Relation.h +++ b/src/ast/Relation.h @@ -54,6 +54,15 @@ class Relation : public Node { return attributes.size(); } + /** Return the arity of this relation */ + std::size_t getAuxiliaryArity() const { + std::size_t arity = 0; + for (const auto& a : attributes) { + arity += a->getMerger() ? 1 : 0; + } + return arity; + } + /** Set relation attributes */ void setAttributes(VecOwn attrs); diff --git a/src/ast/transform/SemanticChecker.cpp b/src/ast/transform/SemanticChecker.cpp index 0e076159130..8465ac60cd7 100644 --- a/src/ast/transform/SemanticChecker.cpp +++ b/src/ast/transform/SemanticChecker.cpp @@ -244,10 +244,10 @@ void SemanticCheckerImpl::checkAtom(const Clause& parent, const Atom& atom) { report.addError("Undefined relation " + toString(atom.getQualifiedName()), atom.getSrcLoc()); return; } - - if (r->getArity() != atom.getArity()) { + std::size_t arity = r->getArity(); + if (arity != atom.getArity()) { report.addError("Mismatching arity of relation " + toString(atom.getQualifiedName()) + " (expected " + - toString(r->getArity()) + ", got " + toString(atom.getArity()) + ")", + toString(arity) + ", got " + toString(atom.getArity()) + ")", atom.getSrcLoc()); } @@ -660,9 +660,10 @@ void SemanticCheckerImpl::checkFunctorDeclaration(const FunctorDeclaration& decl void SemanticCheckerImpl::checkRelationDeclaration(const Relation& relation) { const auto& attributes = relation.getAttributes(); - assert(attributes.size() == relation.getArity() && "mismatching attribute size and arity"); + const std::size_t arity = relation.getArity(); + assert(attributes.size() == arity && "mismatching attribute size and arity"); - for (std::size_t i = 0; i < relation.getArity(); i++) { + for (std::size_t i = 0; i < arity; i++) { Attribute* attr = attributes[i]; checkType(*attr); diff --git a/src/ast2ram/ClauseTranslator.h b/src/ast2ram/ClauseTranslator.h index 93021f514f6..d157804276d 100644 --- a/src/ast2ram/ClauseTranslator.h +++ b/src/ast2ram/ClauseTranslator.h @@ -39,6 +39,8 @@ class TranslatorContext; enum TranslationMode { DEFAULT, + Auxiliary, + // Subsumptive clauses // // R(x0) <= R(x1) :- body. diff --git a/src/ast2ram/provenance/UnitTranslator.cpp b/src/ast2ram/provenance/UnitTranslator.cpp index 6c105d882d7..f8c9ed02462 100644 --- a/src/ast2ram/provenance/UnitTranslator.cpp +++ b/src/ast2ram/provenance/UnitTranslator.cpp @@ -24,12 +24,14 @@ #include "ast2ram/utility/TranslatorContext.h" #include "ast2ram/utility/Utils.h" #include "ast2ram/utility/ValueIndex.h" +#include "ram/AbstractOperator.h" #include "ram/Call.h" #include "ram/DebugInfo.h" #include "ram/ExistenceCheck.h" #include "ram/Expression.h" #include "ram/Filter.h" #include "ram/Insert.h" +#include "ram/IntrinsicOperator.h" #include "ram/LogRelationTimer.h" #include "ram/MergeExtend.h" #include "ram/Negation.h" @@ -69,18 +71,14 @@ Own UnitTranslator::generateProgram(const ast::TranslationUnit& t Own UnitTranslator::createRamRelation( const ast::Relation* baseRelation, std::string ramRelationName) const { - auto arity = baseRelation->getArity(); - // All relations in a provenance program should have a provenance data structure - auto representation = RelationRepresentation::PROVENANCE; + auto relation = seminaive::UnitTranslator::createRamRelation(baseRelation, ramRelationName); - // Add in base relation information - std::vector attributeNames; - std::vector attributeTypeQualifiers; - for (const auto& attribute : baseRelation->getAttributes()) { - attributeNames.push_back(attribute->getName()); - attributeTypeQualifiers.push_back(context->getAttributeTypeQualifier(attribute->getTypeName())); - } + std::size_t arity = relation->getArity(); + std::size_t auxiliaryArity = relation->getAuxiliaryArity(); + std::vector attributeNames = relation->getAttributeNames(); + std::vector attributeTypeQualifiers = relation->getAttributeTypes(); + VecOwn attributeMergers = clone(relation->getAttributeMergers()); // Add in provenance information attributeNames.push_back("@rule_number"); @@ -89,8 +87,12 @@ Own UnitTranslator::createRamRelation( attributeNames.push_back("@level_number"); attributeTypeQualifiers.push_back("i:number"); + ram::IntrinsicOperator minOperator(FunctorOp::MIN); + attributeMergers.push_back(clone(minOperator)); + attributeMergers.push_back(clone(minOperator)); + return mk( - ramRelationName, arity + 2, 2, attributeNames, attributeTypeQualifiers, representation); + ramRelationName, arity + 2, auxiliaryArity + 2, attributeNames, attributeTypeQualifiers, std::move(attributeMergers), relation->getRepresentation()); } std::string UnitTranslator::getInfoRelationName(const ast::Clause* clause) const { @@ -137,9 +139,10 @@ VecOwn UnitTranslator::createRamRelations(const std::vector attributeMerger; // Create the info relation ramRelations.push_back(mk(getInfoRelationName(clause), attributeNames.size(), 0, - attributeNames, attributeTypeQualifiers, RelationRepresentation::INFO)); + attributeNames, attributeTypeQualifiers, std::move(attributeMerger), RelationRepresentation::INFO)); } return ramRelations; diff --git a/src/ast2ram/seminaive/UnitTranslator.cpp b/src/ast2ram/seminaive/UnitTranslator.cpp index 07b4fd9104c..74dc5973067 100644 --- a/src/ast2ram/seminaive/UnitTranslator.cpp +++ b/src/ast2ram/seminaive/UnitTranslator.cpp @@ -20,12 +20,14 @@ #include "ast/Relation.h" #include "ast/SubsumptiveClause.h" #include "ast/TranslationUnit.h" +#include "ast/UserDefinedFunctor.h" #include "ast/analysis/TopologicallySortedSCCGraph.h" #include "ast/utility/Utils.h" #include "ast/utility/Visitor.h" #include "ast2ram/ClauseTranslator.h" #include "ast2ram/utility/TranslatorContext.h" #include "ast2ram/utility/Utils.h" +#include "ram/Aggregate.h" #include "ram/Assign.h" #include "ram/Call.h" #include "ram/Clear.h" @@ -60,7 +62,10 @@ #include "ram/Swap.h" #include "ram/TranslationUnit.h" #include "ram/TupleElement.h" +#include "ram/UndefValue.h" #include "ram/UnsignedConstant.h" +#include "ram/UserDefinedAggregator.h" +#include "ram/UserDefinedOperator.h" #include "ram/Variable.h" #include "ram/utility/Utils.h" #include "reports/DebugReport.h" @@ -113,7 +118,8 @@ Own UnitTranslator::generateNonRecursiveRelation(const ast::Rela } // Translate clause - Own rule = context->translateNonRecursiveClause(*clause); + TranslationMode mode = rel.getAuxiliaryArity() > 0 ? Auxiliary : DEFAULT; + Own rule = context->translateNonRecursiveClause(*clause, mode); // Add logging if (glb->config().has("profile")) { @@ -176,8 +182,16 @@ Own UnitTranslator::generateStratum(std::size_t scc) const { const auto* rel = *sccRelations.begin(); appendStmt(current, generateNonRecursiveRelation(*rel)); + // lub auxiliary arities using the @lub relation + if (rel->getAuxiliaryArity() > 0) { + std::string mainRelation = getConcreteRelationName(rel->getQualifiedName()); + std::string newRelation = getNewRelationName(rel->getQualifiedName()); + appendStmt(current, generateStratumLubSequence(*rel, newRelation, mainRelation)); + appendStmt(current, mk(newRelation)); + } + // issue delete sequence for non-recursive subsumptions - appendStmt(current, generateNonRecursiveDelete(sccRelations)); + appendStmt(current, generateNonRecursiveDelete(*rel)); } // Get all non-recursive relation statements @@ -404,50 +418,48 @@ VecOwn UnitTranslator::generateClauseVersions( return clauseVersions; } -Own UnitTranslator::generateNonRecursiveDelete(const ast::RelationSet& scc) const { +Own UnitTranslator::generateNonRecursiveDelete(const ast::Relation& rel) const { VecOwn code; // Generate code for non-recursive subsumption - for (const ast::Relation* rel : scc) { - if (!context->hasSubsumptiveClause(rel->getQualifiedName())) { + if (!context->hasSubsumptiveClause(rel.getQualifiedName())) { + return mk(std::move(code)); + } + + std::string mainRelation = getConcreteRelationName(rel.getQualifiedName()); + std::string deleteRelation = getDeleteRelationName(rel.getQualifiedName()); + + // Compute subsumptive deletions for non-recursive rules + for (auto clause : context->getProgram()->getClauses(rel)) { + if (!isA(clause)) { continue; } - std::string mainRelation = getConcreteRelationName(rel->getQualifiedName()); - std::string deleteRelation = getDeleteRelationName(rel->getQualifiedName()); - - // Compute subsumptive deletions for non-recursive rules - for (auto clause : context->getProgram()->getClauses(*rel)) { - if (!isA(clause)) { - continue; - } + // Translate subsumptive clause + Own rule = + context->translateNonRecursiveClause(*clause, SubsumeDeleteCurrentCurrent); - // Translate subsumptive clause - Own rule = - context->translateNonRecursiveClause(*clause, SubsumeDeleteCurrentCurrent); - - // Add logging for subsumptive clause - if (glb->config().has("profile")) { - const std::string& relationName = toString(rel->getQualifiedName()); - const auto& srcLocation = clause->getSrcLoc(); - const std::string clauseText = stringify(toString(*clause)); - const std::string logTimerStatement = - LogStatement::tNonrecursiveRule(relationName, srcLocation, clauseText); - rule = mk(std::move(rule), logTimerStatement, mainRelation); - } + // Add logging for subsumptive clause + if (glb->config().has("profile")) { + const std::string& relationName = toString(rel.getQualifiedName()); + const auto& srcLocation = clause->getSrcLoc(); + const std::string clauseText = stringify(toString(*clause)); + const std::string logTimerStatement = + LogStatement::tNonrecursiveRule(relationName, srcLocation, clauseText); + rule = mk(std::move(rule), logTimerStatement, mainRelation); + } - // Add debug info for subsumptive clause - std::ostringstream ds; - ds << toString(*clause) << "\nin file "; - ds << clause->getSrcLoc(); - rule = mk(std::move(rule), ds.str()); + // Add debug info for subsumptive clause + std::ostringstream ds; + ds << toString(*clause) << "\nin file "; + ds << clause->getSrcLoc(); + rule = mk(std::move(rule), ds.str()); - // Add subsumptive rule to result - appendStmt(code, std::move(rule)); - } - appendStmt(code, mk(generateEraseTuples(rel, mainRelation, deleteRelation), - mk(deleteRelation))); + // Add subsumptive rule to result + appendStmt(code, std::move(rule)); } + appendStmt(code, mk(generateEraseTuples(&rel, mainRelation, deleteRelation), + mk(deleteRelation))); return mk(std::move(code)); } @@ -459,11 +471,16 @@ Own UnitTranslator::generateStratumPreamble(const ast::RelationS std::string deltaRelation = getDeltaRelationName(rel->getQualifiedName()); std::string mainRelation = getConcreteRelationName(rel->getQualifiedName()); appendStmt(preamble, generateNonRecursiveRelation(*rel)); + // lub tuples using the @lub relation + if (rel->getAuxiliaryArity() > 0) { + std::string newRelation = getNewRelationName(rel->getQualifiedName()); + appendStmt(preamble, generateStratumLubSequence(*rel, newRelation, mainRelation)); + appendStmt(preamble, mk(newRelation)); + } + // Generate non recursive delete sequences for subsumptive rules + appendStmt(preamble, generateNonRecursiveDelete(*rel)); } - // Generate non recursive delete sequences for subsumptive rules - appendStmt(preamble, generateNonRecursiveDelete(scc)); - // Generate code for priming relation for (const ast::Relation* rel : scc) { std::string deltaRelation = getDeltaRelationName(rel->getQualifiedName()); @@ -503,7 +520,13 @@ Own UnitTranslator::generateStratumTableUpdates(const ast::Relat // swap new and and delta relation and clear new relation afterwards (if not a subsumptive relation) Own updateRelTable; - if (!context->hasSubsumptiveClause(rel->getQualifiedName())) { + if (rel->getAuxiliaryArity() > 0) { + updateRelTable =mk( + mk(deltaRelation), + generateStratumLubSequence(*rel, newRelation, deltaRelation), + generateMergeRelations(rel, mainRelation, deltaRelation) + ); + } else if (!context->hasSubsumptiveClause(rel->getQualifiedName())) { updateRelTable = mk(generateMergeRelations(rel, mainRelation, newRelation), mk(deltaRelation, newRelation), mk(newRelation)); } else { @@ -563,6 +586,127 @@ Own UnitTranslator::generateStratumLoopBody(const ast::RelationS return mk(std::move(loopBody)); } +/// assuming the @new() relation is populated with new tuples, generate RAM code +/// to populate the @delta() relation with the lubbed elements from @new() +Own UnitTranslator::generateStratumLubSequence(const ast::Relation& rel, const std::string& fromName, const std::string& toName) const { + VecOwn stmts; + assert(rel.getAuxiliaryArity() > 0); + + auto attributes = rel.getAttributes(); + std::string name = getConcreteRelationName(rel.getQualifiedName()); + //std::string deltaName = getDeltaRelationName(rel.getQualifiedName()); + std::string lubName = getLubRelationName(rel.getQualifiedName()); + //std::string newName = getNewRelationName(rel.getQualifiedName()); + + const std::size_t arity = rel.getArity(); + const std::size_t auxiliaryArity = rel.getAuxiliaryArity(); + + // Step 1 : populate @lub() from @new() + VecOwn values; + std::size_t firstAuxiliary = arity - auxiliaryArity; + for (std::size_t i = 0; i < arity; i++) { + if (i < firstAuxiliary) { + values.push_back(mk(0,i)); + } else { + values.push_back(mk(i-firstAuxiliary+1,0)); + } + } + Own op = mk(lubName, std::move(values)); + + for (std::size_t i = arity-1; i >= firstAuxiliary; i--) { + auto merger = attributes[i]->getMerger(); + assert(merger.has_value()); + ast::UserDefinedFunctor udf(merger.value()); + const auto typeAttributes = context->getFunctorParamTypeAtributes(udf); + const auto returnAttribute = context->getFunctorReturnTypeAttribute(udf); + bool stateful = context->isStatefulFunctor(udf); + std::size_t level = i-firstAuxiliary+1; + auto aggregator = mk(merger.value(), mk(0,i), typeAttributes, returnAttribute, stateful); + Own condition = mk(BinaryConstraintOp::NE, mk(level,i), mk(0,i)); + for (std::size_t j = 0; j < attributes.size(); j++) { + auto merger = attributes[j]->getMerger(); + if (merger) break; + condition = mk( + std::move(condition), + mk(BinaryConstraintOp::EQ, mk(level,j), mk(0,j)) + ); + } + op = mk(std::move(op), std::move(aggregator), fromName, + mk(level,i), std::move(condition), level); + } + + op = mk(fromName, 0, std::move(op)); + appendStmt(stmts, mk(std::move(op))); + + // clear @new() now that we no longer need it + appendStmt(stmts, mk(fromName)); + + // Step 2 : populate @delta() from @lub() for tuples that have to be lubbed with @concrete + + Own condition; + for (std::size_t i = 0; i < arity; i++) { + if (i < firstAuxiliary) { + values.push_back(mk(0,i)); + } else { + auto merger = attributes[i]->getMerger(); + assert(merger.has_value()); + ast::UserDefinedFunctor udf(merger.value()); + const auto typeAttributes = context->getFunctorParamTypeAtributes(udf); + const auto returnAttribute = context->getFunctorReturnTypeAttribute(udf); + bool stateful = true; // todo + VecOwn args; + args.push_back(mk(0,i)); + args.push_back(mk(1,i)); + auto lub = mk(merger.value(), typeAttributes, returnAttribute, stateful, std::move(args)); + auto cst = mk(BinaryConstraintOp::EQ, mk(1,i), clone(lub)); + if (condition) { + condition = mk(std::move(condition), std::move(cst)); + } else { + condition = std::move(cst); + } + values.push_back(std::move(lub)); + + + } + } + op = mk(toName, std::move(values)); + op = mk(mk(std::move(condition)), std::move(op)); + + for (std::size_t i = 0; i < arity - auxiliaryArity; i++) { + auto cst = mk(BinaryConstraintOp::EQ, mk(0,i), mk(1,i)); + if (condition) { + condition = mk(std::move(condition), std::move(cst)); + } else { + condition = std::move(cst); + } + } + op = mk(std::move(condition), std::move(op)); + op = mk(name, 1, std::move(op)); + op = mk(lubName, 0, std::move(op)); + appendStmt(stmts, mk(std::move(op))); + + // Step 3 : populate @delta() from @lub() for tuples that have nothing to lub in @concrete + for (std::size_t i = 0; i < arity; i++) { + values.push_back(mk(0,i)); + } + op = mk(toName, std::move(values)); + for (std::size_t i = 0; i < arity; i++) { + if (i < firstAuxiliary) { + values.push_back(mk(0,i)); + } else { + values.push_back(mk()); + } + } + op = mk(mk(mk(name, std::move(values))), std::move(op)); + op = mk(lubName, 0, std::move(op)); + + appendStmt(stmts, mk(std::move(op))); + + appendStmt(stmts, mk(lubName)); + + return mk(std::move(stmts)); +} + Own UnitTranslator::generateStratumExitSequence(const ast::RelationSet& scc) const { // Helper function to add a new term to a conjunctive condition auto addCondition = [&](Own& cond, Own term) { @@ -688,6 +832,10 @@ Own UnitTranslator::generateStoreRelation(const ast::Relation* r Own UnitTranslator::createRamRelation( const ast::Relation* baseRelation, std::string ramRelationName) const { auto arity = baseRelation->getArity(); + + bool mergeAuxiliary = (ramRelationName != getNewRelationName(baseRelation->getQualifiedName())); + + auto auxArity = mergeAuxiliary ? baseRelation->getAuxiliaryArity() : 0; auto representation = baseRelation->getRepresentation(); if (representation == RelationRepresentation::BTREE_DELETE && ramRelationName[0] == '@') { representation = RelationRepresentation::DEFAULT; @@ -695,13 +843,23 @@ Own UnitTranslator::createRamRelation( std::vector attributeNames; std::vector attributeTypeQualifiers; + VecOwn attributeMergers; for (const auto& attribute : baseRelation->getAttributes()) { attributeNames.push_back(attribute->getName()); attributeTypeQualifiers.push_back(context->getAttributeTypeQualifier(attribute->getTypeName())); + const auto merger = attribute->getMerger(); + if (mergeAuxiliary && merger) { + ast::UserDefinedFunctor udf(merger.value()); + const auto typeAttributes = context->getFunctorParamTypeAtributes(udf); + const auto returnAttribute = context->getFunctorReturnTypeAttribute(udf); + bool stateful = context->isStatefulFunctor(udf); + VecOwn args; + attributeMergers.push_back(mk(merger.value(), typeAttributes, returnAttribute, stateful, std::move(args))); + } } return mk( - ramRelationName, arity, 0, attributeNames, attributeTypeQualifiers, representation); + ramRelationName, arity, auxArity, attributeNames, attributeTypeQualifiers, std::move(attributeMergers), representation); } VecOwn UnitTranslator::createRamRelations(const std::vector& sccOrdering) const { @@ -713,16 +871,24 @@ VecOwn UnitTranslator::createRamRelations(const std::vectorgetQualifiedName()); ramRelations.push_back(createRamRelation(rel, mainName)); + if (rel->getAuxiliaryArity() > 0) { + // Add lub relation + std::string lubName = getLubRelationName(rel->getQualifiedName()); + ramRelations.push_back(createRamRelation(rel, lubName)); + } + + if (isRecursive || rel->getAuxiliaryArity() > 0) { + // Add new relation + std::string newName = getNewRelationName(rel->getQualifiedName()); + ramRelations.push_back(createRamRelation(rel, newName)); + } + // Recursive relations also require @delta and @new variants, with the same signature if (isRecursive) { // Add delta relation std::string deltaName = getDeltaRelationName(rel->getQualifiedName()); ramRelations.push_back(createRamRelation(rel, deltaName)); - // Add new relation - std::string newName = getNewRelationName(rel->getQualifiedName()); - ramRelations.push_back(createRamRelation(rel, newName)); - // Add auxiliary relation for subsumption if (context->hasSubsumptiveClause(rel->getQualifiedName())) { // Add reject relation diff --git a/src/ast2ram/seminaive/UnitTranslator.h b/src/ast2ram/seminaive/UnitTranslator.h index 5c1400b2170..e52799b8e8c 100644 --- a/src/ast2ram/seminaive/UnitTranslator.h +++ b/src/ast2ram/seminaive/UnitTranslator.h @@ -81,11 +81,12 @@ class UnitTranslator : public ast2ram::UnitTranslator { /** Low-level stratum translation */ Own generateStratum(std::size_t scc) const; Own generateStratumPreamble(const ast::RelationSet& scc) const; - Own generateNonRecursiveDelete(const ast::RelationSet& scc) const; + Own generateNonRecursiveDelete(const ast::Relation& rel) const; Own generateStratumPostamble(const ast::RelationSet& scc) const; Own generateStratumLoopBody(const ast::RelationSet& scc) const; Own generateStratumTableUpdates(const ast::RelationSet& scc) const; Own generateStratumExitSequence(const ast::RelationSet& scc) const; + Own generateStratumLubSequence(const ast::Relation& rel, const std::string& fromName, const std::string& toName) const; /** Other helper generations */ virtual Own generateClearExpiredRelations(const ast::RelationSet& expiredRelations) const; diff --git a/src/ast2ram/utility/Utils.cpp b/src/ast2ram/utility/Utils.cpp index 7ce90a3786d..d74ddd3a3b2 100644 --- a/src/ast2ram/utility/Utils.cpp +++ b/src/ast2ram/utility/Utils.cpp @@ -23,6 +23,7 @@ #include "ast/UnnamedVariable.h" #include "ast/Variable.h" #include "ast/utility/Utils.h" +#include "ast2ram/ClauseTranslator.h" #include "ast2ram/utility/Location.h" #include "ram/Clear.h" #include "ram/Condition.h" @@ -77,6 +78,9 @@ std::string getAtomName(const ast::Clause& clause, const ast::Atom* atom, } if (!isRecursive) { + if (mode == Auxiliary && clause.getHead() == atom) { + return getNewRelationName(atom->getQualifiedName()); + } return getConcreteRelationName(atom->getQualifiedName()); } if (clause.getHead() == atom) { @@ -100,6 +104,10 @@ std::string getNewRelationName(const ast::QualifiedName& name) { return getConcreteRelationName(name, "@new_"); } +std::string getLubRelationName(const ast::QualifiedName& name) { + return getConcreteRelationName(name, "@lub_"); +} + std::string getRejectRelationName(const ast::QualifiedName& name) { return getConcreteRelationName(name, "@reject_"); } diff --git a/src/ast2ram/utility/Utils.h b/src/ast2ram/utility/Utils.h index 65d1f5543f0..330488a40b2 100644 --- a/src/ast2ram/utility/Utils.h +++ b/src/ast2ram/utility/Utils.h @@ -54,6 +54,9 @@ std::string getDeltaRelationName(const ast::QualifiedName& name); /** Get the corresponding RAM 'new' relation name for the relation */ std::string getNewRelationName(const ast::QualifiedName& name); +/** Get the corresponding RAM 'lub' relation name for the relation */ +std::string getLubRelationName(const ast::QualifiedName& name); + /** Get the corresponding RAM 'reject' relation name for the relation */ std::string getRejectRelationName(const ast::QualifiedName& name); diff --git a/src/include/souffle/datastructure/BTree.h b/src/include/souffle/datastructure/BTree.h index 47d2bc8226d..72b4fc90105 100644 --- a/src/include/souffle/datastructure/BTree.h +++ b/src/include/souffle/datastructure/BTree.h @@ -91,8 +91,8 @@ class btree { /* -------------- updater utilities ------------- */ mutable Updater upd; - void update(Key& old_k, const Key& new_k) { - upd.update(old_k, new_k); + bool update(Key& old_k, const Key& new_k) { + return upd.update(old_k, new_k); } /* -------------- the node type ----------------- */ @@ -1225,14 +1225,14 @@ class btree { } // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *pos)) { + if (typeid(Comparator) != typeid(WeakComparator)) { if (!cur->lock.try_upgrade_to_write(cur_lease)) { // start again return insert(k, hints); } - update(*pos, k); + bool updated = update(*pos, k); cur->lock.end_write(); - return true; + return updated; } // we found the element => no check of lock necessary @@ -1280,14 +1280,14 @@ class btree { } // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *(pos - 1))) { + if (typeid(Comparator) != typeid(WeakComparator)) { if (!cur->lock.try_upgrade_to_write(cur_lease)) { // start again return insert(k, hints); } - update(*(pos - 1), k); + bool updated = update(*(pos - 1), k); cur->lock.end_write(); - return true; + return updated; } // we found the element => done @@ -1432,9 +1432,8 @@ class btree { // early exit for sets if (isSet && pos != b && weak_equal(*pos, k)) { // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *pos)) { - update(*pos, k); - return true; + if (typeid(Comparator) != typeid(WeakComparator)) { + return update(*pos, k); } return false; @@ -1458,9 +1457,8 @@ class btree { // early exit for sets if (isSet && pos != a && weak_equal(*(pos - 1), k)) { // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *(pos - 1))) { - update(*(pos - 1), k); - return true; + if (typeid(Comparator) != typeid(WeakComparator)) { + return update(*(pos - 1), k); } return false; diff --git a/src/include/souffle/datastructure/BTreeDelete.h b/src/include/souffle/datastructure/BTreeDelete.h index 745a3c12216..fc747ff1c46 100644 --- a/src/include/souffle/datastructure/BTreeDelete.h +++ b/src/include/souffle/datastructure/BTreeDelete.h @@ -92,8 +92,8 @@ class btree_delete { /* -------------- updater utilities ------------- */ mutable Updater upd; - void update(Key& old_k, const Key& new_k) { - upd.update(old_k, new_k); + bool update(Key& old_k, const Key& new_k) { + return upd.update(old_k, new_k); } /* -------------- the node type ----------------- */ @@ -1278,14 +1278,14 @@ class btree_delete { } // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *pos)) { + if (typeid(Comparator) != typeid(WeakComparator)) { if (!cur->lock.try_upgrade_to_write(cur_lease)) { // start again return insert(k, hints); } - update(*pos, k); + bool updated = update(*pos, k); cur->lock.end_write(); - return true; + return updated; } // we found the element => no check of lock necessary @@ -1333,14 +1333,14 @@ class btree_delete { } // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *(pos - 1))) { + if (typeid(Comparator) != typeid(WeakComparator)) { if (!cur->lock.try_upgrade_to_write(cur_lease)) { // start again return insert(k, hints); } - update(*(pos - 1), k); + bool updated = update(*(pos - 1), k); cur->lock.end_write(); - return true; + return updated; } // we found the element => done @@ -1485,9 +1485,8 @@ class btree_delete { // early exit for sets if (isSet && pos != b && weak_equal(*pos, k)) { // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *pos)) { - update(*pos, k); - return true; + if (typeid(Comparator) != typeid(WeakComparator)) { + return update(*pos, k); } return false; @@ -1511,9 +1510,8 @@ class btree_delete { // early exit for sets if (isSet && pos != a && weak_equal(*(pos - 1), k)) { // update provenance information - if (typeid(Comparator) != typeid(WeakComparator) && less(k, *(pos - 1))) { - update(*(pos - 1), k); - return true; + if (typeid(Comparator) != typeid(WeakComparator)) { + return update(*(pos - 1), k); } return false; diff --git a/src/include/souffle/datastructure/BTreeUtil.h b/src/include/souffle/datastructure/BTreeUtil.h index bdf624fa5ca..164006005db 100644 --- a/src/include/souffle/datastructure/BTreeUtil.h +++ b/src/include/souffle/datastructure/BTreeUtil.h @@ -217,7 +217,9 @@ struct default_strategy> : public linear {}; */ template struct updater { - void update(T& /* old_t */, const T& /* new_t */) {} + bool update(T& /* old_t */, const T& /* new_t */) { + return false; + } }; } // end of namespace detail diff --git a/src/interpreter/BTreeDeleteIndex.cpp b/src/interpreter/BTreeDeleteIndex.cpp index 1d51bbc172e..7275e3728e5 100644 --- a/src/interpreter/BTreeDeleteIndex.cpp +++ b/src/interpreter/BTreeDeleteIndex.cpp @@ -21,18 +21,15 @@ namespace souffle::interpreter { -#define CREATE_BTREE_DELETE_REL(Structure, Arity, ...) \ - case (Arity): { \ - return mk>(id.getAuxiliaryArity(), id.getName(), indexSelection); \ +#define CREATE_BTREE_DELETE_REL(Structure, Arity, AuxiliaryArity, ...) \ + if (id.getArity() == Arity && id.getAuxiliaryArity() == AuxiliaryArity) { \ + return mk>(id.getName(), indexSelection); \ } Own createBTreeDeleteRelation( const ram::Relation& id, const ram::analysis::IndexCluster& indexSelection) { - switch (id.getArity()) { - FOR_EACH_BTREE_DELETE(CREATE_BTREE_DELETE_REL); - - default: fatal("Requested arity not yet supported. Feel free to add it."); - } + FOR_EACH_BTREE_DELETE(CREATE_BTREE_DELETE_REL); + fatal("Requested arity not yet supported. Feel free to add it."); } } // namespace souffle::interpreter diff --git a/src/interpreter/BTreeIndex.cpp b/src/interpreter/BTreeIndex.cpp index 97127bf35f4..5a42aa6c491 100644 --- a/src/interpreter/BTreeIndex.cpp +++ b/src/interpreter/BTreeIndex.cpp @@ -21,19 +21,15 @@ namespace souffle::interpreter { -#define CREATE_BTREE_REL(Structure, Arity, ...) \ - case (Arity): { \ - return mk>( \ - id.getAuxiliaryArity(), id.getName(), indexSelection); \ +#define CREATE_BTREE_REL(Structure, Arity, AuxiliaryArity, ...) \ + if (id.getArity() == Arity && id.getAuxiliaryArity() == AuxiliaryArity) { \ + return mk>(id.getName(), indexSelection); \ } Own createBTreeRelation( const ram::Relation& id, const ram::analysis::IndexCluster& indexSelection) { - switch (id.getArity()) { - FOR_EACH_BTREE(CREATE_BTREE_REL); - - default: fatal("Requested arity not yet supported. Feel free to add it."); - } + FOR_EACH_BTREE(CREATE_BTREE_REL); + fatal("Requested arity not yet supported. Feel free to add it."); } } // namespace souffle::interpreter diff --git a/src/interpreter/Engine.cpp b/src/interpreter/Engine.cpp index 69c6b09dcae..aceeacd53d5 100644 --- a/src/interpreter/Engine.cpp +++ b/src/interpreter/Engine.cpp @@ -359,13 +359,13 @@ void Engine::createRelation(const ram::Relation& id, const std::size_t idx) { } RelationHandle res; - - if (id.getRepresentation() == RelationRepresentation::EQREL) { + bool hasProvenance = id.getAttributeNames().back() == "@level_number"; + if (hasProvenance) { + res = createProvenanceRelation(id, isa.getIndexSelection(id.getName())); + } else if (id.getRepresentation() == RelationRepresentation::EQREL) { res = createEqrelRelation(id, isa.getIndexSelection(id.getName())); } else if (id.getRepresentation() == RelationRepresentation::BTREE_DELETE) { res = createBTreeDeleteRelation(id, isa.getIndexSelection(id.getName())); - } else if (id.getRepresentation() == RelationRepresentation::PROVENANCE) { - res = createProvenanceRelation(id, isa.getIndexSelection(id.getName())); } else { res = createBTreeRelation(id, isa.getIndexSelection(id.getName())); } @@ -527,9 +527,9 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { // Overload CASE based on number of arguments. // CASE(Kind) -> BASE_CASE(Kind) -// CASE(Kind, Structure, Arity) -> EXTEND_CASE(Kind, Structure, Arity) -#define GET_MACRO(_1, _2, _3, NAME, ...) NAME -#define CASE(...) GET_MACRO(__VA_ARGS__, EXTEND_CASE, _Dummy, BASE_CASE)(__VA_ARGS__) +// CASE(Kind, Structure, Arity, AuxiliaryArity) -> EXTEND_CASE(Kind, Structure, Arity, AuxiliaryArity) +#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME +#define CASE(...) GET_MACRO(__VA_ARGS__, EXTEND_CASE, _Dummy, _Dummy2, BASE_CASE)(__VA_ARGS__) #define BASE_CASE(Kind) \ case (I_##Kind): { \ @@ -537,12 +537,12 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { [[maybe_unused]] const auto& shadow = *static_cast(node); \ [[maybe_unused]] const auto& cur = *static_cast(node->getShadow()); // EXTEND_CASE also defer the relation type -#define EXTEND_CASE(Kind, Structure, Arity) \ - case (I_##Kind##_##Structure##_##Arity): { \ +#define EXTEND_CASE(Kind, Structure, Arity, AuxiliaryArity) \ + case (I_##Kind##_##Structure##_##Arity##_##AuxiliaryArity): { \ return [&]() -> RamDomain { \ [[maybe_unused]] const auto& shadow = *static_cast(node); \ [[maybe_unused]] const auto& cur = *static_cast(node->getShadow());\ - using RelType = Relation; + using RelType = Relation; #define ESAC(Kind) \ } \ (); \ @@ -978,8 +978,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { return !execute(shadow.getChild(), ctxt); ESAC(Negation) -#define EMPTINESS_CHECK(Structure, Arity, ...) \ - CASE(EmptinessCheck, Structure, Arity) \ +#define EMPTINESS_CHECK(Structure, Arity, AuxiliaryArity, ...) \ + CASE(EmptinessCheck, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return rel.empty(); \ ESAC(EmptinessCheck) @@ -987,8 +987,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(EMPTINESS_CHECK) #undef EMPTINESS_CHECK -#define RELATION_SIZE(Structure, Arity, ...) \ - CASE(RelationSize, Structure, Arity) \ +#define RELATION_SIZE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(RelationSize, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return rel.size(); \ ESAC(RelationSize) @@ -996,16 +996,16 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(RELATION_SIZE) #undef RELATION_SIZE -#define EXISTENCE_CHECK(Structure, Arity, ...) \ - CASE(ExistenceCheck, Structure, Arity) \ +#define EXISTENCE_CHECK(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ExistenceCheck, Structure, Arity, AuxiliaryArity) \ return evalExistenceCheck(shadow, ctxt); \ ESAC(ExistenceCheck) FOR_EACH(EXISTENCE_CHECK) #undef EXISTENCE_CHECK -#define PROVENANCE_EXISTENCE_CHECK(Structure, Arity, ...) \ - CASE(ProvenanceExistenceCheck, Structure, Arity) \ +#define PROVENANCE_EXISTENCE_CHECK(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ProvenanceExistenceCheck, Structure, Arity, AuxiliaryArity) \ return evalProvenanceExistenceCheck(shadow, ctxt); \ ESAC(ProvenanceExistenceCheck) @@ -1127,8 +1127,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { return result; ESAC(TupleOperation) -#define SCAN(Structure, Arity, ...) \ - CASE(Scan, Structure, Arity) \ +#define SCAN(Structure, Arity, AuxiliaryArity, ...) \ + CASE(Scan, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalScan(rel, cur, shadow, ctxt); \ ESAC(Scan) @@ -1136,24 +1136,24 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(SCAN) #undef SCAN -#define PARALLEL_SCAN(Structure, Arity, ...) \ - CASE(ParallelScan, Structure, Arity) \ +#define PARALLEL_SCAN(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ParallelScan, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalParallelScan(rel, cur, shadow, ctxt); \ ESAC(ParallelScan) FOR_EACH(PARALLEL_SCAN) #undef PARALLEL_SCAN -#define INDEX_SCAN(Structure, Arity, ...) \ - CASE(IndexScan, Structure, Arity) \ +#define INDEX_SCAN(Structure, Arity, AuxiliaryArity, ...) \ + CASE(IndexScan, Structure, Arity, AuxiliaryArity) \ return evalIndexScan(cur, shadow, ctxt); \ ESAC(IndexScan) FOR_EACH(INDEX_SCAN) #undef INDEX_SCAN -#define PARALLEL_INDEX_SCAN(Structure, Arity, ...) \ - CASE(ParallelIndexScan, Structure, Arity) \ +#define PARALLEL_INDEX_SCAN(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ParallelIndexScan, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalParallelIndexScan(rel, cur, shadow, ctxt); \ ESAC(ParallelIndexScan) @@ -1161,8 +1161,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(PARALLEL_INDEX_SCAN) #undef PARALLEL_INDEX_SCAN -#define IFEXISTS(Structure, Arity, ...) \ - CASE(IfExists, Structure, Arity) \ +#define IFEXISTS(Structure, Arity, AuxiliaryArity, ...) \ + CASE(IfExists, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalIfExists(rel, cur, shadow, ctxt); \ ESAC(IfExists) @@ -1170,8 +1170,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(IFEXISTS) #undef IFEXISTS -#define PARALLEL_IFEXISTS(Structure, Arity, ...) \ - CASE(ParallelIfExists, Structure, Arity) \ +#define PARALLEL_IFEXISTS(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ParallelIfExists, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalParallelIfExists(rel, cur, shadow, ctxt); \ ESAC(ParallelIfExists) @@ -1179,16 +1179,16 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(PARALLEL_IFEXISTS) #undef PARALLEL_IFEXISTS -#define INDEX_IFEXISTS(Structure, Arity, ...) \ - CASE(IndexIfExists, Structure, Arity) \ +#define INDEX_IFEXISTS(Structure, Arity, AuxiliaryArity, ...) \ + CASE(IndexIfExists, Structure, Arity, AuxiliaryArity) \ return evalIndexIfExists(cur, shadow, ctxt); \ ESAC(IndexIfExists) FOR_EACH(INDEX_IFEXISTS) #undef INDEX_IFEXISTS -#define PARALLEL_INDEX_IFEXISTS(Structure, Arity, ...) \ - CASE(ParallelIndexIfExists, Structure, Arity) \ +#define PARALLEL_INDEX_IFEXISTS(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ParallelIndexIfExists, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalParallelIndexIfExists(rel, cur, shadow, ctxt); \ ESAC(ParallelIndexIfExists) @@ -1215,8 +1215,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { return execute(shadow.getNestedOperation(), ctxt); ESAC(UnpackRecord) -#define PARALLEL_AGGREGATE(Structure, Arity, ...) \ - CASE(ParallelAggregate, Structure, Arity) \ +#define PARALLEL_AGGREGATE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ParallelAggregate, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalParallelAggregate(rel, cur, shadow, ctxt); \ ESAC(ParallelAggregate) @@ -1224,8 +1224,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(PARALLEL_AGGREGATE) #undef PARALLEL_AGGREGATE -#define AGGREGATE(Structure, Arity, ...) \ - CASE(Aggregate, Structure, Arity) \ +#define AGGREGATE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(Aggregate, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalAggregate(cur, shadow, rel.scan(), ctxt); \ ESAC(Aggregate) @@ -1233,16 +1233,16 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(AGGREGATE) #undef AGGREGATE -#define PARALLEL_INDEX_AGGREGATE(Structure, Arity, ...) \ - CASE(ParallelIndexAggregate, Structure, Arity) \ +#define PARALLEL_INDEX_AGGREGATE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(ParallelIndexAggregate, Structure, Arity, AuxiliaryArity) \ return evalParallelIndexAggregate(cur, shadow, ctxt); \ ESAC(ParallelIndexAggregate) FOR_EACH(PARALLEL_INDEX_AGGREGATE) #undef PARALLEL_INDEX_AGGREGATE -#define INDEX_AGGREGATE(Structure, Arity, ...) \ - CASE(IndexAggregate, Structure, Arity) \ +#define INDEX_AGGREGATE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(IndexAggregate, Structure, Arity, AuxiliaryArity) \ return evalIndexAggregate(cur, shadow, ctxt); \ ESAC(IndexAggregate) @@ -1275,8 +1275,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { return result; ESAC(Filter) -#define GUARDED_INSERT(Structure, Arity, ...) \ - CASE(GuardedInsert, Structure, Arity) \ +#define GUARDED_INSERT(Structure, Arity, AuxiliaryArity, ...) \ + CASE(GuardedInsert, Structure, Arity, AuxiliaryArity) \ auto& rel = *static_cast(shadow.getRelation()); \ return evalGuardedInsert(rel, shadow, ctxt); \ ESAC(GuardedInsert) @@ -1284,8 +1284,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(GUARDED_INSERT) #undef GUARDED_INSERT -#define INSERT(Structure, Arity, ...) \ - CASE(Insert, Structure, Arity) \ +#define INSERT(Structure, Arity, AuxiliaryArity, ...) \ + CASE(Insert, Structure, Arity, AuxiliaryArity) \ auto& rel = *static_cast(shadow.getRelation()); \ return evalInsert(rel, shadow, ctxt); \ ESAC(Insert) @@ -1293,10 +1293,10 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(INSERT) #undef INSERT -#define ERASE(Structure, Arity, ...) \ - CASE(Erase, Structure, Arity) \ +#define ERASE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(Erase, Structure, Arity, AuxiliaryArity) \ void(static_cast(shadow.getRelation())); \ - auto& rel = *static_cast*>(shadow.getRelation()); \ + auto& rel = *static_cast*>(shadow.getRelation()); \ return evalErase(rel, shadow, ctxt); \ ESAC(Erase) @@ -1361,8 +1361,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { return execute(shadow.getChild(), ctxt); ESAC(DebugInfo) -#define CLEAR(Structure, Arity, ...) \ - CASE(Clear, Structure, Arity) \ +#define CLEAR(Structure, Arity, AuxiliaryArity, ...) \ + CASE(Clear, Structure, Arity, AuxiliaryArity) \ auto& rel = *static_cast(shadow.getRelation()); \ rel.__purge(); \ return true; \ @@ -1371,8 +1371,8 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { FOR_EACH(CLEAR) #undef CLEAR -#define ESTIMATEJOINSIZE(Structure, Arity, ...) \ - CASE(EstimateJoinSize, Structure, Arity) \ +#define ESTIMATEJOINSIZE(Structure, Arity, AuxiliaryArity, ...) \ + CASE(EstimateJoinSize, Structure, Arity, AuxiliaryArity) \ const auto& rel = *static_cast(shadow.getRelation()); \ return evalEstimateJoinSize(rel, cur, shadow, ctxt); \ ESAC(EstimateJoinSize) @@ -1937,7 +1937,7 @@ bool runNested(const ram::Aggregator& aggregator) { default: return false; } } else if (isA(aggregator)) { - return false; + return true; } return false; } diff --git a/src/interpreter/EqrelIndex.cpp b/src/interpreter/EqrelIndex.cpp index 7a368c16e9a..450af53fcdd 100644 --- a/src/interpreter/EqrelIndex.cpp +++ b/src/interpreter/EqrelIndex.cpp @@ -23,7 +23,8 @@ namespace souffle::interpreter { Own createEqrelRelation( const ram::Relation& id, const ram::analysis::IndexCluster& indexSelection) { assert(id.getArity() == 2 && "Eqivalence relation must have arity size 2."); - return mk(id.getAuxiliaryArity(), id.getName(), indexSelection); + assert(id.getAuxiliaryArity() == 0 && "Eqivalence relation must have auxiliary arity size 0."); + return mk(id.getName(), indexSelection); } } // namespace souffle::interpreter diff --git a/src/interpreter/Index.h b/src/interpreter/Index.h index 3fc693de8b4..c3526de398d 100644 --- a/src/interpreter/Index.h +++ b/src/interpreter/Index.h @@ -142,11 +142,12 @@ struct ViewWrapper { /** * An index is an abstraction of a data structure */ -template typename Structure> +template typename Structure> class Index { public: static constexpr std::size_t Arity = _Arity; - using Data = Structure; + static constexpr std::size_t AuxiliaryArity = _AuxiliaryArity; + using Data = Structure; using Tuple = typename souffle::Tuple; using iterator = typename Data::iterator; using Hints = typename Data::operation_hints; @@ -239,7 +240,7 @@ class Index { /** * Inserts all elements of the given index. */ - void insert(const Index& src) { + void insert(const Index& src) { for (const auto& tuple : src) { this->insert(tuple); } @@ -316,8 +317,8 @@ class Index { * A partial specialize template for nullary indexes. * No complex data structure is required. */ -template