souffle  2.0.2-371-g6315b36
Namespaces | Data Structures | Typedefs | Functions
souffle::ast::transform Namespace Reference

Namespaces

 test
 

Data Structures

class  AddNullariesToAtomlessAggregatesTransformer
 Transformation pass to add artificial nullary atom (+Tautology()) to aggregate bodies that have no atoms. More...
 
class  ComponentChecker
 
class  ComponentInstantiationTransformer
 
class  ConditionalTransformer
 Transformer that executes a sub-transformer iff a condition holds. More...
 
class  DebugReporter
 Transformation pass which wraps another transformation pass and generates a debug report section for the stage after applying the wrapped transformer, and adds it to the translation unit's debug report. More...
 
class  ExecutionPlanChecker
 
class  FixpointTransformer
 Transformer that repeatedly executes a sub-transformer until no changes are made. More...
 
class  FoldAnonymousRecords
 Transformation pass that removes (binary) constraints on the anonymous records. More...
 
class  GroundedTermsChecker
 
class  GroundWitnessesTransformer
 Apply a grounding so that the witness of a selection aggregate (min/max) can be transferred to the outer scope. More...
 
class  InlineRelationsTransformer
 Transformation pass to inline marked relations. More...
 
class  IOAttributesTransformer
 Transformation pass to set attribute names and types in IO operations. More...
 
class  IODefaultsTransformer
 Transformation pass to set defaults for IO operations. More...
 
class  MagicSetTransformer
 Magic Set Transformation. More...
 
class  MaterializeAggregationQueriesTransformer
 Transformation pass to create artificial relations for bodies of aggregation functions consisting of more than a single atom. More...
 
class  MaterializeSingletonAggregationTransformer
 Replaces literals containing single-valued aggregates with a synthesised relation. More...
 
class  MetaTransformer
 Transformer that coordinates other sub-transformations. More...
 
class  MinimiseProgramTransformer
 Transformation pass to remove equivalent rules. More...
 
class  NameUnnamedVariablesTransformer
 Transformation pass to replace unnamed variables with singletons. More...
 
class  NormaliseMultiResultFunctorsTransformer
 Uniquely names all appearances of ranges. More...
 
class  NullableVector
 
class  NullTransformer
 Transformer that does absolutely nothing. More...
 
class  PartitionBodyLiteralsTransformer
 Transformation pass to move literals into new clauses if they are independent of remaining literals. More...
 
class  PipelineTransformer
 Transformer that holds an arbitrary number of sub-transformations. More...
 
class  PragmaChecker
 
class  ProvenanceTransformer
 Transformation pass to add provenance information. More...
 
class  ReduceExistentialsTransformer
 Transformation pass to reduce unnecessary computation for relations that only appear in the form A(_,...,_). More...
 
class  RemoveBooleanConstraintsTransformer
 Transformation pass to remove constant boolean constraints Should be called after any transformation that may generate boolean constraints. More...
 
class  RemoveEmptyRelationsTransformer
 Transformation pass to remove all empty relations and rules that use empty relations. More...
 
class  RemoveRedundantRelationsTransformer
 Transformation pass to remove relations which are redundant (do not contribute to output). More...
 
class  RemoveRedundantSumsTransformer
 Transformation pass to remove expressions of the form sum k : { ... More...
 
class  RemoveRelationCopiesTransformer
 Transformation pass to replaces copy of relations by their origin. More...
 
class  ReorderLiteralsTransformer
 Transformation pass to reorder body literals. More...
 
class  ReplaceSingletonVariablesTransformer
 Transformation pass to replace singleton variables with unnamed variables. More...
 
class  ResolveAliasesTransformer
 Transformation pass to eliminate grounded aliases. More...
 
class  ResolveAnonymousRecordAliasesTransformer
 Transformer resolving aliases for anonymous records. More...
 
class  SemanticChecker
 
struct  SemanticCheckerImpl
 
class  SimplifyAggregateTargetExpressionTransformer
 Transformation pass to rename aggregation variables to make them unique. More...
 
class  Transformer
 
class  TypeChecker
 
class  TypeCheckerImpl
 
class  TypeDeclarationChecker
 
class  UniqueAggregationVariablesTransformer
 Transformation pass to rename aggregation variables to make them unique. More...
 
class  WhileTransformer
 Transformer that repeatedly executes a sub-transformer while a condition is met. More...
 

Typedefs

using AdornDatabaseTransformer = MagicSetTransformer::AdornDatabaseTransformer
 
using LabelDatabaseTransformer = MagicSetTransformer::LabelDatabaseTransformer
 
using MagicSetCoreTransformer = MagicSetTransformer::MagicSetCoreTransformer
 
using NegativeLabellingTransformer = MagicSetTransformer::LabelDatabaseTransformer::NegativeLabellingTransformer
 
using NormaliseDatabaseTransformer = MagicSetTransformer::NormaliseDatabaseTransformer
 
using PositiveLabellingTransformer = MagicSetTransformer::LabelDatabaseTransformer::PositiveLabellingTransformer
 

Functions

ArgumentcombineAggregators (std::vector< Aggregator * > aggrs, std::string fun)
 
std::vector< std::vector< Literal * > > combineNegatedLiterals (std::vector< std::vector< Literal * >> litGroups)
 Return the negated version of a disjunction of conjunctions. More...
 
bool containsInlinedAtom (const Program &program, const Clause &clause)
 Checks if a given clause contains an atom that should be inlined. More...
 
std::vector< QualifiedNamefindInlineCycle (const PrecedenceGraphAnalysis &precedenceGraph, std::map< const Relation *, const Relation * > &origins, const Relation *current, RelationSet &unvisited, RelationSet &visiting, RelationSet &visited)
 Find a cycle consisting entirely of inlined relations. More...
 
std::vector< std::vector< Literal * > > formNegatedLiterals (Program &program, Atom *atom)
 Forms the bodies that will replace the negation of a given inlined atom. More...
 
NullableVector< Argument * > getInlinedArgument (Program &program, const Argument *arg)
 Returns a vector of arguments that should replace the given argument after one step of inlining. More...
 
NullableVector< Atom * > getInlinedAtom (Program &program, Atom &atom)
 Returns a vector of atoms that should replace the given atom after one step of inlining. More...
 
std::vector< Clause * > getInlinedClause (Program &program, const Clause &clause)
 Returns a list of clauses that should replace the given clause after one step of inlining. More...
 
NullableVector< std::vector< Literal * > > getInlinedLiteral (Program &program, Literal *lit)
 Tries to perform a single step of inlining on the given literal. More...
 
std::pair< NullableVector< Literal * >, std::vector< BinaryConstraint * > > inlineBodyLiterals (Atom *atom, Clause *atomInlineClause)
 Inlines the given atom based on a given clause. More...
 
Own< RelationmakeInfoRelation (Clause &originalClause, size_t originalClauseNum, TranslationUnit &translationUnit)
 
QualifiedName makeRelationName (const QualifiedName &orig, const std::string &type, int num=-1)
 Helper functions. More...
 
bool nameInlinedUnderscores (Program &program)
 Removes all underscores in all atoms of inlined relations. More...
 
LiteralnegateLiteral (Literal *lit)
 Returns the negated version of a given literal. More...
 
bool normaliseInlinedHeads (Program &program)
 Replace constants in the head of inlined clauses with (constrained) variables. More...
 
bool reduceSubstitution (std::vector< std::pair< Argument *, Argument * >> &sub)
 Reduces a vector of substitutions. More...
 
void renameVariables (Argument *arg)
 Renames all variables in a given argument uniquely. More...
 
void transformEqrelRelation (Program &program, Relation &rel)
 Transform eqrel relations to explicitly define equivalence relations. More...
 
NullableVector< std::pair< Argument *, Argument * > > unifyAtoms (Atom *first, Atom *second)
 Returns the nullable vector of substitutions needed to unify the two given atoms. More...
 
static const std::vector< SrcLocationusesInvalidWitness (TranslationUnit &tu, const Clause &clause, const Aggregator &aggregate)
 A witness is considered "invalid" if it is trying to export a witness out of a count, sum, or mean aggregate. More...
 

Typedef Documentation

◆ AdornDatabaseTransformer

Definition at line 62 of file MagicSet.cpp.

◆ LabelDatabaseTransformer

Definition at line 61 of file MagicSet.cpp.

◆ MagicSetCoreTransformer

Definition at line 63 of file MagicSet.cpp.

◆ NegativeLabellingTransformer

Definition at line 66 of file MagicSet.cpp.

◆ NormaliseDatabaseTransformer

Definition at line 60 of file MagicSet.cpp.

◆ PositiveLabellingTransformer

Definition at line 68 of file MagicSet.cpp.

Function Documentation

◆ combineAggregators()

Argument* souffle::ast::transform::combineAggregators ( std::vector< Aggregator * >  aggrs,
std::string  fun 
)

Definition at line 521 of file InlineRelations.cpp.

537  {

Referenced by getInlinedArgument().

◆ combineNegatedLiterals()

std::vector<std::vector<Literal*> > souffle::ast::transform::combineNegatedLiterals ( std::vector< std::vector< Literal * >>  litGroups)

Return the negated version of a disjunction of conjunctions.

E.g. (a1(x) ^ a2(x) ^ ...) v (b1(x) ^ b2(x) ^ ...) –into-> (!a1(x) ^ !b1(x)) v (!a2(x) ^ !b2(x)) v ...

Definition at line 385 of file InlineRelations.cpp.

388  {
389  // !(a1 ^ a2 ^ a3 ^ ...) --into-> !a1 v !a2 v !a3 v ...
390  for (auto& i : litGroup) {
391  std::vector<Literal*> newVec;
392  newVec.push_back(negateLiteral(i));
393  negation.push_back(newVec);
394  }
395 
396  // Done!
397  return negation;
398  }
399 
400  // Produce the negated versions of all disjunctions ignoring the first recursively
401  std::vector<std::vector<Literal*>> combinedRHS = combineNegatedLiterals(
402  std::vector<std::vector<Literal*>>(litGroups.begin() + 1, litGroups.end()));
403 
404  // We now just need to add the negation of a single literal from the untouched LHS
405  // to every single conjunction on the RHS to finalise creating every possible combination
406  for (Literal* lhsLit : litGroup) {
407  for (std::vector<Literal*> rhsVec : combinedRHS) {
408  std::vector<Literal*> newVec;
409  newVec.push_back(negateLiteral(lhsLit));
410 
411  for (Literal* lit : rhsVec) {
412  newVec.push_back(lit->clone());
413  }
414 
415  negation.push_back(newVec);
416  }
417  }
418 
419  for (std::vector<Literal*> rhsVec : combinedRHS) {
420  for (Literal* lit : rhsVec) {
421  delete lit;
422  }
423  }
424 
425  return negation;
426 }
427 
428 /**
429  * Forms the bodies that will replace the negation of a given inlined atom.
430  * E.g. a(x) <- (a11(x), a12(x)) ; (a21(x), a22(x)) => !a(x) <- (!a11(x), !a21(x)) ; (!a11(x), !a22(x)) ; ...
431  * Essentially, produce every combination (m_1 ^ m_2 ^ ...) where m_i is the negation of a literal in the
432  * ith rule of a.

◆ containsInlinedAtom()

bool souffle::ast::transform::containsInlinedAtom ( const Program program,
const Clause clause 
)

Checks if a given clause contains an atom that should be inlined.

Definition at line 202 of file InlineRelations.cpp.

213  {

◆ findInlineCycle()

std::vector<QualifiedName> souffle::ast::transform::findInlineCycle ( const PrecedenceGraphAnalysis precedenceGraph,
std::map< const Relation *, const Relation * > &  origins,
const Relation current,
RelationSet unvisited,
RelationSet visiting,
RelationSet visited 
)

Find a cycle consisting entirely of inlined relations.

If no cycle exists, then an empty vector is returned.

Definition at line 713 of file SemanticChecker.cpp.

715  {
716  // Nothing left to visit - so no cycles exist!
717  return result;
718  }
719 
720  // Choose any element from the unvisited set
721  current = *unvisited.begin();
722  origins[current] = nullptr;
723 
724  // Move it to "currently visiting"
725  unvisited.erase(current);
726  visiting.insert(current);
727 
728  // Check if we can find a cycle beginning from this node
729  std::vector<QualifiedName> subresult =
730  findInlineCycle(precedenceGraph, origins, current, unvisited, visiting, visited);
731 
732  if (subresult.empty()) {
733  // No cycle found, try again from another node
734  return findInlineCycle(precedenceGraph, origins, nullptr, unvisited, visiting, visited);
735  } else {
736  // Cycle found! Return it
737  return subresult;
738  }
739  }
740 
741  // Check neighbours
742  const RelationSet& successors = precedenceGraph.graph().successors(current);
743  for (const Relation* successor : successors) {
744  // Only care about inlined neighbours in the graph
745  if (successor->hasQualifier(RelationQualifier::INLINE)) {
746  if (visited.find(successor) != visited.end()) {
747  // The neighbour has already been visited, so move on
748  continue;
749  }
750 
751  if (visiting.find(successor) != visiting.end()) {
752  // Found a cycle!!
753  // Construct the cycle in reverse
754  while (current != nullptr) {
755  result.push_back(current->getQualifiedName());
756  current = origins[current];
757  }
758  return result;
759  }
760 
761  // Node has not been visited yet
762  origins[successor] = current;
763 
764  // Move from unvisited to visiting
765  unvisited.erase(successor);
766  visiting.insert(successor);
767 
768  // Visit recursively and check if a cycle is formed
769  std::vector<QualifiedName> subgraphCycle =
770  findInlineCycle(precedenceGraph, origins, successor, unvisited, visiting, visited);
771 
772  if (!subgraphCycle.empty()) {
773  // Found a cycle!
774  return subgraphCycle;
775  }
776  }
777  }
778 
779  // Visited all neighbours with no cycle found, so done visiting this node.
780  visiting.erase(current);
781  visited.insert(current);
782  return result;
783 }
784 
785 void SemanticCheckerImpl::checkInlining() {
786  auto isInline = [&](const Relation* rel) { return rel->hasQualifier(RelationQualifier::INLINE); };
787 
788  // Find all inlined relations
789  RelationSet inlinedRelations;

◆ formNegatedLiterals()

std::vector<std::vector<Literal*> > souffle::ast::transform::formNegatedLiterals ( Program program,
Atom atom 
)

Forms the bodies that will replace the negation of a given inlined atom.

E.g. a(x) <- (a11(x), a12(x)) ; (a21(x), a22(x)) => !a(x) <- (!a11(x), !a21(x)) ; (!a11(x), !a22(x)) ; ... Essentially, produce every combination (m_1 ^ m_2 ^ ...) where m_i is the negation of a literal in the ith rule of a.

Definition at line 440 of file InlineRelations.cpp.

441  : getClauses(program, *getRelation(program, atom->getQualifiedName()))) {
442  // Form the replacement clause by inlining based on the current clause
443  std::pair<NullableVector<Literal*>, std::vector<BinaryConstraint*>> inlineResult =
444  inlineBodyLiterals(atom, inClause);
445  NullableVector<Literal*> replacementBodyLiterals = inlineResult.first;
446  std::vector<BinaryConstraint*> currConstraints = inlineResult.second;
447 
448  if (!replacementBodyLiterals.isValid()) {
449  // Failed to unify, so just move on
450  continue;
451  }
452 
453  addedBodyLiterals.push_back(replacementBodyLiterals.getVector());
454  addedConstraints.push_back(currConstraints);
455  }
456 
457  // We now have a list of bodies needed to inline the given atom.
458  // We want to inline the negated version, however, which is done using De Morgan's Law.
459  std::vector<std::vector<Literal*>> negatedAddedBodyLiterals = combineNegatedLiterals(addedBodyLiterals);
460 
461  // Add in the necessary constraints to all the body literals
462  for (auto& negatedAddedBodyLiteral : negatedAddedBodyLiterals) {
463  for (std::vector<BinaryConstraint*> constraintGroup : addedConstraints) {
464  for (BinaryConstraint* constraint : constraintGroup) {
465  negatedAddedBodyLiteral.push_back(constraint->clone());
466  }
467  }
468  }
469 
470  // Free up the old body literals and constraints
471  for (std::vector<Literal*> litGroup : addedBodyLiterals) {
472  for (Literal* lit : litGroup) {
473  delete lit;
474  }
475  }
476  for (std::vector<BinaryConstraint*> consGroup : addedConstraints) {
477  for (Constraint* cons : consGroup) {
478  delete cons;
479  }
480  }
481 
482  return negatedAddedBodyLiterals;
483 }
484 
485 /**
486  * Renames all variables in a given argument uniquely.
487  */
488 void renameVariables(Argument* arg) {
489  static int varCount = 0;

References inlineBodyLiterals().

Here is the call graph for this function:

◆ getInlinedArgument()

NullableVector<Argument*> souffle::ast::transform::getInlinedArgument ( Program program,
const Argument arg 
)

Returns a vector of arguments that should replace the given argument after one step of inlining.

Note: This function is currently generalised to perform any required inlining within aggregators as well, making it simple to extend to this later on if desired (and the semantic check is removed).

Definition at line 543 of file InlineRelations.cpp.

543  {
544  // First try inlining the target expression if necessary
545  if (aggr->getTargetExpression() != nullptr) {
546  NullableVector<Argument*> argumentVersions =
547  getInlinedArgument(program, aggr->getTargetExpression());
548 
549  if (argumentVersions.isValid()) {
550  // An element in the target expression can be inlined!
551  changed = true;
552 
553  // Create a new aggregator per version of the target expression
554  for (Argument* newArg : argumentVersions.getVector()) {
555  auto* newAggr = new Aggregator(aggr->getBaseOperator(), Own<Argument>(newArg));
556  VecOwn<Literal> newBody;
557  for (Literal* lit : aggr->getBodyLiterals()) {
558  newBody.push_back(souffle::clone(lit));
559  }
560  newAggr->setBody(std::move(newBody));
561  versions.push_back(newAggr);
562  }
563  }
564  }
565 
566  // Try inlining body arguments if the target expression has not been changed.
567  // (At this point we only handle one step of inlining at a time)
568  if (!changed) {
569  std::vector<Literal*> bodyLiterals = aggr->getBodyLiterals();
570  for (size_t i = 0; i < bodyLiterals.size(); i++) {
571  Literal* currLit = bodyLiterals[i];
572 
573  NullableVector<std::vector<Literal*>> literalVersions = getInlinedLiteral(program, currLit);
574 
575  if (literalVersions.isValid()) {
576  // Literal can be inlined!
577  changed = true;
578 
579  AggregateOp op = aggr->getBaseOperator();
580 
581  // Create an aggregator (with the same operation) for each possible body
582  std::vector<Aggregator*> aggrVersions;
583  for (std::vector<Literal*> inlineVersions : literalVersions.getVector()) {
584  Own<Argument> target;
585  if (aggr->getTargetExpression() != nullptr) {
586  target = souffle::clone(aggr->getTargetExpression());
587  }
588  auto* newAggr = new Aggregator(aggr->getBaseOperator(), std::move(target));
589 
590  VecOwn<Literal> newBody;
591  // Add in everything except the current literal being replaced
592  for (size_t j = 0; j < bodyLiterals.size(); j++) {
593  if (i != j) {
594  newBody.push_back(souffle::clone(bodyLiterals[j]));
595  }
596  }
597 
598  // Add in everything new that replaces that literal
599  for (Literal* addedLit : inlineVersions) {
600  newBody.push_back(Own<Literal>(addedLit));
601  }
602 
603  newAggr->setBody(std::move(newBody));
604  aggrVersions.push_back(newAggr);
605  }
606 
607  // Utility lambda: get functor used to tie aggregators together.
608  auto aggregateToFunctor = [](AggregateOp op) {
609  switch (op) {
610  case AggregateOp::MIN:
611  case AggregateOp::FMIN:
612  case AggregateOp::UMIN: return "min";
613  case AggregateOp::MAX:
614  case AggregateOp::FMAX:
615  case AggregateOp::UMAX: return "max";
616  case AggregateOp::SUM:
617  case AggregateOp::FSUM:
618  case AggregateOp::USUM:
619  case AggregateOp::COUNT: return "+";
620  case AggregateOp::MEAN: fatal("no translation");
621  }
622 
624  };
625  // Create the actual overall aggregator that ties the replacement aggregators together.
626  // example: min x : { a(x) }. <=> min ( min x : { a1(x) }, min x : { a2(x) }, ... )
627  if (op != AggregateOp::MEAN) {
628  versions.push_back(combineAggregators(aggrVersions, aggregateToFunctor(op)));
629  }
630  }
631 
632  // Only perform one stage of inlining at a time.
633  if (changed) {
634  break;
635  }
636  }
637  }
638  } else if (const auto* functor = dynamic_cast<const Functor*>(arg)) {
639  size_t i = 0;
640  for (auto funArg : functor->getArguments()) {
641  // TODO (azreika): use unique pointers
642  // try inlining each argument from left to right
643  NullableVector<Argument*> argumentVersions = getInlinedArgument(program, funArg);
644  if (argumentVersions.isValid()) {
645  changed = true;
646  for (Argument* newArgVersion : argumentVersions.getVector()) {
647  // same functor but with new argument version
648  VecOwn<Argument> argsCopy;
649  size_t j = 0;
650  for (auto& functorArg : functor->getArguments()) {
651  if (j == i) {
652  argsCopy.emplace_back(newArgVersion);
653  } else {
654  argsCopy.emplace_back(functorArg->clone());
655  }
656  ++j;
657  }
658  if (const auto* intrFunc = dynamic_cast<const IntrinsicFunctor*>(arg)) {
659  auto* newFunctor =
660  new IntrinsicFunctor(intrFunc->getBaseFunctionOp(), std::move(argsCopy));
661  newFunctor->setSrcLoc(functor->getSrcLoc());
662  versions.push_back(newFunctor);
663  } else if (const auto* userFunc = dynamic_cast<const UserDefinedFunctor*>(arg)) {
664  auto* newFunctor = new UserDefinedFunctor(userFunc->getName(), std::move(argsCopy));
665  newFunctor->setSrcLoc(userFunc->getSrcLoc());
666  versions.push_back(newFunctor);
667  }
668  }
669  // only one step at a time
670  break;
671  }
672  ++i;
673  }
674  } else if (const auto* cast = dynamic_cast<const ast::TypeCast*>(arg)) {
675  NullableVector<Argument*> argumentVersions = getInlinedArgument(program, cast->getValue());
676  if (argumentVersions.isValid()) {
677  changed = true;
678  for (Argument* newArg : argumentVersions.getVector()) {
679  Argument* newTypeCast = new ast::TypeCast(Own<Argument>(newArg), cast->getType());
680  versions.push_back(newTypeCast);
681  }
682  }
683  } else if (const auto* record = dynamic_cast<const RecordInit*>(arg)) {
684  std::vector<Argument*> recordArguments = record->getArguments();
685  for (size_t i = 0; i < recordArguments.size(); i++) {
686  Argument* currentRecArg = recordArguments[i];
687  NullableVector<Argument*> argumentVersions = getInlinedArgument(program, currentRecArg);
688  if (argumentVersions.isValid()) {
689  changed = true;
690  for (Argument* newArgumentVersion : argumentVersions.getVector()) {
691  auto* newRecordArg = new RecordInit();
692  for (size_t j = 0; j < recordArguments.size(); j++) {
693  if (i == j) {
694  newRecordArg->addArgument(Own<Argument>(newArgumentVersion));
695  } else {
696  newRecordArg->addArgument(souffle::clone(recordArguments[j]));
697  }
698  }
699  versions.push_back(newRecordArg);
700  }
701  }
702 
703  // Only perform one stage of inlining at a time.
704  if (changed) {
705  break;
706  }
707  }
708  }
709 
710  if (changed) {
711  // Return a valid vector - replacements need to be made!
712  return NullableVector<Argument*>(versions);
713  } else {
714  // Return an invalid vector - no inlining has occurred
715  return NullableVector<Argument*>();
716  }
717 }
718 
719 /**
720  * Returns a vector of atoms that should replace the given atom after one step of inlining.
721  * Assumes the relation the atom belongs to is not inlined itself.
722  */
723 NullableVector<Atom*> getInlinedAtom(Program& program, Atom& atom) {

References souffle::clone(), combineAggregators(), souffle::COUNT, souffle::fatal(), souffle::FMAX, souffle::FMIN, souffle::FSUM, getInlinedLiteral(), i, j, souffle::MAX, souffle::MEAN, souffle::MIN, souffle::SUM, souffle::UMAX, souffle::UMIN, UNREACHABLE_BAD_CASE_ANALYSIS, and souffle::USUM.

Referenced by getInlinedAtom().

Here is the call graph for this function:

◆ getInlinedAtom()

NullableVector<Atom*> souffle::ast::transform::getInlinedAtom ( Program program,
Atom atom 
)

Returns a vector of atoms that should replace the given atom after one step of inlining.

Assumes the relation the atom belongs to is not inlined itself.

Definition at line 729 of file InlineRelations.cpp.

729  {
730  Argument* arg = arguments[i];
731 
732  NullableVector<Argument*> argumentVersions = getInlinedArgument(program, arg);
733 
734  if (argumentVersions.isValid()) {
735  // Argument has replacements
736  changed = true;
737 
738  // Create a new atom per new version of the argument
739  for (Argument* newArgument : argumentVersions.getVector()) {
740  auto args = atom.getArguments();
741  VecOwn<Argument> newArgs;
742  for (size_t j = 0; j < args.size(); j++) {
743  if (j == i) {
744  newArgs.emplace_back(newArgument);
745  } else {
746  newArgs.emplace_back(args[j]->clone());
747  }
748  }
749  auto* newAtom = new Atom(atom.getQualifiedName(), std::move(newArgs), atom.getSrcLoc());
750  versions.push_back(newAtom);
751  }
752  }
753 
754  // Only perform one stage of inlining at a time.
755  if (changed) {
756  break;
757  }
758  }
759 
760  if (changed) {
761  // Return a valid vector - replacements need to be made!
762  return NullableVector<Atom*>(versions);
763  } else {
764  // Return an invalid vector - no replacements need to be made
765  return NullableVector<Atom*>();
766  }
767 }
768 
769 /**
770  * Tries to perform a single step of inlining on the given literal.
771  * Returns a pair of nullable vectors (v, w) such that:
772  * - v is valid if and only if the literal can be directly inlined, whereby it
773  * contains the bodies that replace it

References souffle::clone(), getInlinedArgument(), i, and j.

Referenced by getInlinedLiteral().

Here is the call graph for this function:

◆ getInlinedClause()

std::vector<Clause*> souffle::ast::transform::getInlinedClause ( Program program,
const Clause clause 
)

Returns a list of clauses that should replace the given clause after one step of inlining.

If no inlining can occur, the list will only contain a clone of the original clause.

Definition at line 911 of file InlineRelations.cpp.

913  {
914  // The head atom can be inlined!
915  changed = true;
916 
917  // Produce the new clauses with the replacement head atoms
918  for (Atom* newHead : headVersions.getVector()) {
919  auto* newClause = new Clause();
920  newClause->setSrcLoc(clause.getSrcLoc());
921 
922  newClause->setHead(Own<Atom>(newHead));
923 
924  // The body will remain unchanged
925  for (Literal* lit : clause.getBodyLiterals()) {
926  newClause->addToBody(souffle::clone(lit));
927  }
928 
929  versions.push_back(newClause);
930  }
931  }
932 
933  // Only perform one stage of inlining at a time.
934  // If the head atoms did not need inlining, try inlining atoms nested in the body.
935  if (!changed) {
936  std::vector<Literal*> bodyLiterals = clause.getBodyLiterals();
937  for (size_t i = 0; i < bodyLiterals.size(); i++) {
938  Literal* currLit = bodyLiterals[i];
939 
940  // Three possible cases when trying to inline a literal:
941  // 1) The literal itself may be directly inlined. In this case, the atom can be replaced
942  // with multiple different bodies, as the inlined atom may have several rules.
943  // 2) Otherwise, the literal itself may not need to be inlined, but a subnode (e.g. an argument)
944  // may need to be inlined. In this case, an altered literal must replace the original.
945  // Again, several possible versions may exist, as the inlined relation may have several rules.
946  // 3) The literal does not depend on any inlined relations, and so does not need to be changed.
947  NullableVector<std::vector<Literal*>> litVersions = getInlinedLiteral(program, currLit);
948 
949  if (litVersions.isValid()) {
950  // Case 1 and 2: Inlining has occurred!
951  changed = true;
952 
953  // The literal may be replaced with several different bodies.
954  // Create a new clause for each possible version.
955  std::vector<std::vector<Literal*>> bodyVersions = litVersions.getVector();
956 
957  // Create the base clause with the current literal removed
958  auto baseClause = Own<Clause>(cloneHead(&clause));
959  for (Literal* oldLit : bodyLiterals) {
960  if (currLit != oldLit) {
961  baseClause->addToBody(souffle::clone(oldLit));
962  }
963  }
964 
965  for (std::vector<Literal*> body : bodyVersions) {
966  Clause* replacementClause = baseClause->clone();
967 
968  // Add in the current set of literals replacing the inlined literal
969  // In Case 2, each body contains exactly one literal
970  for (Literal* newLit : body) {
971  replacementClause->addToBody(Own<Literal>(newLit));
972  }
973 
974  versions.push_back(replacementClause);
975  }
976  }
977 
978  // Only replace at most one literal per iteration
979  if (changed) {
980  break;
981  }
982  }
983  }
984 
985  if (!changed) {
986  // Case 3: No inlining changes, so a clone of the original should be returned
987  std::vector<Clause*> ret;
988  ret.push_back(clause.clone());
989  return ret;
990  } else {
991  // Inlining changes, so return the replacement clauses.
992  return versions;
993  }
994 }
995 
996 bool InlineRelationsTransformer::transform(TranslationUnit& translationUnit) {
997  bool changed = false;
998  Program& program = translationUnit.getProgram();
999 
1000  // Replace constants in the head of inlined clauses with (constrained) variables.

◆ getInlinedLiteral()

NullableVector< std::vector< Literal * > > souffle::ast::transform::getInlinedLiteral ( Program program,
Literal lit 
)

Tries to perform a single step of inlining on the given literal.

Returns a pair of nullable vectors (v, w) such that:

  • v is valid if and only if the literal can be directly inlined, whereby it contains the bodies that replace it
  • if v is not valid, then w is valid if and only if the literal cannot be inlined directly, but contains a subargument that can be. In this case, it will contain the versions that will replace it.
  • If both are invalid, then no more inlining can occur on this literal and we are done.

Definition at line 785 of file InlineRelations.cpp.

786  {
787  // Check if this atom is meant to be inlined
788  Relation* rel = getRelation(program, atom->getQualifiedName());
789 
790  if (rel->hasQualifier(RelationQualifier::INLINE)) {
791  // We found an atom in the clause that needs to be inlined!
792  // The clause needs to be replaced
793  inlined = true;
794 
795  // N new clauses should be formed, where N is the number of clauses
796  // associated with the inlined relation
797  for (Clause* inClause : getClauses(program, *rel)) {
798  // Form the replacement clause
799  std::pair<NullableVector<Literal*>, std::vector<BinaryConstraint*>> inlineResult =
800  inlineBodyLiterals(atom, inClause);
801  NullableVector<Literal*> replacementBodyLiterals = inlineResult.first;
802  std::vector<BinaryConstraint*> currConstraints = inlineResult.second;
803 
804  if (!replacementBodyLiterals.isValid()) {
805  // Failed to unify the atoms! We can skip this one...
806  continue;
807  }
808 
809  // Unification successful - the returned vector of literals represents one possible body
810  // replacement We can add in the unification constraints as part of these literals.
811  std::vector<Literal*> bodyResult = replacementBodyLiterals.getVector();
812 
813  for (BinaryConstraint* cons : currConstraints) {
814  bodyResult.push_back(cons);
815  }
816 
817  addedBodyLiterals.push_back(bodyResult);
818  }
819  } else {
820  // Not meant to be inlined, but a subargument may be
821  NullableVector<Atom*> atomVersions = getInlinedAtom(program, *atom);
822  if (atomVersions.isValid()) {
823  // Subnode needs to be inlined, so we have a vector of replacement atoms
824  changed = true;
825  for (Atom* newAtom : atomVersions.getVector()) {
826  versions.push_back(newAtom);
827  }
828  }
829  }
830  } else if (auto neg = dynamic_cast<Negation*>(lit)) {
831  // For negations, check the corresponding atom
832  Atom* atom = neg->getAtom();
833  NullableVector<std::vector<Literal*>> atomVersions = getInlinedLiteral(program, atom);
834 
835  if (atomVersions.isValid()) {
836  // The atom can be inlined
837  inlined = true;
838 
839  if (atomVersions.getVector().empty()) {
840  // No clauses associated with the atom, so just becomes a true literal
841  addedBodyLiterals.push_back({new BooleanConstraint(true)});
842  } else {
843  // Suppose an atom a(x) is inlined and has the following rules:
844  // - a(x) :- a11(x), a12(x).
845  // - a(x) :- a21(x), a22(x).
846  // Then, a(x) <- (a11(x) ^ a12(x)) v (a21(x) ^ a22(x))
847  // => !a(x) <- (!a11(x) v !a12(x)) ^ (!a21(x) v !a22(x))
848  // => !a(x) <- (!a11(x) ^ !a21(x)) v (!a11(x) ^ !a22(x)) v ...
849  // Essentially, produce every combination (m_1 ^ m_2 ^ ...) where m_i is a
850  // negated literal in the ith rule of a.
851  addedBodyLiterals = formNegatedLiterals(program, atom);
852  }
853  }
854  if (atomVersions.isValid()) {
855  for (const auto& curVec : atomVersions.getVector()) {
856  for (auto* cur : curVec) {
857  delete cur;
858  }
859  }
860  }
861  } else if (auto* constraint = dynamic_cast<BinaryConstraint*>(lit)) {
862  NullableVector<Argument*> lhsVersions = getInlinedArgument(program, constraint->getLHS());
863  if (lhsVersions.isValid()) {
864  changed = true;
865  for (Argument* newLhs : lhsVersions.getVector()) {
866  Literal* newLit = new BinaryConstraint(constraint->getBaseOperator(), Own<Argument>(newLhs),
867  souffle::clone(constraint->getRHS()));
868  versions.push_back(newLit);
869  }
870  } else {
871  NullableVector<Argument*> rhsVersions = getInlinedArgument(program, constraint->getRHS());
872  if (rhsVersions.isValid()) {
873  changed = true;
874  for (Argument* newRhs : rhsVersions.getVector()) {
875  Literal* newLit = new BinaryConstraint(constraint->getBaseOperator(),
876  souffle::clone(constraint->getLHS()), Own<Argument>(newRhs));
877  versions.push_back(newLit);
878  }
879  }
880  }
881  }
882 
883  if (changed) {
884  // Not inlined directly but found replacement literals
885  // Rewrite these as single-literal bodies
886  for (Literal* version : versions) {
887  std::vector<Literal*> newBody;
888  newBody.push_back(version);
889  addedBodyLiterals.push_back(newBody);
890  }
891  inlined = true;
892  }
893 
894  if (inlined) {
895  return NullableVector<std::vector<Literal*>>(addedBodyLiterals);
896  } else {
897  return NullableVector<std::vector<Literal*>>();
898  }
899 }
900 
901 /**
902  * Returns a list of clauses that should replace the given clause after one step of inlining.
903  * If no inlining can occur, the list will only contain a clone of the original clause.
904  */
905 std::vector<Clause*> getInlinedClause(Program& program, const Clause& clause) {

References souffle::ast::getClauses(), getInlinedAtom(), souffle::ast::getRelation(), souffle::INLINE, inlineBodyLiterals(), and rel().

Referenced by getInlinedArgument().

Here is the call graph for this function:

◆ inlineBodyLiterals()

std::pair<NullableVector<Literal*>, std::vector<BinaryConstraint*> > souffle::ast::transform::inlineBodyLiterals ( Atom atom,
Clause atomInlineClause 
)

Inlines the given atom based on a given clause.

Returns the vector of replacement literals and the necessary constraints. If unification is unsuccessful, the vector of literals is marked as invalid.

Definition at line 304 of file InlineRelations.cpp.

311  : public NodeMapper {
312  int varnum;
313  VariableRenamer(int varnum) : varnum(varnum) {}
314  Own<Node> operator()(Own<Node> node) const override {
315  if (auto* var = dynamic_cast<ast::Variable*>(node.get())) {
316  // Rename the variable
317  auto newVar = souffle::clone(var);
318  std::stringstream newName;
319  newName << "<inlined_" << var->getName() << "_" << varnum << ">";
320  newVar->setName(newName.str());
321  return newVar;
322  }
323  node->apply(*this);
324  return node;
325  }
326  };
327 
328  VariableRenamer update(inlineCount);
329  atomClause->apply(update);
330 
331  inlineCount++;
332 
333  // Get the constraints needed to unify the two atoms
334  NullableVector<std::pair<Argument*, Argument*>> res = unifyAtoms(atomClause->getHead(), atom);
335  if (res.isValid()) {
336  changed = true;
337  for (std::pair<Argument*, Argument*> pair : res.getVector()) {
338  // FIXME: float equiv (`FEQ`)
339  constraints.push_back(new BinaryConstraint(
340  BinaryConstraintOp::EQ, souffle::clone(pair.first), souffle::clone(pair.second)));
341  }
342 
343  // Add in the body of the current clause of the inlined atom
344  for (Literal* lit : atomClause->getBodyLiterals()) {
345  addedLits.push_back(lit->clone());
346  }
347  }
348 
349  if (changed) {
350  return std::make_pair(NullableVector<Literal*>(addedLits), constraints);
351  } else {
352  return std::make_pair(NullableVector<Literal*>(), constraints);
353  }
354 }
355 
356 /**
357  * Returns the negated version of a given literal
358  */
359 Literal* negateLiteral(Literal* lit) {
360  if (auto* atom = dynamic_cast<Atom*>(lit)) {

Referenced by formNegatedLiterals(), and getInlinedLiteral().

◆ makeInfoRelation()

Own<Relation> souffle::ast::transform::makeInfoRelation ( Clause originalClause,
size_t  originalClauseNum,
TranslationUnit translationUnit 
)

Definition at line 78 of file Provenance.cpp.

100  {
101  if (auto* var = dynamic_cast<ast::Variable*>(arg)) {
102  return toString(*var);
103  } else if (auto* constant = dynamic_cast<Constant*>(arg)) {
104  return toString(*constant);
105  }
106  if (isA<UnnamedVariable>(arg)) {
107  return "_";
108  }
109  if (isA<Functor>(arg)) {
110  return tfm::format("functor_%d", functorNumber++);
111  }
112  if (isA<Aggregator>(arg)) {
113  return tfm::format("agg_%d", aggregateNumber++);
114  }
115 
116  fatal("Unhandled argument type");
117  };
118 
119  // add head arguments
120  for (auto& arg : originalClause.getHead()->getArguments()) {
121  headVariables.push_back(getArgInfo(arg));
122  }
123 
124  // join variables in the head with commas
125  std::stringstream headVariableString;
126  headVariableString << join(headVariables, ",");
127 
128  // add an attribute to infoRelation for the head of clause
129  infoRelation->addAttribute(mk<Attribute>(std::string("head_vars"), QualifiedName("symbol")));
130  infoClauseHead->addArgument(mk<StringConstant>(toString(join(headVariables, ","))));
131 
132  // visit all body literals and add to info clause head
133  for (size_t i = 0; i < originalClause.getBodyLiterals().size(); i++) {
134  auto lit = originalClause.getBodyLiterals()[i];
135 
136  const Atom* atom = nullptr;
137  if (isA<Atom>(lit)) {
138  atom = static_cast<Atom*>(lit);
139  } else if (isA<Negation>(lit)) {
140  atom = static_cast<Negation*>(lit)->getAtom();
141  } else if (isA<ProvenanceNegation>(lit)) {
142  atom = static_cast<ProvenanceNegation*>(lit)->getAtom();
143  }
144 
145  // add an attribute for atoms and binary constraints
146  if (atom != nullptr || isA<BinaryConstraint>(lit)) {
147  infoRelation->addAttribute(
148  mk<Attribute>(std::string("rel_") + std::to_string(i), QualifiedName("symbol")));
149  }
150 
151  if (atom != nullptr) {
152  std::string relName = toString(atom->getQualifiedName());
153 
154  // for an atom, add its name and variables (converting aggregates to variables)
155  if (isA<Atom>(lit)) {
156  std::string atomDescription = relName;
157 
158  for (auto& arg : atom->getArguments()) {
159  atomDescription.append("," + getArgInfo(arg));
160  }
161 
162  infoClauseHead->addArgument(mk<StringConstant>(atomDescription));
163  // for a negation, add a marker with the relation name
164  } else if (isA<Negation>(lit)) {
165  infoClauseHead->addArgument(mk<StringConstant>("!" + relName));
166  }
167  }
168  }
169 
170  // visit all body constraints and add to info clause head
171  for (size_t i = 0; i < originalClause.getBodyLiterals().size(); i++) {
172  auto lit = originalClause.getBodyLiterals()[i];
173 
174  if (auto con = dynamic_cast<BinaryConstraint*>(lit)) {
175  // for a constraint, add the constraint symbol and LHS and RHS
176  std::string constraintDescription = toBinaryConstraintSymbol(con->getBaseOperator());
177 
178  constraintDescription.append("," + getArgInfo(con->getLHS()));
179  constraintDescription.append("," + getArgInfo(con->getRHS()));
180 
181  infoClauseHead->addArgument(mk<StringConstant>(constraintDescription));
182  }
183  }
184 
185  infoRelation->addAttribute(mk<Attribute>("clause_repr", QualifiedName("symbol")));
186  infoClauseHead->addArgument(mk<StringConstant>(toString(originalClause)));
187 
188  // set clause head and add clause to info relation
189  infoClause->setHead(Own<Atom>(infoClauseHead));
190  Program& program = translationUnit.getProgram();
191  program.addClause(Own<Clause>(infoClause));
192 
193  return Own<Relation>(infoRelation);
194 }
195 
196 /** Transform eqrel relations to explicitly define equivalence relations */
197 void transformEqrelRelation(Program& program, Relation& rel) {
198  assert(rel.getRepresentation() == RelationRepresentation::EQREL &&
199  "attempting to transform non-eqrel relation");
200  assert(rel.getArity() == 2 && "eqrel relation not binary");

◆ makeRelationName()

QualifiedName souffle::ast::transform::makeRelationName ( const QualifiedName orig,
const std::string &  type,
int  num = -1 
)
inline

Helper functions.

Definition at line 68 of file Provenance.cpp.

73  {
74  QualifiedName name =
75  makeRelationName(originalClause.getHead()->getQualifiedName(), "@info", originalClauseNum);
76 

◆ nameInlinedUnderscores()

bool souffle::ast::transform::nameInlinedUnderscores ( Program program)

Removes all underscores in all atoms of inlined relations.

Definition at line 146 of file InlineRelations.cpp.

147  : inlinedRelations(std::move(inlinedRelations)), replaceUnderscores(replaceUnderscores) {}
148 
149  Own<Node> operator()(Own<Node> node) const override {
150  static int underscoreCount = 0;
151 
152  if (!replaceUnderscores) {
153  // Check if we should start replacing underscores for this node's subnodes
154  if (auto* atom = dynamic_cast<Atom*>(node.get())) {
155  if (inlinedRelations.find(atom->getQualifiedName()) != inlinedRelations.end()) {
156  // Atom associated with an inlined relation, so replace the underscores
157  // in all of its subnodes with named variables.
158  M replace(inlinedRelations, true);
159  node->apply(replace);
160  changed |= replace.changed;
161  return node;
162  }
163  }
164  } else if (isA<UnnamedVariable>(node.get())) {
165  // Give a unique name to the underscored variable
166  // TODO (azreika): need a more consistent way of handling internally generated variables in
167  // general
168  std::stringstream newVarName;
169  newVarName << "<underscore_" << underscoreCount++ << ">";
170  changed = true;
171  return mk<ast::Variable>(newVarName.str());
172  }
173 
174  node->apply(*this);
175  return node;
176  }
177  };
178 
179  // Store the names of all relations to be inlined
180  std::set<QualifiedName> inlinedRelations;
181  for (Relation* rel : program.getRelations()) {
182  if (rel->hasQualifier(RelationQualifier::INLINE)) {
183  inlinedRelations.insert(rel->getQualifiedName());
184  }
185  }
186 
187  // Apply the renaming procedure to the entire program
188  M update(inlinedRelations, false);
189  program.apply(update);
190  return update.changed;
191 }
192 
193 /**
194  * Checks if a given clause contains an atom that should be inlined.
195  */
196 bool containsInlinedAtom(const Program& program, const Clause& clause) {
197  bool foundInlinedAtom = false;

◆ negateLiteral()

Literal* souffle::ast::transform::negateLiteral ( Literal lit)

Returns the negated version of a given literal.

Definition at line 365 of file InlineRelations.cpp.

366  {
367  Constraint* newCons = cons->clone();
368  negateConstraintInPlace(*newCons);
369  return newCons;
370  }
371 
372  fatal("unsupported literal type: %s", *lit);
373 }
374 
375 /**
376  * Return the negated version of a disjunction of conjunctions.
377  * E.g. (a1(x) ^ a2(x) ^ ...) v (b1(x) ^ b2(x) ^ ...) --into-> (!a1(x) ^ !b1(x)) v (!a2(x) ^ !b2(x)) v ...
378  */
379 std::vector<std::vector<Literal*>> combineNegatedLiterals(std::vector<std::vector<Literal*>> litGroups) {

◆ normaliseInlinedHeads()

bool souffle::ast::transform::normaliseInlinedHeads ( Program program)

Replace constants in the head of inlined clauses with (constrained) variables.

Definition at line 93 of file InlineRelations.cpp.

93  {
94  continue;
95  }
96 
97  for (Clause* clause : getClauses(program, *rel)) {
98  // Set up the new clause with an empty body and no arguments in the head
99  auto newClause = mk<Clause>();
100  newClause->setSrcLoc(clause->getSrcLoc());
101  auto clauseHead = mk<Atom>(clause->getHead()->getQualifiedName());
102 
103  // Add in everything in the original body
104  for (Literal* lit : clause->getBodyLiterals()) {
105  newClause->addToBody(souffle::clone(lit));
106  }
107 
108  // Set up the head arguments in the new clause
109  for (Argument* arg : clause->getHead()->getArguments()) {
110  if (auto* constant = dynamic_cast<Constant*>(arg)) {
111  // Found a constant in the head, so replace it with a variable
112  std::stringstream newVar;
113  newVar << "<new_var_" << newVarCount++ << ">";
114  clauseHead->addArgument(mk<ast::Variable>(newVar.str()));
115 
116  // Add a body constraint to set the variable's value to be the original constant
117  newClause->addToBody(mk<BinaryConstraint>(BinaryConstraintOp::EQ,
118  mk<ast::Variable>(newVar.str()), souffle::clone(constant)));
119  } else {
120  // Already a variable
121  clauseHead->addArgument(souffle::clone(arg));
122  }
123  }
124 
125  newClause->setHead(std::move(clauseHead));
126 
127  // Replace the old clause with this one
128  program.addClause(std::move(newClause));
129  program.removeClause(clause);
130  changed = true;
131  }
132  }
133 
134  return changed;
135 }
136 
137 /**
138  * Removes all underscores in all atoms of inlined relations
139  */
140 bool nameInlinedUnderscores(Program& program) {
141  struct M : public NodeMapper {

◆ reduceSubstitution()

bool souffle::ast::transform::reduceSubstitution ( std::vector< std::pair< Argument *, Argument * >> &  sub)

Reduces a vector of substitutions.

Returns false only if matched argument pairs are found to be incompatible.

Definition at line 219 of file InlineRelations.cpp.

221  {
222  auto currPair = sub[i];
223  Argument* lhs = currPair.first;
224  Argument* rhs = currPair.second;
225 
226  // Start trying to reduce the substitution
227  // Note: Can probably go further with this substitution reduction
228  if (*lhs == *rhs) {
229  // Get rid of redundant `x = x`
230  sub.erase(sub.begin() + i);
231  done = false;
232  } else if (isA<Constant>(lhs) && isA<Constant>(rhs)) {
233  // Both are constants but not equal (prev case => !=)
234  // Failed to unify!
235  return false;
236  } else if (isA<RecordInit>(lhs) && isA<RecordInit>(rhs)) {
237  // Note: we will not deal with the case where only one side is
238  // a record and the other is a variable, as variables can be records
239  // on a deeper level.
240  std::vector<Argument*> lhsArgs = static_cast<RecordInit*>(lhs)->getArguments();
241  std::vector<Argument*> rhsArgs = static_cast<RecordInit*>(rhs)->getArguments();
242 
243  if (lhsArgs.size() != rhsArgs.size()) {
244  // Records of unequal size can't be equated
245  return false;
246  }
247 
248  // Equate all corresponding arguments
249  for (size_t i = 0; i < lhsArgs.size(); i++) {
250  sub.push_back(std::make_pair(lhsArgs[i], rhsArgs[i]));
251  }
252 
253  // Get rid of the record equality
254  sub.erase(sub.begin() + i);
255  done = false;
256  } else if ((isA<RecordInit>(lhs) && isA<Constant>(rhs)) ||
257  (isA<Constant>(lhs) && isA<RecordInit>(rhs))) {
258  // A record =/= a constant
259  return false;
260  }
261  }
262  }
263 
264  return true;
265 }
266 
267 /**
268  * Returns the nullable vector of substitutions needed to unify the two given atoms.
269  * If unification is not successful, the returned vector is marked as invalid.
270  * Assumes that the atoms are both of the same relation.
271  */

References i, lhs, rhs, and souffle::ast::analysis::sub().

Here is the call graph for this function:

◆ renameVariables()

void souffle::ast::transform::renameVariables ( Argument arg)

Renames all variables in a given argument uniquely.

Definition at line 494 of file InlineRelations.cpp.

494  : varnum(varnum) {}
495  Own<Node> operator()(Own<Node> node) const override {
496  if (auto* var = dynamic_cast<ast::Variable*>(node.get())) {
497  auto newVar = souffle::clone(var);
498  std::stringstream newName;
499  newName << var->getName() << "-v" << varnum;
500  newVar->setName(newName.str());
501  return newVar;
502  }
503  node->apply(*this);
504  return node;
505  }
506  };
507 
508  M update(varCount);
509  arg->apply(update);
510 }
511 
512 // Performs a given binary op on a list of aggregators recursively.
513 // E.g. ( <aggr1, aggr2, aggr3, ...>, o > = (aggr1 o (aggr2 o (agg3 o (...))))
514 // TODO (azreika): remove aggregator support
515 Argument* combineAggregators(std::vector<Aggregator*> aggrs, std::string fun) {
516  // Due to variable scoping issues with aggregators, we rename all variables uniquely in the

◆ transformEqrelRelation()

void souffle::ast::transform::transformEqrelRelation ( Program program,
Relation rel 
)

Transform eqrel relations to explicitly define equivalence relations.

Definition at line 203 of file Provenance.cpp.

255  {
256 Own<Argument> getNextLevelNumber(const std::vector<Argument*>& levels) {
257  if (levels.empty()) return mk<NumericConstant>(0);
258 
259  auto max = levels.size() == 1

◆ unifyAtoms()

NullableVector<std::pair<Argument*, Argument*> > souffle::ast::transform::unifyAtoms ( Atom first,
Atom second 
)

Returns the nullable vector of substitutions needed to unify the two given atoms.

If unification is not successful, the returned vector is marked as invalid. Assumes that the atoms are both of the same relation.

Definition at line 278 of file InlineRelations.cpp.

279  {
280  substitution.push_back(std::make_pair(firstArgs[i], secondArgs[i]));
281  }
282 
283  // Reduce the substitutions
284  bool success = reduceSubstitution(substitution);
285  if (success) {
286  return NullableVector<std::pair<Argument*, Argument*>>(substitution);
287  } else {
288  // Failed to unify the two atoms
289  return NullableVector<std::pair<Argument*, Argument*>>();
290  }
291 }
292 
293 /**
294  * Inlines the given atom based on a given clause.
295  * Returns the vector of replacement literals and the necessary constraints.
296  * If unification is unsuccessful, the vector of literals is marked as invalid.
297  */

References i.

◆ usesInvalidWitness()

static const std::vector<SrcLocation> souffle::ast::transform::usesInvalidWitness ( TranslationUnit tu,
const Clause clause,
const Aggregator aggregate 
)
static

A witness is considered "invalid" if it is trying to export a witness out of a count, sum, or mean aggregate.

However we need to be careful: Sometimes a witness variables occurs within the body of a count, sum, or mean aggregate, but this is valid, because the witness actually belongs to an inner min or max aggregate.

We just need to check that that witness only occurs on this level.

Definition at line 647 of file SemanticChecker.cpp.

651  : aggregate.getBodyLiterals()) {
652  aggregateSubclause->addToBody(souffle::clone(lit));
653  }
654  struct InnerAggregateMasker : public NodeMapper {
655  mutable int numReplaced = 0;
656  Own<Node> operator()(Own<Node> node) const override {
657  if (isA<Aggregator>(node.get())) {
658  std::string newVariableName = "+aggr_var_" + toString(numReplaced++);
659  return mk<Variable>(newVariableName);
660  }
661  node->apply(*this);
662  return node;
663  }
664  };
665  InnerAggregateMasker update;
666  aggregateSubclause->apply(update);
667 
668  // Find the witnesses of the original aggregate.
669  // If we can find occurrences of the witness in
670  // this masked version of the aggregate subclause,
671  // AND the aggregate is a sum / count / mean (we know this because
672  // of the early exit for a min/max aggregate)
673  // then we have an invalid witness and we'll add the source location
674  // of the variable to the invalidWitnessLocations vector.
675  auto witnesses = analysis::getWitnessVariables(tu, clause, aggregate);
676  for (const auto& witness : witnesses) {
677  visitDepthFirst(*aggregateSubclause, [&](const Variable& var) {
678  if (var.getName() == witness) {
679  invalidWitnessLocations.push_back(var.getSrcLoc());
680  }
681  });
682  }
683  return invalidWitnessLocations;
684 }
685 
686 void SemanticCheckerImpl::checkWitnessProblem() {
687  // Check whether there is the use of a witness in
688  // an aggregate where it doesn't make sense to use it, i.e.
689  // count, sum, mean
690  visitDepthFirst(program, [&](const Clause& clause) {
souffle::ast::cloneHead
Clause * cloneHead(const Clause *clause)
Returns a clause which contains head of the given clause.
Definition: Utils.cpp:254
TCB_SPAN_NAMESPACE_NAME::detail::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.h:198
UNREACHABLE_BAD_CASE_ANALYSIS
#define UNREACHABLE_BAD_CASE_ANALYSIS
Definition: MiscUtil.h:206
souffle::ast::transform::renameVariables
void renameVariables(Argument *arg)
Renames all variables in a given argument uniquely.
Definition: InlineRelations.cpp:494
souffle::ast::transform::reduceSubstitution
bool reduceSubstitution(std::vector< std::pair< Argument *, Argument * >> &sub)
Reduces a vector of substitutions.
Definition: InlineRelations.cpp:219
tinyformat::format
void format(std::ostream &out, const char *fmt)
Definition: tinyformat.h:1089
souffle::ast::analysis::sub
std::shared_ptr< Constraint< Var > > sub(const Var &a, const Var &b, const std::string &symbol="⊑")
A generic factory for constraints of the form.
Definition: ConstraintSystem.h:228
souffle::ast::transform::nameInlinedUnderscores
bool nameInlinedUnderscores(Program &program)
Removes all underscores in all atoms of inlined relations.
Definition: InlineRelations.cpp:146
souffle::AggregateOp
AggregateOp
Types of aggregation functions.
Definition: AggregateOp.h:34
souffle::toBinaryConstraintSymbol
char const * toBinaryConstraintSymbol(const BinaryConstraintOp op)
Converts operator to its symbolic representation.
Definition: BinaryConstraintOps.h:336
rhs
Own< Argument > rhs
Definition: ResolveAliases.cpp:185
j
var j
Definition: htmlJsChartistMin.h:15
lhs
Own< Argument > lhs
Definition: ResolveAliases.cpp:184
souffle::toString
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
Definition: StringUtil.h:234
souffle::ast::transform::findInlineCycle
std::vector< QualifiedName > findInlineCycle(const PrecedenceGraphAnalysis &precedenceGraph, std::map< const Relation *, const Relation * > &origins, const Relation *current, RelationSet &unvisited, RelationSet &visiting, RelationSet &visited)
Find a cycle consisting entirely of inlined relations.
Definition: SemanticChecker.cpp:713
souffle::ast::transform::containsInlinedAtom
bool containsInlinedAtom(const Program &program, const Clause &clause)
Checks if a given clause contains an atom that should be inlined.
Definition: InlineRelations.cpp:202
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
souffle::ast::transform::combineNegatedLiterals
std::vector< std::vector< Literal * > > combineNegatedLiterals(std::vector< std::vector< Literal * >> litGroups)
Return the negated version of a disjunction of conjunctions.
Definition: InlineRelations.cpp:385
i
size_t i
Definition: json11.h:663
souffle::ast::getRelation
Relation * getRelation(const Program &program, const QualifiedName &name)
Returns the relation with the given name in the program.
Definition: Utils.cpp:101
souffle::ast::transform::getInlinedClause
std::vector< Clause * > getInlinedClause(Program &program, const Clause &clause)
Returns a list of clauses that should replace the given clause after one step of inlining.
Definition: InlineRelations.cpp:911
souffle::ast::transform::getInlinedAtom
NullableVector< Atom * > getInlinedAtom(Program &program, Atom &atom)
Returns a vector of atoms that should replace the given atom after one step of inlining.
Definition: InlineRelations.cpp:729
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::ast::transform::negateLiteral
Literal * negateLiteral(Literal *lit)
Returns the negated version of a given literal.
Definition: InlineRelations.cpp:365
souffle::ast::transform::getInlinedLiteral
NullableVector< std::vector< Literal * > > getInlinedLiteral(Program &, Literal *)
Tries to perform a single step of inlining on the given literal.
Definition: InlineRelations.cpp:785
souffle::ast::RelationSet
std::set< const Relation *, NameComparison > RelationSet
Relation set.
Definition: Relation.h:180
souffle::ast::getClauses
std::vector< Clause * > getClauses(const Program &program, const QualifiedName &relationName)
Returns a vector of clauses in the program describing the relation with the given name.
Definition: Utils.cpp:77
souffle::ast::transform::transformEqrelRelation
void transformEqrelRelation(Program &program, Relation &rel)
Transform eqrel relations to explicitly define equivalence relations.
Definition: Provenance.cpp:203
souffle::ast::transform::unifyAtoms
NullableVector< std::pair< Argument *, Argument * > > unifyAtoms(Atom *first, Atom *second)
Returns the nullable vector of substitutions needed to unify the two given atoms.
Definition: InlineRelations.cpp:278
souffle::ast::transform::makeRelationName
QualifiedName makeRelationName(const QualifiedName &orig, const std::string &type, int num=-1)
Helper functions.
Definition: Provenance.cpp:68
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
souffle::ast::negateConstraintInPlace
void negateConstraintInPlace(Constraint &constraint)
Negate an ast constraint.
Definition: Utils.cpp:297
souffle::ast::transform::formNegatedLiterals
std::vector< std::vector< Literal * > > formNegatedLiterals(Program &program, Atom *atom)
Forms the bodies that will replace the negation of a given inlined atom.
Definition: InlineRelations.cpp:440
souffle::ast::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:273
souffle::ast::transform::inlineBodyLiterals
std::pair< NullableVector< Literal * >, std::vector< BinaryConstraint * > > inlineBodyLiterals(Atom *atom, Clause *atomInlineClause)
Inlines the given atom based on a given clause.
Definition: InlineRelations.cpp:304
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::ast::transform::combineAggregators
Argument * combineAggregators(std::vector< Aggregator * > aggrs, std::string fun)
Definition: InlineRelations.cpp:521
souffle::ast::analysis::getWitnessVariables
std::set< std::string > getWitnessVariables(const TranslationUnit &tu, const Clause &clause, const Aggregator &aggregate)
Computes the set of witness variables that are used in the aggregate A variable is a witness if it oc...
Definition: Aggregate.cpp:75
souffle::ast::transform::getInlinedArgument
NullableVector< Argument * > getInlinedArgument(Program &program, const Argument *arg)
Returns a vector of arguments that should replace the given argument after one step of inlining.
Definition: InlineRelations.cpp:543