This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/packages/CLPBN/horus/LiftedCircuit.cpp

1234 lines
32 KiB
C++
Raw Normal View History

#include <fstream>
#include "LiftedCircuit.h"
2012-12-19 17:45:53 +00:00
OrNode::~OrNode (void)
{
delete leftBranch_;
delete rightBranch_;
}
double
OrNode::weight (void) const
{
double lw = leftBranch_->weight();
double rw = rightBranch_->weight();
return Globals::logDomain ? Util::logSum (lw, rw) : lw + rw;
}
2012-12-19 17:45:53 +00:00
AndNode::~AndNode (void)
{
delete leftBranch_;
delete rightBranch_;
}
double
AndNode::weight (void) const
{
double lw = leftBranch_->weight();
double rw = rightBranch_->weight();
return Globals::logDomain ? lw + rw : lw * rw;
}
int SetOrNode::nrPos_ = -1;
int SetOrNode::nrNeg_ = -1;
2012-12-19 17:45:53 +00:00
SetOrNode::~SetOrNode (void)
{
delete follow_;
}
double
SetOrNode::weight (void) const
{
double weightSum = LogAware::addIdenty();
for (unsigned i = 0; i < nrGroundings_ + 1; i++) {
nrPos_ = nrGroundings_ - i;
nrNeg_ = i;
if (Globals::logDomain) {
double nrCombs = Util::nrCombinations (nrGroundings_, i);
double w = follow_->weight();
weightSum = Util::logSum (weightSum, std::log (nrCombs) + w);
} else {
double w = follow_->weight();
weightSum += Util::nrCombinations (nrGroundings_, i) * w;
}
}
nrPos_ = -1;
nrNeg_ = -1;
return weightSum;
}
2012-12-19 17:45:53 +00:00
SetAndNode::~SetAndNode (void)
{
delete follow_;
}
double
SetAndNode::weight (void) const
{
2012-12-12 21:19:22 +00:00
return LogAware::pow (follow_->weight(), nrGroundings_);
}
2012-12-19 17:45:53 +00:00
IncExcNode::~IncExcNode (void)
{
delete plus1Branch_;
delete plus2Branch_;
delete minusBranch_;
}
double
IncExcNode::weight (void) const
{
double w = 0.0;
if (Globals::logDomain) {
w = Util::logSum (plus1Branch_->weight(), plus2Branch_->weight());
w = std::log (std::exp (w) - std::exp (minusBranch_->weight()));
} else {
w = plus1Branch_->weight() + plus2Branch_->weight();
w -= minusBranch_->weight();
}
return w;
}
2012-12-19 17:45:53 +00:00
LeafNode::~LeafNode (void)
{
delete clause_;
}
double
LeafNode::weight (void) const
{
assert (clause_->isUnit());
if (clause_->posCountedLogVars().empty() == false
|| clause_->negCountedLogVars().empty() == false) {
if (SetOrNode::isSet() == false) {
// return a NaN if we have a SetOrNode
// ancester that is not set. This can only
// happen when calculating the weights
// for the edge labels in graphviz
return 0.0 / 0.0;
}
}
double weight = clause_->literals()[0].isPositive()
? lwcnf_.posWeight (clause_->literals().front().lid())
: lwcnf_.negWeight (clause_->literals().front().lid());
LogVarSet lvs = clause_->constr().logVarSet();
lvs -= clause_->ipgLogVars();
lvs -= clause_->posCountedLogVars();
lvs -= clause_->negCountedLogVars();
unsigned nrGroundings = 1;
if (lvs.empty() == false) {
2012-12-09 22:13:58 +00:00
nrGroundings = clause_->constr().projectedCopy (lvs).size();
}
if (clause_->posCountedLogVars().empty() == false) {
nrGroundings *= std::pow (SetOrNode::nrPositives(),
clause_->nrPosCountedLogVars());
}
if (clause_->negCountedLogVars().empty() == false) {
nrGroundings *= std::pow (SetOrNode::nrNegatives(),
clause_->nrNegCountedLogVars());
}
2012-12-12 21:19:22 +00:00
return LogAware::pow (weight, nrGroundings);
}
2012-12-19 17:45:53 +00:00
SmoothNode::~SmoothNode (void)
{
Clause::deleteClauses (clauses_);
}
double
SmoothNode::weight (void) const
{
Clauses cs = clauses();
double totalWeight = LogAware::multIdenty();
for (size_t i = 0; i < cs.size(); i++) {
double posWeight = lwcnf_.posWeight (cs[i]->literals()[0].lid());
double negWeight = lwcnf_.negWeight (cs[i]->literals()[0].lid());
LogVarSet lvs = cs[i]->constr().logVarSet();
lvs -= cs[i]->ipgLogVars();
lvs -= cs[i]->posCountedLogVars();
lvs -= cs[i]->negCountedLogVars();
unsigned nrGroundings = 1;
if (lvs.empty() == false) {
2012-12-09 22:13:58 +00:00
nrGroundings = cs[i]->constr().projectedCopy (lvs).size();
}
if (cs[i]->posCountedLogVars().empty() == false) {
nrGroundings *= std::pow (SetOrNode::nrPositives(),
cs[i]->nrPosCountedLogVars());
}
if (cs[i]->negCountedLogVars().empty() == false) {
nrGroundings *= std::pow (SetOrNode::nrNegatives(),
cs[i]->nrNegCountedLogVars());
}
if (Globals::logDomain) {
totalWeight += Util::logSum (posWeight, negWeight) * nrGroundings;
} else {
totalWeight *= std::pow (posWeight + negWeight, nrGroundings);
}
}
return totalWeight;
}
double
TrueNode::weight (void) const
{
return LogAware::multIdenty();
}
2012-10-30 12:41:00 +00:00
double
CompilationFailedNode::weight (void) const
{
2012-11-27 16:54:02 +00:00
// weighted model counting in compilation
2012-12-09 22:13:58 +00:00
// failed nodes should give NaN
2012-11-27 16:54:02 +00:00
return 0.0 / 0.0;
2012-10-30 12:41:00 +00:00
}
LiftedCircuit::LiftedCircuit (const LiftedWCNF* lwcnf)
: lwcnf_(lwcnf)
{
root_ = 0;
2012-11-27 16:54:02 +00:00
compilationSucceeded_ = true;
Clauses clauses = Clause::copyClauses (lwcnf->clauses());
2012-10-31 23:43:39 +00:00
compile (&root_, clauses);
if (compilationSucceeded_) {
smoothCircuit (root_);
}
if (Globals::verbosity > 1) {
2012-11-27 16:54:02 +00:00
if (compilationSucceeded_) {
double wmc = LogAware::exp (getWeightedModelCount());
cout << "Weighted model count = " << wmc << endl << endl;
2012-11-27 16:54:02 +00:00
}
cout << "Exporting circuit to graphviz (circuit.dot)..." ;
cout << endl << endl;
exportToGraphViz ("circuit.dot");
}
2012-10-24 21:22:49 +01:00
}
2012-12-19 17:45:53 +00:00
LiftedCircuit::~LiftedCircuit (void)
{
delete root_;
unordered_map<CircuitNode*, Clauses>::iterator it;
it = originClausesMap_.begin();
while (it != originClausesMap_.end()) {
Clause::deleteClauses (it->second);
++ it;
}
}
2012-11-27 16:54:02 +00:00
bool
LiftedCircuit::isCompilationSucceeded (void) const
{
return compilationSucceeded_;
}
double
LiftedCircuit::getWeightedModelCount (void) const
{
2012-11-27 16:54:02 +00:00
assert (compilationSucceeded_);
return root_->weight();
}
void
2012-10-24 21:22:49 +01:00
LiftedCircuit::exportToGraphViz (const char* fileName)
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "BayesBallGraph::exportToDotFile()" << endl;
abort();
}
out << "digraph {" << endl;
out << "ranksep=1" << endl;
2012-10-24 21:22:49 +01:00
exportToGraphViz (root_, out);
out << "}" << endl;
out.close();
}
void
LiftedCircuit::compile (
CircuitNode** follow,
Clauses& clauses)
{
2012-11-27 16:54:02 +00:00
if (compilationSucceeded_ == false
&& Globals::verbosity <= 1) {
return;
}
if (clauses.empty()) {
*follow = new TrueNode();
return;
}
2012-12-17 18:39:42 +00:00
if (clauses.size() == 1 && clauses[0]->isUnit()) {
*follow = new LeafNode (clauses[0], *lwcnf_);
return;
}
if (tryUnitPropagation (follow, clauses)) {
return;
}
2012-11-07 18:42:11 +00:00
if (tryIndependence (follow, clauses)) {
return;
}
2012-11-07 18:42:11 +00:00
2012-10-24 21:22:49 +01:00
if (tryShannonDecomp (follow, clauses)) {
return;
}
2012-11-07 18:42:11 +00:00
2012-10-30 00:21:10 +00:00
if (tryInclusionExclusion (follow, clauses)) {
return;
}
2012-11-07 18:42:11 +00:00
if (tryIndepPartialGrounding (follow, clauses)) {
return;
}
2012-11-07 18:42:11 +00:00
2012-10-31 23:43:39 +00:00
if (tryAtomCounting (follow, clauses)) {
return;
}
2012-11-07 18:42:11 +00:00
*follow = new CompilationFailedNode();
if (Globals::verbosity > 1) {
originClausesMap_[*follow] = clauses;
explanationMap_[*follow] = "" ;
}
2012-11-27 16:54:02 +00:00
compilationSucceeded_ = false;
2012-10-31 23:43:39 +00:00
}
bool
LiftedCircuit::tryUnitPropagation (
CircuitNode** follow,
Clauses& clauses)
{
if (Globals::verbosity > 1) {
backupClauses_ = Clause::copyClauses (clauses);
}
for (size_t i = 0; i < clauses.size(); i++) {
if (clauses[i]->isUnit()) {
Clauses propagClauses;
for (size_t j = 0; j < clauses.size(); j++) {
if (i != j) {
LiteralId lid = clauses[i]->literals()[0].lid();
LogVarTypes types = clauses[i]->logVarTypes (0);
if (clauses[i]->literals()[0].isPositive()) {
if (clauses[j]->containsPositiveLiteral (lid, types) == false) {
clauses[j]->removeNegativeLiterals (lid, types);
if (clauses[j]->nrLiterals() > 0) {
propagClauses.push_back (clauses[j]);
} else {
delete clauses[j];
}
} else {
delete clauses[j];
}
} else if (clauses[i]->literals()[0].isNegative()) {
if (clauses[j]->containsNegativeLiteral (lid, types) == false) {
clauses[j]->removePositiveLiterals (lid, types);
if (clauses[j]->nrLiterals() > 0) {
propagClauses.push_back (clauses[j]);
} else {
delete clauses[j];
}
} else {
delete clauses[j];
}
}
}
}
AndNode* andNode = new AndNode();
if (Globals::verbosity > 1) {
originClausesMap_[andNode] = backupClauses_;
stringstream explanation;
explanation << " UP on " << clauses[i]->literals()[0];
explanationMap_[andNode] = explanation.str();
}
2012-12-17 18:39:42 +00:00
Clauses unitClause = { clauses[i] };
compile (andNode->leftBranch(), unitClause);
compile (andNode->rightBranch(), propagClauses);
(*follow) = andNode;
2012-12-17 18:39:42 +00:00
return true;
}
}
2012-12-19 17:45:53 +00:00
if (Globals::verbosity > 1) {
Clause::deleteClauses (backupClauses_);
}
return false;
}
bool
LiftedCircuit::tryIndependence (
CircuitNode** follow,
Clauses& clauses)
{
if (clauses.size() == 1) {
return false;
}
if (Globals::verbosity > 1) {
2012-12-09 22:57:39 +00:00
backupClauses_ = Clause::copyClauses (clauses);
}
2012-11-07 18:42:11 +00:00
Clauses depClauses = { clauses[0] };
Clauses indepClauses (clauses.begin() + 1, clauses.end());
bool finish = false;
while (finish == false) {
finish = true;
for (size_t i = 0; i < indepClauses.size(); i++) {
if (independentClause (*indepClauses[i], depClauses) == false) {
2012-11-07 18:42:11 +00:00
depClauses.push_back (indepClauses[i]);
indepClauses.erase (indepClauses.begin() + i);
finish = false;
break;
}
}
2012-11-07 18:42:11 +00:00
}
if (indepClauses.empty() == false) {
AndNode* andNode = new AndNode ();
if (Globals::verbosity > 1) {
originClausesMap_[andNode] = backupClauses_;
explanationMap_[andNode] = " Independence" ;
}
2012-11-07 18:42:11 +00:00
compile (andNode->leftBranch(), depClauses);
compile (andNode->rightBranch(), indepClauses);
(*follow) = andNode;
return true;
}
2012-12-19 17:45:53 +00:00
if (Globals::verbosity > 1) {
Clause::deleteClauses (backupClauses_);
}
return false;
}
bool
2012-10-24 21:22:49 +01:00
LiftedCircuit::tryShannonDecomp (
CircuitNode** follow,
Clauses& clauses)
{
if (Globals::verbosity > 1) {
backupClauses_ = Clause::copyClauses (clauses);
}
for (size_t i = 0; i < clauses.size(); i++) {
const Literals& literals = clauses[i]->literals();
for (size_t j = 0; j < literals.size(); j++) {
if (literals[j].isGround (
clauses[i]->constr(), clauses[i]->ipgLogVars())) {
Clause* c1 = lwcnf_->createClause (literals[j].lid());
Clause* c2 = new Clause (*c1);
c2->literals().front().complement();
Clauses otherClauses = Clause::copyClauses (clauses);
clauses.push_back (c1);
otherClauses.push_back (c2);
OrNode* orNode = new OrNode();
if (Globals::verbosity > 1) {
originClausesMap_[orNode] = backupClauses_;
stringstream explanation;
explanation << " SD on " << literals[j];
explanationMap_[orNode] = explanation.str();
}
2012-12-17 18:39:42 +00:00
compile (orNode->leftBranch(), clauses);
compile (orNode->rightBranch(), otherClauses);
2012-10-30 00:21:10 +00:00
(*follow) = orNode;
2012-12-17 18:39:42 +00:00
return true;
}
}
}
2012-12-19 17:45:53 +00:00
if (Globals::verbosity > 1) {
Clause::deleteClauses (backupClauses_);
}
return false;
}
2012-10-30 00:21:10 +00:00
bool
LiftedCircuit::tryInclusionExclusion (
CircuitNode** follow,
Clauses& clauses)
{
if (Globals::verbosity > 1) {
backupClauses_ = Clause::copyClauses (clauses);
}
2012-10-30 00:21:10 +00:00
for (size_t i = 0; i < clauses.size(); i++) {
Literals depLits = { clauses[i]->literals().front() };
Literals indepLits (clauses[i]->literals().begin() + 1,
clauses[i]->literals().end());
2012-11-07 23:45:43 +00:00
bool finish = false;
while (finish == false) {
finish = true;
for (size_t j = 0; j < indepLits.size(); j++) {
if (independentLiteral (indepLits[j], depLits) == false) {
depLits.push_back (indepLits[j]);
indepLits.erase (indepLits.begin() + j);
finish = false;
2012-10-30 00:21:10 +00:00
break;
}
}
2012-11-07 23:45:43 +00:00
}
if (indepLits.empty() == false) {
LogVarSet lvs1;
for (size_t j = 0; j < depLits.size(); j++) {
lvs1 |= depLits[j].logVarSet();
}
if (clauses[i]->constr().isCountNormalized (lvs1) == false) {
break;
}
2012-11-07 23:45:43 +00:00
LogVarSet lvs2;
for (size_t j = 0; j < indepLits.size(); j++) {
lvs2 |= indepLits[j].logVarSet();
}
if (clauses[i]->constr().isCountNormalized (lvs2) == false) {
break;
}
Clause* c1 = new Clause (clauses[i]->constr().projectedCopy (lvs1));
2012-11-07 23:45:43 +00:00
for (size_t j = 0; j < depLits.size(); j++) {
c1->addLiteral (depLits[j]);
2012-11-07 23:45:43 +00:00
}
Clause* c2 = new Clause (clauses[i]->constr().projectedCopy (lvs2));
2012-11-07 23:45:43 +00:00
for (size_t j = 0; j < indepLits.size(); j++) {
c2->addLiteral (indepLits[j]);
2012-10-30 00:21:10 +00:00
}
2012-12-09 22:13:58 +00:00
clauses.erase (clauses.begin() + i);
Clauses plus1Clauses = Clause::copyClauses (clauses);
Clauses plus2Clauses = Clause::copyClauses (clauses);
2012-11-07 23:45:43 +00:00
plus1Clauses.push_back (c1);
plus2Clauses.push_back (c2);
clauses.push_back (c1);
clauses.push_back (c2);
IncExcNode* ieNode = new IncExcNode();
if (Globals::verbosity > 1) {
originClausesMap_[ieNode] = backupClauses_;
stringstream explanation;
explanation << " IncExc on clause nº " << i + 1;
explanationMap_[ieNode] = explanation.str();
}
2012-11-07 23:45:43 +00:00
compile (ieNode->plus1Branch(), plus1Clauses);
compile (ieNode->plus2Branch(), plus2Clauses);
compile (ieNode->minusBranch(), clauses);
2012-11-07 23:45:43 +00:00
*follow = ieNode;
return true;
2012-10-30 00:21:10 +00:00
}
}
2012-12-19 17:45:53 +00:00
if (Globals::verbosity > 1) {
Clause::deleteClauses (backupClauses_);
}
2012-10-30 00:21:10 +00:00
return false;
}
bool
LiftedCircuit::tryIndepPartialGrounding (
CircuitNode** follow,
Clauses& clauses)
{
// assumes that all literals have logical variables
// else, shannon decomp was possible
if (Globals::verbosity > 1) {
backupClauses_ = Clause::copyClauses (clauses);
}
LogVars rootLogVars;
LogVarSet lvs = clauses[0]->ipgCandidates();
for (size_t i = 0; i < lvs.size(); i++) {
rootLogVars.clear();
rootLogVars.push_back (lvs[i]);
ConstraintTree ct = clauses[0]->constr().projectedCopy ({lvs[i]});
if (tryIndepPartialGroundingAux (clauses, ct, rootLogVars)) {
for (size_t j = 0; j < clauses.size(); j++) {
clauses[j]->addIpgLogVar (rootLogVars[j]);
}
SetAndNode* setAndNode = new SetAndNode (ct.size());
if (Globals::verbosity > 1) {
originClausesMap_[setAndNode] = backupClauses_;
explanationMap_[setAndNode] = " IPG" ;
}
*follow = setAndNode;
compile (setAndNode->follow(), clauses);
return true;
}
}
2012-12-19 17:45:53 +00:00
if (Globals::verbosity > 1) {
Clause::deleteClauses (backupClauses_);
}
return false;
}
bool
LiftedCircuit::tryIndepPartialGroundingAux (
Clauses& clauses,
ConstraintTree& ct,
LogVars& rootLogVars)
{
for (size_t i = 1; i < clauses.size(); i++) {
LogVarSet lvs = clauses[i]->ipgCandidates();
for (size_t j = 0; j < lvs.size(); j++) {
ConstraintTree ct2 = clauses[i]->constr().projectedCopy ({lvs[j]});
if (ct.tupleSet() == ct2.tupleSet()) {
rootLogVars.push_back (lvs[j]);
break;
}
}
if (rootLogVars.size() != i + 1) {
return false;
}
}
// verifies if the IPG logical vars appear in the same positions
unordered_map<LiteralId, size_t> positions;
for (size_t i = 0; i < clauses.size(); i++) {
const Literals& literals = clauses[i]->literals();
for (size_t j = 0; j < literals.size(); j++) {
size_t idx = literals[j].indexOfLogVar (rootLogVars[i]);
assert (idx != literals[j].nrLogVars());
unordered_map<LiteralId, size_t>::iterator it;
it = positions.find (literals[j].lid());
if (it != positions.end()) {
if (it->second != idx) {
return false;
}
} else {
positions[literals[j].lid()] = idx;
}
}
}
return true;
}
2012-10-31 23:43:39 +00:00
bool
LiftedCircuit::tryAtomCounting (
CircuitNode** follow,
Clauses& clauses)
{
for (size_t i = 0; i < clauses.size(); i++) {
if (clauses[i]->nrPosCountedLogVars() > 0
|| clauses[i]->nrNegCountedLogVars() > 0) {
// only allow one atom counting node per branch
return false;
}
}
if (Globals::verbosity > 1) {
backupClauses_ = Clause::copyClauses (clauses);
}
2012-10-31 23:43:39 +00:00
for (size_t i = 0; i < clauses.size(); i++) {
Literals literals = clauses[i]->literals();
2012-10-31 23:43:39 +00:00
for (size_t j = 0; j < literals.size(); j++) {
2012-11-06 23:39:18 +00:00
if (literals[j].nrLogVars() == 1
&& ! clauses[i]->isIpgLogVar (literals[j].logVars().front())
&& ! clauses[i]->isCountedLogVar (literals[j].logVars().front())) {
unsigned nrGroundings = clauses[i]->constr().projectedCopy (
literals[j].logVars()).size();
SetOrNode* setOrNode = new SetOrNode (nrGroundings);
if (Globals::verbosity > 1) {
originClausesMap_[setOrNode] = backupClauses_;
explanationMap_[setOrNode] = " AC" ;
}
Clause* c1 = new Clause (
clauses[i]->constr().projectedCopy (literals[j].logVars()));
Clause* c2 = new Clause (
clauses[i]->constr().projectedCopy (literals[j].logVars()));
c1->addLiteral (literals[j]);
c2->addLiteralComplemented (literals[j]);
c1->addPosCountedLogVar (literals[j].logVars().front());
c2->addNegCountedLogVar (literals[j].logVars().front());
2012-10-31 23:43:39 +00:00
clauses.push_back (c1);
clauses.push_back (c2);
shatterCountedLogVars (clauses);
compile (setOrNode->follow(), clauses);
*follow = setOrNode;
return true;
}
}
}
2012-12-19 17:45:53 +00:00
if (Globals::verbosity > 1) {
Clause::deleteClauses (backupClauses_);
}
2012-10-31 23:43:39 +00:00
return false;
}
2012-11-01 13:56:12 +00:00
void
LiftedCircuit::shatterCountedLogVars (Clauses& clauses)
{
while (shatterCountedLogVarsAux (clauses)) ;
}
bool
LiftedCircuit::shatterCountedLogVarsAux (Clauses& clauses)
{
for (size_t i = 0; i < clauses.size() - 1; i++) {
for (size_t j = i + 1; j < clauses.size(); j++) {
bool splitedSome = shatterCountedLogVarsAux (clauses, i, j);
if (splitedSome) {
return true;
}
}
}
return false;
}
bool
LiftedCircuit::shatterCountedLogVarsAux (
Clauses& clauses,
size_t idx1,
size_t idx2)
{
Literals lits1 = clauses[idx1]->literals();
Literals lits2 = clauses[idx2]->literals();
2012-11-01 13:56:12 +00:00
for (size_t i = 0; i < lits1.size(); i++) {
for (size_t j = 0; j < lits2.size(); j++) {
if (lits1[i].lid() == lits2[j].lid()) {
LogVars lvs1 = lits1[i].logVars();
LogVars lvs2 = lits2[j].logVars();
for (size_t k = 0; k < lvs1.size(); k++) {
if (clauses[idx1]->isCountedLogVar (lvs1[k])
&& clauses[idx2]->isCountedLogVar (lvs2[k]) == false) {
clauses.push_back (new Clause (*clauses[idx2]));
clauses[idx2]->addPosCountedLogVar (lvs2[k]);
clauses.back()->addNegCountedLogVar (lvs2[k]);
2012-11-01 13:56:12 +00:00
return true;
}
if (clauses[idx2]->isCountedLogVar (lvs2[k])
&& clauses[idx1]->isCountedLogVar (lvs1[k]) == false) {
clauses.push_back (new Clause (*clauses[idx1]));
clauses[idx1]->addPosCountedLogVar (lvs1[k]);
clauses.back()->addNegCountedLogVar (lvs1[k]);
2012-11-01 13:56:12 +00:00
return true;
}
}
}
}
}
return false;
}
2012-11-07 18:42:11 +00:00
bool
2012-11-07 23:45:43 +00:00
LiftedCircuit::independentClause (
2012-11-07 18:42:11 +00:00
Clause& clause,
Clauses& otherClauses) const
{
for (size_t i = 0; i < otherClauses.size(); i++) {
if (Clause::independentClauses (clause, *otherClauses[i]) == false) {
2012-11-07 18:42:11 +00:00
return false;
}
}
return true;
}
2012-11-07 23:45:43 +00:00
bool
LiftedCircuit::independentLiteral (
const Literal& lit,
const Literals& otherLits) const
{
for (size_t i = 0; i < otherLits.size(); i++) {
if (lit.lid() == otherLits[i].lid()
|| (lit.logVarSet() & otherLits[i].logVarSet()).empty() == false) {
return false;
}
}
return true;
}
LitLvTypesSet
2012-10-24 21:22:49 +01:00
LiftedCircuit::smoothCircuit (CircuitNode* node)
{
assert (node != 0);
LitLvTypesSet propagLits;
2012-10-24 21:22:49 +01:00
switch (getCircuitNodeType (node)) {
case CircuitNodeType::OR_NODE: {
OrNode* casted = dynamic_cast<OrNode*>(node);
LitLvTypesSet lids1 = smoothCircuit (*casted->leftBranch());
LitLvTypesSet lids2 = smoothCircuit (*casted->rightBranch());
LitLvTypesSet missingLeft = lids2 - lids1;
LitLvTypesSet missingRight = lids1 - lids2;
createSmoothNode (missingLeft, casted->leftBranch());
createSmoothNode (missingRight, casted->rightBranch());
propagLits |= lids1;
propagLits |= lids2;
2012-10-24 21:22:49 +01:00
break;
}
2012-12-09 22:13:58 +00:00
2012-10-24 21:22:49 +01:00
case CircuitNodeType::AND_NODE: {
AndNode* casted = dynamic_cast<AndNode*>(node);
LitLvTypesSet lids1 = smoothCircuit (*casted->leftBranch());
LitLvTypesSet lids2 = smoothCircuit (*casted->rightBranch());
propagLits |= lids1;
propagLits |= lids2;
2012-10-24 21:22:49 +01:00
break;
}
case CircuitNodeType::SET_OR_NODE: {
SetOrNode* casted = dynamic_cast<SetOrNode*>(node);
propagLits = smoothCircuit (*casted->follow());
TinySet<pair<LiteralId,unsigned>> litSet;
for (size_t i = 0; i < propagLits.size(); i++) {
litSet.insert (make_pair (propagLits[i].lid(),
propagLits[i].logVarTypes().size()));
}
LitLvTypesSet missingLids;
for (size_t i = 0; i < litSet.size(); i++) {
vector<LogVarTypes> allTypes = getAllPossibleTypes (litSet[i].second);
for (size_t j = 0; j < allTypes.size(); j++) {
bool typeFound = false;
for (size_t k = 0; k < propagLits.size(); k++) {
if (litSet[i].first == propagLits[k].lid()
&& containsTypes (propagLits[k].logVarTypes(), allTypes[j])) {
typeFound = true;
break;
}
}
if (typeFound == false) {
2012-11-07 15:28:33 +00:00
missingLids.insert (LitLvTypes (litSet[i].first, allTypes[j]));
}
}
}
createSmoothNode (missingLids, casted->follow());
// setAllFullLogVars() can cause repeated elements in
// the set. Fix this by reconstructing the set again
LitLvTypesSet copy = propagLits;
propagLits.clear();
for (size_t i = 0; i < copy.size(); i++) {
copy[i].setAllFullLogVars();
propagLits.insert (copy[i]);
2012-11-06 15:56:52 +00:00
}
break;
2012-10-24 21:22:49 +01:00
}
2012-12-09 22:13:58 +00:00
2012-10-24 21:22:49 +01:00
case CircuitNodeType::SET_AND_NODE: {
SetAndNode* casted = dynamic_cast<SetAndNode*>(node);
propagLits = smoothCircuit (*casted->follow());
break;
2012-10-24 21:22:49 +01:00
}
2012-12-09 22:13:58 +00:00
2012-10-24 21:22:49 +01:00
case CircuitNodeType::INC_EXC_NODE: {
IncExcNode* casted = dynamic_cast<IncExcNode*>(node);
LitLvTypesSet lids1 = smoothCircuit (*casted->plus1Branch());
LitLvTypesSet lids2 = smoothCircuit (*casted->plus2Branch());
LitLvTypesSet missingPlus1 = lids2 - lids1;
LitLvTypesSet missingPlus2 = lids1 - lids2;
createSmoothNode (missingPlus1, casted->plus1Branch());
createSmoothNode (missingPlus2, casted->plus2Branch());
propagLits |= lids1;
propagLits |= lids2;
break;
2012-10-24 21:22:49 +01:00
}
2012-12-09 22:13:58 +00:00
2012-10-24 21:22:49 +01:00
case CircuitNodeType::LEAF_NODE: {
LeafNode* casted = dynamic_cast<LeafNode*>(node);
2012-11-07 15:28:33 +00:00
propagLits.insert (LitLvTypes (
casted->clause()->literals()[0].lid(),
casted->clause()->logVarTypes(0)));
2012-10-24 21:22:49 +01:00
}
2012-12-09 22:13:58 +00:00
2012-10-24 21:22:49 +01:00
default:
break;
}
2012-12-09 22:13:58 +00:00
return propagLits;
2012-10-24 21:22:49 +01:00
}
void
LiftedCircuit::createSmoothNode (
const LitLvTypesSet& missingLits,
CircuitNode** prev)
{
if (missingLits.empty() == false) {
if (Globals::verbosity > 1) {
2012-12-09 22:13:58 +00:00
unordered_map<CircuitNode*, Clauses>::iterator it;
it = originClausesMap_.find (*prev);
if (it != originClausesMap_.end()) {
backupClauses_ = it->second;
} else {
2012-12-09 22:57:39 +00:00
backupClauses_ = Clause::copyClauses (
{((dynamic_cast<LeafNode*>(*prev))->clause())});
2012-12-09 22:13:58 +00:00
}
}
Clauses clauses;
for (size_t i = 0; i < missingLits.size(); i++) {
LiteralId lid = missingLits[i].lid();
const LogVarTypes& types = missingLits[i].logVarTypes();
Clause* c = lwcnf_->createClause (lid);
for (size_t j = 0; j < types.size(); j++) {
LogVar X = c->literals().front().logVars()[j];
if (types[j] == LogVarType::POS_LV) {
c->addPosCountedLogVar (X);
} else if (types[j] == LogVarType::NEG_LV) {
c->addNegCountedLogVar (X);
}
}
c->addLiteralComplemented (c->literals()[0]);
clauses.push_back (c);
}
SmoothNode* smoothNode = new SmoothNode (clauses, *lwcnf_);
*prev = new AndNode (smoothNode, *prev);
if (Globals::verbosity > 1) {
originClausesMap_[*prev] = backupClauses_;
explanationMap_[*prev] = " Smoothing" ;
}
}
}
2012-11-07 12:37:22 +00:00
vector<LogVarTypes>
LiftedCircuit::getAllPossibleTypes (unsigned nrLogVars) const
{
if (nrLogVars == 0) {
return {};
}
if (nrLogVars == 1) {
return {{LogVarType::POS_LV},{LogVarType::NEG_LV}};
}
vector<LogVarTypes> res;
Ranges ranges (nrLogVars, 2);
Indexer indexer (ranges);
2012-11-07 12:37:22 +00:00
while (indexer.valid()) {
LogVarTypes types;
for (size_t i = 0; i < nrLogVars; i++) {
if (indexer[i] == 0) {
types.push_back (LogVarType::POS_LV);
} else {
types.push_back (LogVarType::NEG_LV);
}
}
res.push_back (types);
++ indexer;
}
return res;
}
bool
LiftedCircuit::containsTypes (
const LogVarTypes& typesA,
const LogVarTypes& typesB) const
{
for (size_t i = 0; i < typesA.size(); i++) {
if (typesA[i] == LogVarType::FULL_LV) {
} else if (typesA[i] == LogVarType::POS_LV
&& typesB[i] == LogVarType::POS_LV) {
} else if (typesA[i] == LogVarType::NEG_LV
&& typesB[i] == LogVarType::NEG_LV) {
} else {
return false;
}
}
return true;
}
2012-10-24 21:22:49 +01:00
CircuitNodeType
LiftedCircuit::getCircuitNodeType (const CircuitNode* node) const
{
CircuitNodeType type;
if (dynamic_cast<const OrNode*>(node) != 0) {
type = CircuitNodeType::OR_NODE;
} else if (dynamic_cast<const AndNode*>(node) != 0) {
type = CircuitNodeType::AND_NODE;
} else if (dynamic_cast<const SetOrNode*>(node) != 0) {
type = CircuitNodeType::SET_OR_NODE;
} else if (dynamic_cast<const SetAndNode*>(node) != 0) {
type = CircuitNodeType::SET_AND_NODE;
2012-10-30 00:21:10 +00:00
} else if (dynamic_cast<const IncExcNode*>(node) != 0) {
type = CircuitNodeType::INC_EXC_NODE;
2012-10-24 21:22:49 +01:00
} else if (dynamic_cast<const LeafNode*>(node) != 0) {
type = CircuitNodeType::LEAF_NODE;
} else if (dynamic_cast<const SmoothNode*>(node) != 0) {
type = CircuitNodeType::SMOOTH_NODE;
} else if (dynamic_cast<const TrueNode*>(node) != 0) {
type = CircuitNodeType::TRUE_NODE;
2012-10-30 12:41:00 +00:00
} else if (dynamic_cast<const CompilationFailedNode*>(node) != 0) {
type = CircuitNodeType::COMPILATION_FAILED_NODE;
2012-10-24 21:22:49 +01:00
} else {
assert (false);
}
return type;
}
void
2012-10-24 21:22:49 +01:00
LiftedCircuit::exportToGraphViz (CircuitNode* node, ofstream& os)
{
assert (node != 0);
2012-12-17 18:39:42 +00:00
static unsigned nrAuxNodes = 0;
2012-10-29 13:49:11 +00:00
stringstream ss;
ss << "n" << nrAuxNodes;
string auxNode = ss.str();
nrAuxNodes ++;
2012-11-07 23:45:43 +00:00
string opStyle = "shape=circle,width=0.7,margin=\"0.0,0.0\"," ;
switch (getCircuitNodeType (node)) {
2012-12-17 18:39:42 +00:00
case OR_NODE: {
OrNode* casted = dynamic_cast<OrNode*>(node);
2012-10-30 14:31:52 +00:00
printClauses (casted, os);
2012-11-07 23:45:43 +00:00
os << auxNode << " [" << opStyle << "label=\"\"]" << endl;
2012-10-29 13:49:11 +00:00
os << escapeNode (node) << " -> " << auxNode;
os << " [label=\"" << getExplanationString (node) << "\"]" ;
os << endl;
2012-12-17 18:39:42 +00:00
2012-10-29 13:49:11 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->leftBranch());
os << " [label=\" " << (*casted->leftBranch())->weight() << "\"]" ;
os << endl;
2012-10-29 13:49:11 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->rightBranch());
os << " [label=\" " << (*casted->rightBranch())->weight() << "\"]" ;
os << endl;
exportToGraphViz (*casted->leftBranch(), os);
exportToGraphViz (*casted->rightBranch(), os);
break;
}
2012-10-31 23:43:39 +00:00
case AND_NODE: {
AndNode* casted = dynamic_cast<AndNode*>(node);
2012-10-30 14:31:52 +00:00
printClauses (casted, os);
2012-10-31 23:43:39 +00:00
2012-11-07 23:45:43 +00:00
os << auxNode << " [" << opStyle << "label=\"\"]" << endl;
2012-10-29 13:49:11 +00:00
os << escapeNode (node) << " -> " << auxNode;
os << " [label=\"" << getExplanationString (node) << "\"]" ;
os << endl;
2012-10-29 13:49:11 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->leftBranch());
os << " [label=\" " << (*casted->leftBranch())->weight() << "\"]" ;
os << endl;
2012-10-29 13:49:11 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->rightBranch()) << endl;
os << " [label=\" " << (*casted->rightBranch())->weight() << "\"]" ;
os << endl;
exportToGraphViz (*casted->leftBranch(), os);
exportToGraphViz (*casted->rightBranch(), os);
break;
}
2012-10-31 23:43:39 +00:00
case SET_OR_NODE: {
2012-10-31 23:43:39 +00:00
SetOrNode* casted = dynamic_cast<SetOrNode*>(node);
printClauses (casted, os);
2012-11-07 23:45:43 +00:00
os << auxNode << " [" << opStyle << "label=\"(X)\"]" << endl;
2012-10-31 23:43:39 +00:00
os << escapeNode (node) << " -> " << auxNode;
os << " [label=\"" << getExplanationString (node) << "\"]" ;
2012-10-31 23:43:39 +00:00
os << endl;
os << auxNode << " -> " ;
os << escapeNode (*casted->follow());
os << " [label=\" " << (*casted->follow())->weight() << "\"]" ;
os << endl;
exportToGraphViz (*casted->follow(), os);
break;
}
2012-10-31 23:43:39 +00:00
case SET_AND_NODE: {
SetAndNode* casted = dynamic_cast<SetAndNode*>(node);
2012-10-30 14:31:52 +00:00
printClauses (casted, os);
2012-10-31 23:43:39 +00:00
2012-11-07 23:45:43 +00:00
os << auxNode << " [" << opStyle << "label=\"∧(X)\"]" << endl;
2012-10-29 13:49:11 +00:00
os << escapeNode (node) << " -> " << auxNode;
os << " [label=\"" << getExplanationString (node) << "\"]" ;
os << endl;
2012-10-31 23:43:39 +00:00
2012-10-29 13:49:11 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->follow());
os << " [label=\" " << (*casted->follow())->weight() << "\"]" ;
os << endl;
2012-10-31 23:43:39 +00:00
exportToGraphViz (*casted->follow(), os);
break;
}
2012-10-31 23:43:39 +00:00
2012-10-30 00:21:10 +00:00
case INC_EXC_NODE: {
IncExcNode* casted = dynamic_cast<IncExcNode*>(node);
2012-10-30 14:31:52 +00:00
printClauses (casted, os);
2012-10-31 23:43:39 +00:00
2012-11-07 23:45:43 +00:00
os << auxNode << " [" << opStyle << "label=\"+ - +\"]" ;
os << endl;
2012-10-30 00:21:10 +00:00
os << escapeNode (node) << " -> " << auxNode;
os << " [label=\"" << getExplanationString (node) << "\"]" ;
2012-10-30 00:21:10 +00:00
os << endl;
os << auxNode << " -> " ;
os << escapeNode (*casted->plus1Branch());
os << " [label=\" " << (*casted->plus1Branch())->weight() << "\"]" ;
os << endl;
2012-11-07 23:45:43 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->minusBranch()) << endl;
os << " [label=\" " << (*casted->minusBranch())->weight() << "\"]" ;
os << endl;
2012-10-31 23:43:39 +00:00
2012-10-30 00:21:10 +00:00
os << auxNode << " -> " ;
os << escapeNode (*casted->plus2Branch());
os << " [label=\" " << (*casted->plus2Branch())->weight() << "\"]" ;
os << endl;
exportToGraphViz (*casted->plus1Branch(), os);
exportToGraphViz (*casted->plus2Branch(), os);
exportToGraphViz (*casted->minusBranch(), os);
break;
}
2012-10-31 23:43:39 +00:00
case LEAF_NODE: {
2012-10-30 16:00:20 +00:00
printClauses (node, os, "style=filled,fillcolor=palegreen,");
break;
2012-10-24 21:22:49 +01:00
}
2012-10-31 23:43:39 +00:00
case SMOOTH_NODE: {
2012-10-30 16:00:20 +00:00
printClauses (node, os, "style=filled,fillcolor=lightblue,");
break;
}
2012-10-31 23:43:39 +00:00
case TRUE_NODE: {
os << escapeNode (node);
os << " [shape=box,label=\"\"]" ;
os << endl;
break;
2012-10-24 21:22:49 +01:00
}
2012-10-31 23:43:39 +00:00
2012-10-30 12:41:00 +00:00
case COMPILATION_FAILED_NODE: {
2012-10-30 16:00:20 +00:00
printClauses (node, os, "style=filled,fillcolor=salmon,");
break;
}
2012-10-31 23:43:39 +00:00
default:
assert (false);
}
}
2012-10-30 14:31:52 +00:00
string
LiftedCircuit::escapeNode (const CircuitNode* node) const
{
stringstream ss;
ss << "\"" << node << "\"" ;
return ss.str();
}
string
LiftedCircuit::getExplanationString (CircuitNode* node)
{
return Util::contains (explanationMap_, node)
? explanationMap_[node]
: "" ;
}
2012-10-30 14:31:52 +00:00
void
LiftedCircuit::printClauses (
CircuitNode* node,
2012-10-30 14:31:52 +00:00
ofstream& os,
string extraOptions)
{
Clauses clauses;
if (Util::contains (originClausesMap_, node)) {
clauses = originClausesMap_[node];
} else if (getCircuitNodeType (node) == CircuitNodeType::LEAF_NODE) {
2012-12-09 22:13:58 +00:00
clauses = { (dynamic_cast<LeafNode*>(node))->clause() } ;
} else if (getCircuitNodeType (node) == CircuitNodeType::SMOOTH_NODE) {
2012-12-09 22:13:58 +00:00
clauses = (dynamic_cast<SmoothNode*>(node))->clauses();
}
2012-12-09 22:13:58 +00:00
assert (clauses.empty() == false);
os << escapeNode (node);
os << " [shape=box," << extraOptions << "label=\"" ;
for (size_t i = 0; i < clauses.size(); i++) {
if (i != 0) os << "\\n" ;
os << *clauses[i];
2012-10-30 14:31:52 +00:00
}
2012-12-09 22:13:58 +00:00
os << "\"]" ;
os << endl;
2012-10-30 14:31:52 +00:00
}