1175 lines
27 KiB
C++
1175 lines
27 KiB
C++
#include <queue>
|
|
|
|
#include <fstream>
|
|
|
|
#include "ConstraintTree.h"
|
|
#include "Util.h"
|
|
|
|
|
|
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 (void)
|
|
{
|
|
childs_.clear();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CTNode::removeAndDeleteChild (CTNode* child)
|
|
{
|
|
removeChild (child);
|
|
CTNode::deleteSubtree (child);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CTNode::removeAndDeleteAllChilds (void)
|
|
{
|
|
for (CTChilds::const_iterator chIt = childs_.begin();
|
|
chIt != childs_.end(); ++ chIt) {
|
|
deleteSubtree (*chIt);
|
|
}
|
|
childs_.clear();
|
|
}
|
|
|
|
|
|
|
|
SymbolSet
|
|
CTNode::childSymbols (void) 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 pair<const CTNode*, CTNode*> StackPair;
|
|
vector<StackPair> stack = { StackPair (root1, root2) };
|
|
while (stack.empty() == false) {
|
|
const CTNode* n1 = stack.back().first;
|
|
CTNode* n2 = stack.back().second;
|
|
stack.pop_back();
|
|
// cout << "n2 childs: " << n2->childs();
|
|
// 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;
|
|
}
|
|
|
|
|
|
|
|
ostream& operator<< (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 (vector<vector<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 (void)
|
|
{
|
|
CTNode::deleteSubtree (root_);
|
|
}
|
|
|
|
|
|
|
|
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 (void)
|
|
{
|
|
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()) {
|
|
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
|
|
{
|
|
ofstream out (fileName);
|
|
if (!out.is_open()) {
|
|
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
|
return;
|
|
}
|
|
out << "digraph {" << endl;
|
|
ConstraintTree copy (*this);
|
|
copy.moveToTop (copy.logVarSet_.elements());
|
|
CTNodes nodes = getNodesBelow (copy.root_);
|
|
out << "\"" << copy.root_ << "\"" << " [label=\"R\"]" << endl;
|
|
for (CTNodes::const_iterator it = ++ nodes.begin();
|
|
it != nodes.end(); ++ it) {
|
|
out << "\"" << *it << "\"";
|
|
out << " [label=\"" << **it << "\"]" ;
|
|
out << 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 << "\"" << endl ;
|
|
}
|
|
}
|
|
if (showLogVars) {
|
|
out << "Root [label=\"\", shape=plaintext]" << 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]" << endl;
|
|
}
|
|
out << "Root -> " << copy.logVars_[0];
|
|
out << " [style=invis]" << endl;
|
|
for (size_t i = 0; i < copy.logVars_.size() - 1; i++) {
|
|
out << copy.logVars_[i] << " -> " << copy.logVars_[i + 1];
|
|
out << " [style=invis]" << endl;
|
|
}
|
|
}
|
|
out << "}" << 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_);
|
|
// cout << commCt->tupleSet() << " + " ;
|
|
// cout << exclCt->tupleSet() << " = " ;
|
|
// cout << tupleSet() << 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;
|
|
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 vector<pair<CTNode*, unsigned>>& res =
|
|
countNormalize (*chIt, stopLevel);
|
|
for (size_t j = 0; j < res.size(); j++) {
|
|
unordered_map<unsigned, ConstraintTree*>::iterator it
|
|
= countMap.find (res[j].second);
|
|
if (it == countMap.end()) {
|
|
ConstraintTree* newCt = new ConstraintTree (logVars_);
|
|
it = countMap.insert (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);
|
|
// cout << "My tuples: " << tupleSet() << endl;
|
|
// cout << "CommCt tuples: " << commCt->tupleSet() << endl;
|
|
// cout << "ExclCt tuples: " << exclCt->tupleSet() << endl;
|
|
// cout << "Counted Lv: " << X << endl;
|
|
// cout << "X_new1: " << X_new1 << endl;
|
|
// cout << "X_new2: " << X_new2 << endl;
|
|
// cout << "Original N: " << N << endl;
|
|
// cout << endl;
|
|
|
|
ConstraintTrees normCts1 = commCt->countNormalize (X);
|
|
vector<unsigned> counts1 (normCts1.size());
|
|
for (size_t i = 0; i < normCts1.size(); i++) {
|
|
counts1[i] = normCts1[i]->getConditionalCount (X);
|
|
// cout << "normCts1[" << i << "] #" << counts1[i] ;
|
|
// cout << " " << normCts1[i]->tupleSet() << endl;
|
|
}
|
|
|
|
ConstraintTrees normCts2 = exclCt->countNormalize (X);
|
|
vector<unsigned> counts2 (normCts2.size());
|
|
for (size_t i = 0; i < normCts2.size(); i++) {
|
|
counts2[i] = normCts2[i]->getConditionalCount (X);
|
|
// cout << "normCts2[" << i << "] #" << counts2[i] ;
|
|
// cout << " " << normCts2[i]->tupleSet() << endl;
|
|
}
|
|
// cout << 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);
|
|
// cout << "joint-count(" << N << ",0)" << 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);
|
|
// cout << "joint-count(0," << N << ")" << endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < normCts1.size(); i++) {
|
|
unsigned j;
|
|
for (j = 0; counts1[i] + counts2[j] != N; j++) ;
|
|
// cout << "joint-count(" << counts1[i] ;
|
|
// cout << "," << counts2[j] << ")" << 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;
|
|
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());
|
|
const 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 (void) const
|
|
{
|
|
return countTuples (root_);
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
ConstraintTree::nrSymbols (LogVar X)
|
|
{
|
|
moveToTop ({X});
|
|
return root_->childs().size();
|
|
}
|
|
|
|
|
|
|
|
vector<pair<CTNode*, unsigned>>
|
|
ConstraintTree::countNormalize (
|
|
const CTNode* n,
|
|
unsigned stopLevel)
|
|
{
|
|
if (n->level() == stopLevel) {
|
|
return vector<pair<CTNode*, unsigned>>() = {
|
|
make_pair (CTNode::copySubtree (n), countTuples (n))
|
|
};
|
|
}
|
|
vector<pair<CTNode*, unsigned>> res;
|
|
const CTChilds& childs = n->childs();
|
|
for (CTChilds::const_iterator chIt = childs.begin();
|
|
chIt != childs.end(); ++ chIt) {
|
|
const vector<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 (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));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|