1277 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1277 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <queue>
 | |
| 
 | |
| #include <iostream>
 | |
| #include <ostream>
 | |
| #include <fstream>
 | |
| 
 | |
| #include "ConstraintTree.h"
 | |
| #include "Util.h"
 | |
| 
 | |
| 
 | |
| namespace Horus {
 | |
| 
 | |
| class CTNode {
 | |
|   public:
 | |
|     CTNode (const CTNode& n, const CTChilds& chs = CTChilds()) 
 | |
|         : symbol_(n.symbol()), childs_(chs), level_(n.level()) { }
 | |
| 
 | |
|     CTNode (Symbol s, unsigned l, const CTChilds& chs = CTChilds())
 | |
|         : symbol_(s), childs_(chs), level_(l) { }
 | |
| 
 | |
|     unsigned level() const { return level_; }
 | |
| 
 | |
|     void setLevel (unsigned level) { level_ = level; }
 | |
| 
 | |
|     Symbol symbol() const { return symbol_; }
 | |
| 
 | |
|     void setSymbol (Symbol s) { symbol_ = s; }
 | |
| 
 | |
|     CTChilds& childs() { return childs_; }
 | |
| 
 | |
|     const CTChilds& childs() const { return childs_; }
 | |
| 
 | |
|     size_t nrChilds() const { return childs_.size(); }
 | |
| 
 | |
|     bool isRoot() const { return level_ == 0; }
 | |
| 
 | |
|     bool isLeaf() const { return childs_.empty(); }
 | |
| 
 | |
|     CTChilds::iterator findSymbol (Symbol symb);
 | |
| 
 | |
|     void mergeSubtree (CTNode*, bool = true);
 | |
| 
 | |
|     void removeChild (CTNode*);
 | |
| 
 | |
|     void removeChilds();
 | |
| 
 | |
|     void removeAndDeleteChild (CTNode*);
 | |
| 
 | |
|     void removeAndDeleteAllChilds();
 | |
| 
 | |
|     SymbolSet childSymbols() const;
 | |
| 
 | |
|     static CTNode* copySubtree (const CTNode*);
 | |
| 
 | |
|     static void deleteSubtree (CTNode*);
 | |
| 
 | |
|   private:
 | |
|     void updateChildLevels (CTNode*, unsigned);
 | |
| 
 | |
|     Symbol     symbol_;
 | |
|     CTChilds   childs_;
 | |
|     unsigned   level_;
 | |
| 
 | |
|     DISALLOW_ASSIGN (CTNode);
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| inline CTChilds::iterator
 | |
| CTNode::findSymbol (Symbol symb)
 | |
| {
 | |
|   CTNode tmp (symb, 0);
 | |
|   return childs_.find (&tmp);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| inline bool
 | |
| CmpSymbol::operator() (const CTNode* n1, const CTNode* n2) const
 | |
| {
 | |
|   return n1->symbol() < n2->symbol();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::mergeSubtree (CTNode* n, bool updateLevels)
 | |
| {
 | |
|   if (updateLevels) {
 | |
|     updateChildLevels (n, level_ + 1);
 | |
|   }
 | |
|   CTChilds::iterator chIt = childs_.find (n);
 | |
|   if (chIt != childs_.end()) {
 | |
|     assert ((*chIt)->symbol() == n->symbol());
 | |
|     const CTChilds& childsToAdd = n->childs();
 | |
|     for (CTChilds::const_iterator it = childsToAdd.begin();
 | |
|          it != childsToAdd.end(); ++ it) {
 | |
|       (*chIt)->mergeSubtree (*it, false);
 | |
|     }
 | |
|     delete n;
 | |
|   } else {
 | |
|     childs_.insert (n);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::removeChild (CTNode* child)
 | |
| {
 | |
|   assert (childs_.contains (child));
 | |
|   childs_.remove (child);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::removeChilds()
 | |
| {
 | |
|   childs_.clear();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::removeAndDeleteChild (CTNode* child)
 | |
| {
 | |
|   removeChild (child);
 | |
|   CTNode::deleteSubtree (child);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::removeAndDeleteAllChilds()
 | |
| {
 | |
|   for (CTChilds::const_iterator chIt = childs_.begin();
 | |
|        chIt != childs_.end(); ++ chIt) {
 | |
|     deleteSubtree (*chIt);
 | |
|   }
 | |
|   childs_.clear();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| SymbolSet
 | |
| CTNode::childSymbols() const
 | |
| {
 | |
|   SymbolSet symbols;
 | |
|   for (CTChilds::const_iterator chIt = childs_.begin();
 | |
|        chIt != childs_.end(); ++ chIt) {
 | |
|     symbols.insert ((*chIt)->symbol());
 | |
|   }
 | |
|   return symbols;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::updateChildLevels (CTNode* n, unsigned level)
 | |
| {
 | |
|   CTNodes stack;
 | |
|   stack.push_back (n);
 | |
|   n->setLevel (level);
 | |
|   while (stack.empty() == false) {
 | |
|     CTNode* node = stack.back();
 | |
|     stack.pop_back();
 | |
|     for (CTChilds::const_iterator chIt = node->childs().begin();
 | |
|          chIt != node->childs().end(); ++ chIt) {
 | |
|       (*chIt)->setLevel (node->level() + 1);
 | |
|     }
 | |
|     stack.insert (stack.end(), node->childs().begin(),
 | |
|         node->childs().end());
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| CTNode*
 | |
| CTNode::copySubtree (const CTNode* root1)
 | |
| {
 | |
|   if (root1->childs().empty()) {
 | |
|     return new CTNode (*root1);
 | |
|   }
 | |
|   CTNode* root2 = new CTNode (*root1);
 | |
|   typedef std::pair<const CTNode*, CTNode*> StackPair;
 | |
|   std::vector<StackPair> stack = { StackPair (root1, root2) };
 | |
|   while (stack.empty() == false) {
 | |
|     const CTNode* n1 = stack.back().first;
 | |
|     CTNode* n2 = stack.back().second;
 | |
|     stack.pop_back();
 | |
|     // std::cout << "n2 childs: " << n2->childs();
 | |
|     // std::cout << "n1 childs: " << n1->childs();
 | |
|     n2->childs().reserve (n1->nrChilds());
 | |
|     stack.reserve (n1->nrChilds());
 | |
|     for (CTChilds::const_iterator chIt = n1->childs().begin();
 | |
|          chIt != n1->childs().end(); ++ chIt) {
 | |
|       CTNode* chCopy = new CTNode (**chIt);
 | |
|       n2->childs().insert_sorted (chCopy);
 | |
|       if ((*chIt)->nrChilds() > 0) {
 | |
|         stack.push_back (StackPair (*chIt, chCopy));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return root2;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| CTNode::deleteSubtree (CTNode* n)
 | |
| {
 | |
|   assert (n);
 | |
|   const CTChilds& childs = n->childs();
 | |
|   for (CTChilds::const_iterator chIt = childs.begin();
 | |
|        chIt != childs.end(); ++ chIt) {
 | |
|     deleteSubtree (*chIt);
 | |
|   }
 | |
|   delete n;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| std::ostream&
 | |
| operator<< (std::ostream& out, const CTNode& n)
 | |
| {
 | |
|   out << "(" << n.level() << ") " ;
 | |
|   out << n.symbol();
 | |
|   return out;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::ConstraintTree (unsigned nrLvs)
 | |
| {
 | |
|   for (unsigned i = 0; i < nrLvs; i++) {
 | |
|     logVars_.push_back (LogVar (i));
 | |
|   }
 | |
|   root_      = new CTNode (0, 0);
 | |
|   logVarSet_ = LogVarSet (logVars_);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::ConstraintTree (const LogVars& logVars)
 | |
| {
 | |
|   root_      = new CTNode (0, 0);
 | |
|   logVars_   = logVars;
 | |
|   logVarSet_ = LogVarSet (logVars);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::ConstraintTree (
 | |
|     const LogVars& logVars,
 | |
|     const Tuples&  tuples)
 | |
| {
 | |
|   root_      = new CTNode (0, 0);
 | |
|   logVars_   = logVars;
 | |
|   logVarSet_ = LogVarSet (logVars);
 | |
|   for (size_t i = 0; i < tuples.size(); i++) {
 | |
|     addTuple (tuples[i]);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::ConstraintTree (
 | |
|      std::vector<std::vector<std::string>> names)
 | |
| {
 | |
|   assert (names.empty() == false);
 | |
|   assert (names.front().empty() == false);
 | |
|   unsigned nrLvs = names[0].size();
 | |
|   for (size_t i = 0; i < nrLvs; i++) {
 | |
|     logVars_.push_back (LogVar (i));
 | |
|   }
 | |
|   root_      = new CTNode (0, 0);
 | |
|   logVarSet_ = LogVarSet (logVars_);
 | |
|   for (size_t i = 0; i < names.size(); i++) {
 | |
|     Tuple t;
 | |
|     for (size_t j = 0; j < names[i].size(); j++) {
 | |
|       assert (names[i].size() == nrLvs);
 | |
|       t.push_back (LiftedUtils::getSymbol (names[i][j]));
 | |
|     }
 | |
|     addTuple (t);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::ConstraintTree (const ConstraintTree& ct)
 | |
| {
 | |
|   *this = ct;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::ConstraintTree (
 | |
|     const CTChilds& rootChilds,
 | |
|     const LogVars& logVars)
 | |
|         : root_(new CTNode (Symbol (0), unsigned (0), rootChilds)),
 | |
|           logVars_(logVars),
 | |
|           logVarSet_(logVars)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree::~ConstraintTree()
 | |
| {
 | |
|   CTNode::deleteSubtree (root_);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool
 | |
| ConstraintTree::empty() const
 | |
| {
 | |
|   return root_->childs().empty();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::addTuple (const Tuple& tuple)
 | |
| {
 | |
|   CTNode* prevNode = root_;
 | |
|   for (size_t i = 0; i < tuple.size(); i++) {
 | |
|     CTChilds::const_iterator it = prevNode->findSymbol (tuple[i]);
 | |
|     if (it == prevNode->childs().end()) {
 | |
|       CTNode* newNode = new CTNode (tuple[i], i + 1);
 | |
|       prevNode->mergeSubtree (newNode, false);
 | |
|       prevNode = newNode;
 | |
|     } else {
 | |
|       prevNode  = *it;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool
 | |
| ConstraintTree::containsTuple (const Tuple& tuple)
 | |
| {
 | |
| 	CTNode* prevNode = root_;
 | |
|   for (size_t i = 0; i < tuple.size(); i++) {
 | |
|     CTChilds::const_iterator it = prevNode->findSymbol (tuple[i]);
 | |
|     if (it == prevNode->childs().end()) {
 | |
|       return false;
 | |
|     } else {
 | |
|       prevNode = *it;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::moveToTop (const LogVars& lvs)
 | |
| {
 | |
|   for (size_t i = 0; i < lvs.size(); i++) {
 | |
|     size_t pos = Util::indexOf (logVars_, lvs[i]);
 | |
|     assert (pos != logVars_.size());
 | |
|     for (size_t j = pos; j-- > i; ) {
 | |
|       swapLogVar (logVars_[j]);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::moveToBottom (const LogVars& lvs)
 | |
| {
 | |
|   for (size_t i = lvs.size(); i-- > 0; ) {
 | |
|     size_t pos = Util::indexOf (logVars_, lvs[i]);
 | |
|     assert (pos != logVars_.size());
 | |
|     size_t stop = logVars_.size() - (lvs.size() - i - 1);
 | |
|     for (size_t j = pos; j < stop - 1; j++) {
 | |
|       swapLogVar (logVars_[j]);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::join (ConstraintTree* ct, bool oneTwoOne)
 | |
| {
 | |
|   if (logVarSet_.empty()) {
 | |
|     CTNode::deleteSubtree (root_);
 | |
|     root_      = CTNode::copySubtree (ct->root());
 | |
|     logVars_   = ct->logVars();
 | |
|     logVarSet_ = ct->logVarSet();
 | |
|     return;
 | |
|   }
 | |
|   if (oneTwoOne) {
 | |
|     if (logVarSet_.contains (ct->logVarSet())) {
 | |
|       return;
 | |
|     }
 | |
|     if (ct->logVarSet().contains (logVarSet_)) {
 | |
|       CTNode::deleteSubtree (root_);
 | |
|       root_      = CTNode::copySubtree (ct->root());
 | |
|       logVars_   = ct->logVars();
 | |
|       logVarSet_ = ct->logVarSet();
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
|   LogVarSet intersect = logVarSet_ & ct->logVarSet_;
 | |
|   if (intersect.empty()) {
 | |
|     // cartesian product
 | |
|     appendOnBottom (root_, ct->root()->childs());
 | |
|     Util::addToVector (logVars_, ct->logVars_);
 | |
|     logVarSet_ |= ct->logVarSet_;
 | |
|   } else {
 | |
|     moveToTop (intersect.elements());
 | |
|     ct->moveToTop (intersect.elements());
 | |
| 
 | |
|     Tuples tuples;
 | |
|     CTNodes appendNodes;
 | |
|     getTuples (ct->root(), Tuples(), intersect.size(),
 | |
|         tuples, appendNodes);
 | |
| 
 | |
|     CTNodes::const_iterator appendIt = appendNodes.begin();
 | |
|     for (size_t i = 0; i < tuples.size(); ++ i, ++ appendIt) {
 | |
|       bool tupleFounded = join (root_, tuples[i], 0, *appendIt);
 | |
|       if (oneTwoOne && tupleFounded == false) {
 | |
|         assert (false);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     LogVars newLvs (ct->logVars().begin() + intersect.size(), 
 | |
|                     ct->logVars().end());
 | |
|     Util::addToVector (logVars_, newLvs);
 | |
|     logVarSet_ |= LogVarSet (newLvs);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| ConstraintTree::getLevel (LogVar X) const
 | |
| {
 | |
|   unsigned level = Util::indexOf (logVars_, X);
 | |
|   level += 1; // root is in level 0, first logVar is in level 1
 | |
|   return level;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::rename (LogVar X_old, LogVar X_new)
 | |
| {
 | |
|   assert (logVarSet_.contains (X_old));
 | |
|   assert (logVarSet_.contains (X_new) == false);
 | |
|   logVarSet_ -= X_old;
 | |
|   logVarSet_ |= X_new;
 | |
|   for (size_t i = 0; i < logVars_.size(); i++) {
 | |
|     if (logVars_[i] == X_old) {
 | |
|       logVars_[i] = X_new;
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
|   assert (false);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::applySubstitution (const Substitution& theta)
 | |
| {
 | |
|   for (size_t i = 0; i < logVars_.size(); i++) {
 | |
|     logVars_[i] = theta.newNameFor (logVars_[i]);
 | |
|   }
 | |
|   logVarSet_ = LogVarSet (logVars_);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::project (const LogVarSet& X)
 | |
| {
 | |
|   assert (logVarSet_.contains (X));
 | |
|   remove ((logVarSet_ - X));
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree
 | |
| ConstraintTree::projectedCopy (const LogVarSet& X)
 | |
| {
 | |
|   ConstraintTree copy = *this;
 | |
|   copy.project (X);
 | |
|   return copy;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::remove (const LogVarSet& X)
 | |
| {
 | |
|   assert (logVarSet_.contains (X));
 | |
|   if (X.empty()) {
 | |
|     return;
 | |
|   }
 | |
|   moveToBottom (X.elements());
 | |
|   unsigned level = getLevel (X.front()) - 1;
 | |
|   CTNodes nodes = getNodesAtLevel (level);
 | |
|   for (CTNodes::const_iterator it = nodes.begin();
 | |
|        it != nodes.end(); ++ it) {
 | |
|     (*it)->removeAndDeleteAllChilds();
 | |
|   }
 | |
|   logVars_.resize (logVars_.size() - X.size());
 | |
|   logVarSet_ -= X;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool
 | |
| ConstraintTree::ConstraintTree::isSingleton (LogVar X)
 | |
| {
 | |
|   Symbol symb;
 | |
|   unsigned level = getLevel (X);
 | |
|   CTNodes stack;
 | |
|   stack.push_back (root_);
 | |
|   while (stack.empty() == false) {
 | |
|     CTNode* node = stack.back();
 | |
|     stack.pop_back();
 | |
|     if (node->level() == level) {
 | |
|       if (symb.valid()) {
 | |
|         if (node->symbol() != symb) {
 | |
|           return false;
 | |
|         }
 | |
|       } else {
 | |
|         symb = node->symbol();
 | |
|       }
 | |
|     } else {
 | |
|       stack.insert (stack.end(), node->childs().begin(),
 | |
|           node->childs().end());
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| LogVarSet
 | |
| ConstraintTree::singletons()
 | |
| {
 | |
|   LogVarSet singletons;
 | |
|   for (size_t i = 0; i < logVars_.size(); i++) {
 | |
|     if (isSingleton (logVars_[i])) {
 | |
|       singletons.insert (logVars_[i]);
 | |
|     }
 | |
|   }
 | |
|   return singletons;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| TupleSet
 | |
| ConstraintTree::tupleSet (unsigned stopLevel) const
 | |
| {
 | |
|   assert (root_->isRoot());
 | |
|   Tuples tuples;
 | |
|   if (stopLevel == 0) {
 | |
|     stopLevel = logVars_.size();
 | |
|   }
 | |
|   getTuples (root_, Tuples(), stopLevel, tuples, CTNodes() = {});
 | |
|   return TupleSet (tuples);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| TupleSet
 | |
| ConstraintTree::tupleSet (const LogVars& originalLvs)
 | |
| {
 | |
|   LogVars uniqueLvs;
 | |
|   for (size_t i = 0; i < originalLvs.size(); i++) {
 | |
|     if (Util::contains (uniqueLvs, originalLvs[i]) == false) {
 | |
|       uniqueLvs.push_back (originalLvs[i]);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Tuples tuples;
 | |
|   moveToTop (uniqueLvs);
 | |
|   unsigned stopLevel = uniqueLvs.size();
 | |
|   getTuples (root_, Tuples(), stopLevel, tuples, CTNodes() = {});
 | |
| 
 | |
|   if (originalLvs.size() != uniqueLvs.size()) {
 | |
|     std::vector<size_t> indexes;
 | |
|     indexes.reserve (originalLvs.size());
 | |
|     for (size_t i = 0; i < originalLvs.size(); i++) {
 | |
|       indexes.push_back (Util::indexOf (uniqueLvs, originalLvs[i]));
 | |
|     }
 | |
|     Tuples tuples2;
 | |
|     tuples2.reserve (tuples.size());
 | |
|     for (size_t i = 0; i < tuples.size(); i++) {
 | |
|       Tuple t;
 | |
|       t.reserve (originalLvs.size());
 | |
|       for (size_t j = 0; j < originalLvs.size(); j++) {
 | |
|         t.push_back (tuples[i][indexes[j]]);
 | |
|       }
 | |
|       tuples2.push_back (t);
 | |
|     }
 | |
|     return TupleSet (tuples2);
 | |
|   }
 | |
| 
 | |
|   return TupleSet (tuples);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::exportToGraphViz (
 | |
|     const char* fileName,
 | |
|     bool showLogVars) const
 | |
| {
 | |
|   std::ofstream out (fileName);
 | |
|   if (!out.is_open()) {
 | |
|     std::cerr << "Error: couldn't open file '" << fileName << "'." ;
 | |
|     std::cerr << std::endl;
 | |
|     return;
 | |
|   }
 | |
|   out << "digraph {" << std::endl;
 | |
|   ConstraintTree copy (*this);
 | |
|   copy.moveToTop (copy.logVarSet_.elements());
 | |
|   CTNodes nodes = getNodesBelow (copy.root_);
 | |
|   out << "\"" << copy.root_ << "\"" << " [label=\"R\"]" << std::endl;
 | |
|   for (CTNodes::const_iterator it = ++ nodes.begin();
 | |
|        it != nodes.end(); ++ it) {
 | |
|     out << "\"" << *it << "\"";
 | |
|     out << " [label=\"" << **it << "\"]" ;
 | |
|     out << std::endl;
 | |
|   }
 | |
|   for (CTNodes::const_iterator it = nodes.begin();
 | |
|        it != nodes.end(); ++ it) {
 | |
|     const CTChilds& childs = (*it)->childs();
 | |
|     for (CTChilds::const_iterator chIt = childs.begin();
 | |
|          chIt != childs.end(); ++ chIt) {
 | |
|       out << "\"" << *it << "\"" ;
 | |
|       out << " -> " ;
 | |
|       out << "\"" << *chIt << "\"" << std::endl ;
 | |
|     }
 | |
|   }
 | |
|   if (showLogVars) {
 | |
|     out << "Root [label=\"\", shape=plaintext]" << std::endl;
 | |
|     for (size_t i = 0; i < copy.logVars_.size(); i++) {
 | |
|       out << copy.logVars_[i] << " [label=" ;
 | |
|       out << copy.logVars_[i] << ", " ;
 | |
|       out << "shape=plaintext, fontsize=14]" << std::endl;
 | |
|     }
 | |
|    out << "Root -> " << copy.logVars_[0];
 | |
|    out << " [style=invis]" << std::endl;
 | |
|     for (size_t i = 0; i < copy.logVars_.size() - 1; i++) {
 | |
|       out << copy.logVars_[i] << " -> " << copy.logVars_[i + 1];
 | |
|       out << " [style=invis]" << std::endl;
 | |
|     }
 | |
|   }
 | |
|   out << "}" <<std::endl;
 | |
|   out.close();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool
 | |
| ConstraintTree::isCountNormalized (const LogVarSet& Ys)
 | |
| {
 | |
|   assert (logVarSet_.contains (Ys));
 | |
|   if (Ys.empty()) {
 | |
|     return true;
 | |
|   }
 | |
|   if (Ys.size() == logVars_.size()) {
 | |
|     assert (LogVarSet (logVars_) == LogVarSet (Ys));
 | |
|     return true;
 | |
|   }
 | |
|   LogVarSet Zs = logVarSet_ - LogVarSet (Ys);
 | |
|   moveToTop (Zs.elements());
 | |
|   CTNodes nodes = getNodesAtLevel (Zs.size());
 | |
|   unsigned count = countTuples (*nodes.begin());
 | |
|   for (CTNodes::const_iterator it = nodes.begin();
 | |
|        it != nodes.end(); ++ it) {
 | |
|     if (countTuples (*it) != count) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| ConstraintTree::getConditionalCount (const LogVarSet& Ys)
 | |
| {
 | |
|   assert (isCountNormalized (Ys));
 | |
|   if (Ys.empty()) {
 | |
|     return 1;
 | |
|   }
 | |
|   if (Ys.size() == logVars_.size()) {
 | |
|     assert (LogVarSet (Ys) == LogVarSet (logVars_));
 | |
|     return countTuples (root_);
 | |
|   }
 | |
|   LogVarSet Zs = logVarSet_ - Ys;
 | |
|   moveToTop (Zs.elements());
 | |
|   CTNode* n = root_;
 | |
|   unsigned l = 0;
 | |
|   while (l != Zs.size()) {
 | |
|     n = *(n->childs().begin());
 | |
|     l ++;
 | |
|   }
 | |
|   return countTuples (n);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| TinySet<unsigned>
 | |
| ConstraintTree::getConditionalCounts (const LogVarSet& Ys)
 | |
| {
 | |
|   TinySet<unsigned> counts;
 | |
|   assert (logVarSet_.contains (Ys));
 | |
|   if (Ys.empty()) {
 | |
|     counts.insert (1);
 | |
|   } else if (Ys.size() == logVars_.size()) {
 | |
|     assert (LogVarSet (logVars_) == LogVarSet (Ys));
 | |
|     counts.insert (countTuples (root_));
 | |
|   } else {
 | |
|     LogVarSet Zs = logVarSet_ - LogVarSet (Ys);
 | |
|     moveToTop (Zs.elements());
 | |
|     CTNodes nodes = getNodesAtLevel (Zs.size());
 | |
|     for (CTNodes::const_iterator it = nodes.begin();
 | |
|          it != nodes.end(); ++ it) {
 | |
|       counts.insert (countTuples (*it));
 | |
|     }
 | |
|   }
 | |
|   return counts;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool
 | |
| ConstraintTree::isCartesianProduct (const LogVarSet& Xs)
 | |
| {
 | |
|   assert (logVarSet_.contains (Xs));
 | |
|   if (Xs.size() <= 1) {
 | |
|     return true;
 | |
|   }
 | |
|   moveToTop (Xs.elements());
 | |
|   for (size_t i = 1; i < Xs.size(); i++) {
 | |
|     CTNodes nodes = getNodesAtLevel (i);
 | |
|     for (size_t j = 1; j < nodes.size(); j++) {
 | |
|       if (nodes[j-1]->nrChilds() != nodes[ j ]->nrChilds()) {
 | |
|         return false;
 | |
|       }
 | |
|       if (nodes[j-1]->childSymbols() != nodes[ j ]->childSymbols()) {
 | |
|         return false;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| std::pair<ConstraintTree*,ConstraintTree*>
 | |
| ConstraintTree::split (const Tuple& tuple)
 | |
| {
 | |
|   // assumes that my log vars are already on top
 | |
|   LogVars lvs (logVars_.begin(), logVars_.begin() + tuple.size());
 | |
|   ConstraintTree tempCt (logVars_, {tuple});
 | |
|   return split (lvs, &tempCt, lvs);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| std::pair<ConstraintTree*, ConstraintTree*>
 | |
| ConstraintTree::split (
 | |
|     const LogVars& lvs1,
 | |
|     ConstraintTree* ct,
 | |
|     const LogVars& lvs2)
 | |
| {
 | |
|   assert (lvs1.size() == lvs2.size());
 | |
|   assert (lvs1.size() == LogVarSet (lvs1).size());
 | |
|   assert (lvs2.size() == LogVarSet (lvs2).size());
 | |
|   assert (logVarSet_.contains (lvs1));
 | |
|   assert (ct->logVarSet().contains (lvs2));
 | |
|   CTChilds commChilds, exclChilds;
 | |
|   unsigned stopLevel = lvs1.size();
 | |
|   split (root_, ct->root(), commChilds, exclChilds, stopLevel);
 | |
|   ConstraintTree* commCt = new ConstraintTree (commChilds, logVars_);
 | |
|   ConstraintTree* exclCt = new ConstraintTree (exclChilds, logVars_);
 | |
|   // std::cout << commCt->tupleSet() << " + " ;
 | |
|   // std::cout << exclCt->tupleSet() << " = " ;
 | |
|   // std::cout << tupleSet() << std::endl;
 | |
|   assert ((commCt->tupleSet() | exclCt->tupleSet()) == tupleSet());
 | |
|   assert ((exclCt->tupleSet (stopLevel) & ct->tupleSet (stopLevel)).empty());
 | |
|   return {commCt, exclCt};
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTrees
 | |
| ConstraintTree::countNormalize (const LogVarSet& Ys)
 | |
| {
 | |
|   assert (logVarSet_.contains (Ys));
 | |
|   LogVarSet Zs = logVarSet_ - Ys;
 | |
|   if (Ys.empty() || Zs.empty()) {
 | |
|     return { new ConstraintTree (*this) };
 | |
|   }
 | |
|   moveToTop (Zs.elements());
 | |
|   ConstraintTrees cts;
 | |
|   std::unordered_map<unsigned, ConstraintTree*> countMap;
 | |
|   unsigned stopLevel = getLevel (Zs.back());
 | |
|   const CTChilds& childs = root_->childs();
 | |
| 
 | |
|   for (CTChilds::const_iterator chIt = childs.begin();
 | |
|        chIt != childs.end(); ++ chIt) {
 | |
|     const std::vector<std::pair<CTNode*, unsigned>>& res =
 | |
|         countNormalize (*chIt, stopLevel);
 | |
|     for (size_t j = 0; j < res.size(); j++) {
 | |
|       std::unordered_map<unsigned, ConstraintTree*>::iterator it
 | |
|           = countMap.find (res[j].second);
 | |
|       if (it == countMap.end()) {
 | |
|         ConstraintTree* newCt = new ConstraintTree (logVars_);
 | |
|         it = countMap.insert (std::make_pair (res[j].second, newCt)).first;
 | |
|         cts.push_back (newCt);
 | |
|       }
 | |
|       it->second->root_->mergeSubtree (res[j].first);
 | |
|     }
 | |
|   }
 | |
|   return cts;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTrees
 | |
| ConstraintTree::jointCountNormalize (
 | |
|     ConstraintTree* commCt,
 | |
|     ConstraintTree* exclCt,
 | |
|     LogVar X,
 | |
|     LogVar X_new1,
 | |
|     LogVar X_new2)
 | |
| {
 | |
|   unsigned N = getConditionalCount (X);
 | |
|   // std::cout << "My tuples:     " << tupleSet() << std::endl;
 | |
|   // std::cout << "CommCt tuples: " << commCt->tupleSet() << std::endl;
 | |
|   // std::cout << "ExclCt tuples: " << exclCt->tupleSet() << std::endl;
 | |
|   // std::cout << "Counted Lv:    " << X << std::endl;
 | |
|   // std::cout << "X_new1:        " << X_new1 << std::endl;
 | |
|   // std::cout << "X_new2:        " << X_new2 << std::endl;
 | |
|   // std::cout << "Original N:    " << N << std::endl;
 | |
|   // std::cout << endl;
 | |
| 
 | |
|   ConstraintTrees normCts1 = commCt->countNormalize (X);
 | |
|   std::vector<unsigned> counts1 (normCts1.size());
 | |
|   for (size_t i = 0; i < normCts1.size(); i++) {
 | |
|     counts1[i] = normCts1[i]->getConditionalCount (X);
 | |
|     // std::cout << "normCts1[" << i << "] #" << counts1[i] ;
 | |
|     // std::cout << " " << normCts1[i]->tupleSet() << std::endl;
 | |
|   }
 | |
| 
 | |
|   ConstraintTrees normCts2 = exclCt->countNormalize (X);
 | |
|   std::vector<unsigned> counts2 (normCts2.size());
 | |
|   for (size_t i = 0; i < normCts2.size(); i++) {
 | |
|     counts2[i] = normCts2[i]->getConditionalCount (X);
 | |
|     // std::cout << "normCts2[" << i << "] #" << counts2[i] ;
 | |
|     // std::cout << " " << normCts2[i]->tupleSet() << std::endl;
 | |
|   }
 | |
|   // std::cout << std::endl;
 | |
| 
 | |
|   ConstraintTree* excl1 = 0;
 | |
|   for (size_t i = 0; i < normCts1.size(); i++) {
 | |
|     if (counts1[i] == N) {
 | |
|       excl1 = normCts1[i];
 | |
|       normCts1.erase (normCts1.begin() + i);
 | |
|       counts1.erase (counts1.begin() + i);
 | |
|       // std::cout << "joint-count(" << N << ",0)" << std::endl;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ConstraintTree* excl2 = 0;
 | |
|   for (size_t i = 0; i < normCts2.size(); i++) {
 | |
|     if (counts2[i] == N) {
 | |
|       excl2 = normCts2[i];
 | |
|       normCts2.erase (normCts2.begin() + i);
 | |
|       counts2.erase (counts2.begin() + i);
 | |
|       // std::cout << "joint-count(0," << N << ")" << std::endl;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (size_t i = 0; i < normCts1.size(); i++) {
 | |
|     unsigned j;
 | |
|     for (j = 0; counts1[i] + counts2[j] != N; j++) ;
 | |
|     // std::cout << "joint-count(" << counts1[i] ;
 | |
|     // std::cout <<  "," << counts2[j] << ")" << std::endl;
 | |
|     const CTChilds& childs = normCts2[j]->root_->childs();
 | |
|     for (CTChilds::const_iterator chIt = childs.begin();
 | |
|          chIt != childs.end(); ++ chIt) {
 | |
|       normCts1[i]->root_->mergeSubtree (CTNode::copySubtree (*chIt));
 | |
|     }
 | |
|     delete normCts2[j];
 | |
|   }
 | |
| 
 | |
|   ConstraintTrees cts = normCts1;
 | |
|   commCt->rename (X, X_new1);
 | |
|   exclCt->rename (X, X_new2);
 | |
|   for (size_t i = 0; i < cts.size(); i++) {
 | |
|     cts[i]->remove (X);
 | |
|     cts[i]->join (commCt);
 | |
|     cts[i]->join (exclCt);
 | |
|   }
 | |
| 
 | |
|   if (excl1) {
 | |
|     cts.push_back (excl1);
 | |
|   }
 | |
|   if (excl2) {
 | |
|     cts.push_back (excl2);
 | |
|   }
 | |
| 
 | |
|   return cts;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| LogVars
 | |
| ConstraintTree::expand (LogVar X)
 | |
| {
 | |
|   moveToBottom ({X});
 | |
|   assert (isCountNormalized (X));
 | |
|   CTNodes nodes = getNodesAtLevel (logVars_.size() - 1);
 | |
|   unsigned nrSymbols = getConditionalCount (X);
 | |
|   for (CTNodes::const_iterator it = nodes.begin();
 | |
|        it != nodes.end(); ++ it) {
 | |
|     Symbols symbols;
 | |
|     const CTChilds& childs = (*it)->childs();
 | |
|     for (CTChilds::const_iterator chIt = childs.begin();
 | |
|          chIt != childs.end(); ++ chIt) {
 | |
|       symbols.push_back ((*chIt)->symbol());
 | |
|     }
 | |
|     (*it)->removeAndDeleteAllChilds();
 | |
|     CTNode* prev = *it;
 | |
|     assert (symbols.size() == nrSymbols);
 | |
|     for (size_t j = 0; j < nrSymbols; j++) {
 | |
|       CTNode* newNode = new CTNode (symbols[j], (*it)->level() + j);
 | |
|       prev->mergeSubtree (newNode);
 | |
|       prev = newNode;
 | |
|     }
 | |
|   }
 | |
|   LogVars newLvs;
 | |
|   logVars_.pop_back();
 | |
|   for (size_t i = 0; i < nrSymbols; i++) {
 | |
|     logVars_.push_back (LogVar (logVarSet_.back() + 1));
 | |
|     newLvs.push_back   (LogVar (logVarSet_.back() + 1));
 | |
|     logVarSet_.insert  (LogVar (logVarSet_.back() + 1));
 | |
|   }
 | |
|   logVarSet_ -= X;
 | |
|   return newLvs;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTrees
 | |
| ConstraintTree::ground (LogVar X)
 | |
| {
 | |
|   moveToTop ({X});
 | |
|   ConstraintTrees cts;
 | |
|   const CTChilds& nodes = root_->childs();
 | |
|   for (CTChilds::const_iterator it = nodes.begin();
 | |
|        it != nodes.end(); ++ it) {
 | |
|     CTNode* copy = CTNode::copySubtree (*it);
 | |
|     copy->setSymbol ((*it)->symbol());
 | |
|     ConstraintTree* newCt = new ConstraintTree (logVars_);
 | |
|     newCt->root()->mergeSubtree (copy);
 | |
|     cts.push_back (newCt);
 | |
|   }
 | |
|   return cts;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::cloneLogVar (LogVar X_1, LogVar X_2)
 | |
| {
 | |
|   moveToBottom ({X_1});
 | |
|   CTNodes leafs = getNodesAtLevel (logVars_.size());
 | |
|   for (size_t i = 0; i < leafs.size(); i++) {
 | |
|     leafs[i]->childs().insert_sorted (
 | |
|         new CTNode (leafs[i]->symbol(), leafs[i]->level() + 1));
 | |
|   }
 | |
|   logVars_.push_back (X_2);
 | |
|   logVarSet_.insert (X_2);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ConstraintTree&
 | |
| ConstraintTree::operator= (const ConstraintTree& ct)
 | |
| {
 | |
|   if (this != &ct) {
 | |
|     root_      = CTNode::copySubtree (ct.root_);
 | |
|     logVars_   = ct.logVars_;
 | |
|     logVarSet_ = ct.logVarSet_;
 | |
|   }
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| ConstraintTree::countTuples (const CTNode* n) const
 | |
| {
 | |
|   if (n->isLeaf()) {
 | |
|     return 1;
 | |
|   }
 | |
|   unsigned sum = 0;
 | |
|   const CTChilds& childs = n->childs();
 | |
|   for (CTChilds::const_iterator chIt = childs.begin();
 | |
|       chIt != childs.end(); ++ chIt) {
 | |
|     sum += countTuples (*chIt);
 | |
|   }
 | |
|   return sum;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| CTNodes
 | |
| ConstraintTree::getNodesBelow (CTNode* fromHere) const
 | |
| {
 | |
|   CTNodes nodes;
 | |
|   std::queue<CTNode*> queue;
 | |
|   queue.push (fromHere);
 | |
|   while (queue.empty() == false) {
 | |
|     CTNode* node = queue.front();
 | |
|     nodes.push_back (node);
 | |
|     for (CTChilds::const_iterator chIt = node->childs().begin();
 | |
|          chIt != node->childs().end(); ++ chIt) {
 | |
|       queue.push (*chIt);
 | |
|     }
 | |
|     queue.pop();
 | |
|   }
 | |
|   return nodes;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| CTNodes
 | |
| ConstraintTree::getNodesAtLevel (unsigned level) const
 | |
| {
 | |
|   assert (level <= logVars_.size());
 | |
|   if (level == 0) {
 | |
|     return { root_ };
 | |
|   }
 | |
|   CTNodes stack;
 | |
|   CTNodes nodes;
 | |
|   stack.push_back (root_);
 | |
|   while (stack.empty() == false) {
 | |
|     CTNode* node = stack.back();
 | |
|     stack.pop_back();
 | |
|     if (node->level() + 1 == level) {
 | |
|       nodes.insert (nodes.end(), node->childs().begin(),
 | |
|           node->childs().end());
 | |
|     } else {
 | |
|       stack.insert (stack.end(), node->childs().begin(),
 | |
|           node->childs().end());
 | |
|     }
 | |
|   }
 | |
|   return nodes;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| ConstraintTree::nrNodes (const CTNode* n) const
 | |
| {
 | |
|   unsigned nr = 0;
 | |
|   if (n->isLeaf() == false) {
 | |
|     for (CTChilds::const_iterator chIt = n->childs().begin();
 | |
|          chIt != n->childs().end(); ++ chIt) {
 | |
|       nr += nrNodes (*chIt);
 | |
|     }
 | |
|   }
 | |
|   return nr;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::appendOnBottom (CTNode* n, const CTChilds& childs)
 | |
| {
 | |
|   if (childs.empty()) {
 | |
|     return;
 | |
|   }
 | |
|   CTNodes stack { n };
 | |
|   while (stack.empty() == false) {
 | |
|     CTNode* node = stack.back();
 | |
|     stack.pop_back();
 | |
|     if (node->isLeaf()) {
 | |
|       for (CTChilds::const_iterator chIt = childs.begin();
 | |
|            chIt != childs.end(); ++ chIt) {
 | |
|         node->mergeSubtree (CTNode::copySubtree (*chIt));
 | |
|       }
 | |
|     } else {
 | |
|       stack.insert (stack.end(), node->childs().begin(),
 | |
|           node->childs().end());
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::swapLogVar (LogVar X)
 | |
| {
 | |
|   size_t pos = Util::indexOf (logVars_, X);
 | |
|   assert (pos != logVars_.size());
 | |
|   CTNodes nodes = getNodesAtLevel (pos);
 | |
|   for (CTNodes::const_iterator nodeIt = nodes.begin();
 | |
|        nodeIt != nodes.end(); ++ nodeIt) {
 | |
|     CTChilds childsCopy = (*nodeIt)->childs();
 | |
|     (*nodeIt)->removeChilds();
 | |
|     for (CTChilds::const_iterator ccIt = childsCopy.begin();
 | |
|          ccIt != childsCopy.end(); ++ ccIt) {
 | |
|        const CTChilds& grandsons = (*ccIt)->childs();
 | |
|        for (CTChilds::const_iterator gsIt = grandsons.begin();
 | |
|             gsIt != grandsons.end(); ++ gsIt) {
 | |
|          CTNode* childCopy = new CTNode (
 | |
|              (*ccIt)->symbol(), (*ccIt)->level() + 1, (*gsIt)->childs());
 | |
|          (*gsIt)->removeChilds();
 | |
|          (*gsIt)->childs().insert_sorted (childCopy);
 | |
|          (*gsIt)->setLevel ((*gsIt)->level() - 1);
 | |
|          (*nodeIt)->mergeSubtree ((*gsIt), false);
 | |
|        }
 | |
|        delete (*ccIt);
 | |
|     }
 | |
|   }
 | |
|   std::swap (logVars_[pos], logVars_[pos + 1]);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool
 | |
| ConstraintTree::join (
 | |
|     CTNode* currNode,
 | |
|     const Tuple& tuple,
 | |
|     size_t currIdx,
 | |
|     CTNode* appendNode)
 | |
| {
 | |
|   bool tupleFounded = false;
 | |
|   CTChilds::const_iterator it = currNode->findSymbol (tuple[currIdx]);
 | |
|   if (it != currNode->childs().end()) {
 | |
|     if (currIdx == tuple.size() - 1) {
 | |
|       appendOnBottom (*it, appendNode->childs());
 | |
|       return true;
 | |
|     } else {
 | |
|       tupleFounded = join (*it, tuple, currIdx + 1, appendNode);
 | |
|     }
 | |
|   }
 | |
|   return tupleFounded;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::getTuples (
 | |
|     CTNode* n,
 | |
|     Tuples currTuples,
 | |
|     unsigned stopLevel,
 | |
|     Tuples& tuplesCollected,
 | |
|     CTNodes& continuationNodes) const
 | |
| {
 | |
|   if (n->isRoot() == false) {
 | |
|     if (currTuples.empty()) {
 | |
|         currTuples.push_back ({ n->symbol()});
 | |
|     } else {
 | |
|       for (size_t i = 0; i < currTuples.size(); i++) {
 | |
|         currTuples[i].push_back (n->symbol());
 | |
|       }
 | |
|     }
 | |
|     if (n->level() == stopLevel) {
 | |
|       for (size_t i = 0; i < currTuples.size(); i++) {
 | |
|         tuplesCollected.push_back (currTuples[i]);
 | |
|         continuationNodes.push_back (n);
 | |
|       }
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
|   const CTChilds& childs = n->childs();
 | |
|   for (CTChilds::const_iterator chIt = childs.begin();
 | |
|       chIt != childs.end(); ++ chIt) {
 | |
|     getTuples (*chIt, currTuples, stopLevel, tuplesCollected,
 | |
|         continuationNodes);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| ConstraintTree::size() const
 | |
| {
 | |
|   return countTuples (root_);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| ConstraintTree::nrSymbols (LogVar X)
 | |
| {
 | |
|   moveToTop ({X});
 | |
|   return root_->childs().size();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| std::vector<std::pair<CTNode*, unsigned>>
 | |
| ConstraintTree::countNormalize (
 | |
|      const CTNode* n,
 | |
|      unsigned stopLevel)
 | |
| {
 | |
|   if (n->level() == stopLevel) {
 | |
|     return std::vector<std::pair<CTNode*, unsigned>>() = {
 | |
|       std::make_pair (CTNode::copySubtree (n), countTuples (n))
 | |
|     };
 | |
|   }
 | |
|   std::vector<std::pair<CTNode*, unsigned>> res;
 | |
|   const CTChilds& childs = n->childs();
 | |
|   for (CTChilds::const_iterator chIt = childs.begin();
 | |
|        chIt != childs.end(); ++ chIt) {
 | |
|     const std::vector<std::pair<CTNode*, unsigned>>& lowerRes =
 | |
|         countNormalize (*chIt, stopLevel);
 | |
|     for (size_t j = 0; j < lowerRes.size(); j++) {
 | |
|       CTNode* newNode = new CTNode (*n);
 | |
|       newNode->mergeSubtree (lowerRes[j].first);
 | |
|       res.push_back (std::make_pair (newNode, lowerRes[j].second));
 | |
|     }
 | |
|   }
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void
 | |
| ConstraintTree::split (
 | |
|     CTNode* n1,
 | |
|     CTNode* n2,
 | |
|     CTChilds& commChilds,
 | |
|     CTChilds& exclChilds,
 | |
|     unsigned stopLevel)
 | |
| {
 | |
|   CTChilds& childs1 = n1->childs();
 | |
|   for (CTChilds::const_iterator chIt1 = childs1.begin();
 | |
|        chIt1 != childs1.end(); ++ chIt1) {
 | |
|     CTChilds::iterator chIt2 = n2->findSymbol ((*chIt1)->symbol());
 | |
|     if (chIt2 == n2->childs().end()) {
 | |
|       exclChilds.insert_sorted (CTNode::copySubtree (*chIt1));
 | |
|     } else {
 | |
|       if ((*chIt1)->level() == stopLevel) {
 | |
|         commChilds.insert_sorted (CTNode::copySubtree (*chIt1));
 | |
|       } else {
 | |
|         CTChilds lowerCommChilds, lowerExclChilds;
 | |
|         split (*chIt1, *chIt2, lowerCommChilds, lowerExclChilds, stopLevel);
 | |
|         if (lowerCommChilds.empty() == false) {
 | |
|           commChilds.insert_sorted (new CTNode (**chIt1, lowerCommChilds));
 | |
|         }
 | |
|         if (lowerExclChilds.empty() == false) {
 | |
|           exclChilds.insert_sorted (new CTNode (**chIt1, lowerExclChilds));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace Horus
 | |
| 
 |