This shouldn't be on the repository
This commit is contained in:
parent
4b901d26d7
commit
d8c5725b2e
@ -1,84 +0,0 @@
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "BayesBall.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
FactorGraph*
|
||||
BayesBall::getMinimalFactorGraph (const VarIds& queryIds)
|
||||
{
|
||||
assert (fg_.bayesianFactors());
|
||||
Scheduling scheduling;
|
||||
for (size_t i = 0; i < queryIds.size(); i++) {
|
||||
assert (dag_.getNode (queryIds[i]));
|
||||
BBNode* n = dag_.getNode (queryIds[i]);
|
||||
scheduling.push (ScheduleInfo (n, false, true));
|
||||
}
|
||||
|
||||
while (!scheduling.empty()) {
|
||||
ScheduleInfo& sch = scheduling.front();
|
||||
BBNode* n = sch.node;
|
||||
n->setAsVisited();
|
||||
if (n->hasEvidence() == false && sch.visitedFromChild) {
|
||||
if (n->isMarkedOnTop() == false) {
|
||||
n->markOnTop();
|
||||
scheduleParents (n, scheduling);
|
||||
}
|
||||
if (n->isMarkedOnBottom() == false) {
|
||||
n->markOnBottom();
|
||||
scheduleChilds (n, scheduling);
|
||||
}
|
||||
}
|
||||
if (sch.visitedFromParent) {
|
||||
if (n->hasEvidence() && n->isMarkedOnTop() == false) {
|
||||
n->markOnTop();
|
||||
scheduleParents (n, scheduling);
|
||||
}
|
||||
if (n->hasEvidence() == false && n->isMarkedOnBottom() == false) {
|
||||
n->markOnBottom();
|
||||
scheduleChilds (n, scheduling);
|
||||
}
|
||||
}
|
||||
scheduling.pop();
|
||||
}
|
||||
|
||||
FactorGraph* fg = new FactorGraph();
|
||||
constructGraph (fg);
|
||||
return fg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BayesBall::constructGraph (FactorGraph* fg) const
|
||||
{
|
||||
const FacNodes& facNodes = fg_.facNodes();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
const BBNode* n = dag_.getNode (
|
||||
facNodes[i]->factor().argument (0));
|
||||
if (n->isMarkedOnTop()) {
|
||||
fg->addFactor (facNodes[i]->factor());
|
||||
} else if (n->hasEvidence() && n->isVisited()) {
|
||||
VarIds varIds = { facNodes[i]->factor().argument (0) };
|
||||
Ranges ranges = { facNodes[i]->factor().range (0) };
|
||||
Params params (ranges[0], LogAware::noEvidence());
|
||||
params[n->getEvidence()] = LogAware::withEvidence();
|
||||
fg->addFactor (Factor (varIds, ranges, params));
|
||||
}
|
||||
}
|
||||
const VarNodes& varNodes = fg_.varNodes();
|
||||
for (size_t i = 0; i < varNodes.size(); i++) {
|
||||
if (varNodes[i]->hasEvidence()) {
|
||||
VarNode* vn = fg->getVarNode (varNodes[i]->varId());
|
||||
if (vn) {
|
||||
vn->setEvidence (varNodes[i]->getEvidence());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
#ifndef HORUS_BAYESBALL_H
|
||||
#define HORUS_BAYESBALL_H
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "FactorGraph.h"
|
||||
#include "BayesBallGraph.h"
|
||||
#include "Horus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct ScheduleInfo
|
||||
{
|
||||
ScheduleInfo (BBNode* n, bool vfp, bool vfc) :
|
||||
node(n), visitedFromParent(vfp), visitedFromChild(vfc) { }
|
||||
|
||||
BBNode* node;
|
||||
bool visitedFromParent;
|
||||
bool visitedFromChild;
|
||||
};
|
||||
|
||||
|
||||
typedef queue<ScheduleInfo, list<ScheduleInfo>> Scheduling;
|
||||
|
||||
|
||||
class BayesBall
|
||||
{
|
||||
public:
|
||||
BayesBall (FactorGraph& fg)
|
||||
: fg_(fg) , dag_(fg.getStructure())
|
||||
{
|
||||
dag_.clear();
|
||||
}
|
||||
|
||||
FactorGraph* getMinimalFactorGraph (const VarIds&);
|
||||
|
||||
static FactorGraph* getMinimalFactorGraph (FactorGraph& fg, VarIds vids)
|
||||
{
|
||||
BayesBall bb (fg);
|
||||
return bb.getMinimalFactorGraph (vids);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void constructGraph (FactorGraph* fg) const;
|
||||
|
||||
void scheduleParents (const BBNode* n, Scheduling& sch) const;
|
||||
|
||||
void scheduleChilds (const BBNode* n, Scheduling& sch) const;
|
||||
|
||||
FactorGraph& fg_;
|
||||
|
||||
BayesBallGraph& dag_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void
|
||||
BayesBall::scheduleParents (const BBNode* n, Scheduling& sch) const
|
||||
{
|
||||
const vector<BBNode*>& ps = n->parents();
|
||||
for (vector<BBNode*>::const_iterator it = ps.begin();
|
||||
it != ps.end(); ++it) {
|
||||
sch.push (ScheduleInfo (*it, false, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void
|
||||
BayesBall::scheduleChilds (const BBNode* n, Scheduling& sch) const
|
||||
{
|
||||
const vector<BBNode*>& cs = n->childs();
|
||||
for (vector<BBNode*>::const_iterator it = cs.begin();
|
||||
it != cs.end(); ++it) {
|
||||
sch.push (ScheduleInfo (*it, true, false));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HORUS_BAYESBALL_H
|
||||
|
@ -1,106 +0,0 @@
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "BayesBallGraph.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
void
|
||||
BayesBallGraph::addNode (BBNode* n)
|
||||
{
|
||||
assert (Util::contains (varMap_, n->varId()) == false);
|
||||
nodes_.push_back (n);
|
||||
varMap_[n->varId()] = n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BayesBallGraph::addEdge (VarId vid1, VarId vid2)
|
||||
{
|
||||
unordered_map<VarId, BBNode*>::iterator it1;
|
||||
unordered_map<VarId, BBNode*>::iterator it2;
|
||||
it1 = varMap_.find (vid1);
|
||||
it2 = varMap_.find (vid2);
|
||||
assert (it1 != varMap_.end());
|
||||
assert (it2 != varMap_.end());
|
||||
it1->second->addChild (it2->second);
|
||||
it2->second->addParent (it1->second);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const BBNode*
|
||||
BayesBallGraph::getNode (VarId vid) const
|
||||
{
|
||||
unordered_map<VarId, BBNode*>::const_iterator it;
|
||||
it = varMap_.find (vid);
|
||||
return it != varMap_.end() ? it->second : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BBNode*
|
||||
BayesBallGraph::getNode (VarId vid)
|
||||
{
|
||||
unordered_map<VarId, BBNode*>::const_iterator it;
|
||||
it = varMap_.find (vid);
|
||||
return it != varMap_.end() ? it->second : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BayesBallGraph::setIndexes (void)
|
||||
{
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
nodes_[i]->setIndex (i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BayesBallGraph::clear (void)
|
||||
{
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
nodes_[i]->clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BayesBallGraph::exportToGraphViz (const char* fileName)
|
||||
{
|
||||
ofstream out (fileName);
|
||||
if (!out.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
return;
|
||||
}
|
||||
out << "digraph {" << endl;
|
||||
out << "ranksep=1" << endl;
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
out << nodes_[i]->varId() ;
|
||||
out << " [" ;
|
||||
out << "label=\"" << nodes_[i]->label() << "\"" ;
|
||||
if (nodes_[i]->hasEvidence()) {
|
||||
out << ",style=filled, fillcolor=yellow" ;
|
||||
}
|
||||
out << "]" << endl;
|
||||
}
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
const vector<BBNode*>& childs = nodes_[i]->childs();
|
||||
for (size_t j = 0; j < childs.size(); j++) {
|
||||
out << nodes_[i]->varId() << " -> " << childs[j]->varId();
|
||||
out << " [style=bold]" << endl ;
|
||||
}
|
||||
}
|
||||
out << "}" << endl;
|
||||
out.close();
|
||||
}
|
||||
|
@ -1,84 +0,0 @@
|
||||
#ifndef HORUS_BAYESBALLGRAPH_H
|
||||
#define HORUS_BAYESBALLGRAPH_H
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "Var.h"
|
||||
#include "Horus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BBNode : public Var
|
||||
{
|
||||
public:
|
||||
BBNode (Var* v) : Var (v) , visited_(false),
|
||||
markedOnTop_(false), markedOnBottom_(false) { }
|
||||
|
||||
const vector<BBNode*>& childs (void) const { return childs_; }
|
||||
|
||||
vector<BBNode*>& childs (void) { return childs_; }
|
||||
|
||||
const vector<BBNode*>& parents (void) const { return parents_; }
|
||||
|
||||
vector<BBNode*>& parents (void) { return parents_; }
|
||||
|
||||
void addParent (BBNode* p) { parents_.push_back (p); }
|
||||
|
||||
void addChild (BBNode* c) { childs_.push_back (c); }
|
||||
|
||||
bool isVisited (void) const { return visited_; }
|
||||
|
||||
void setAsVisited (void) { visited_ = true; }
|
||||
|
||||
bool isMarkedOnTop (void) const { return markedOnTop_; }
|
||||
|
||||
void markOnTop (void) { markedOnTop_ = true; }
|
||||
|
||||
bool isMarkedOnBottom (void) const { return markedOnBottom_; }
|
||||
|
||||
void markOnBottom (void) { markedOnBottom_ = true; }
|
||||
|
||||
void clear (void) { visited_ = markedOnTop_ = markedOnBottom_ = false; }
|
||||
|
||||
private:
|
||||
bool visited_;
|
||||
bool markedOnTop_;
|
||||
bool markedOnBottom_;
|
||||
|
||||
vector<BBNode*> childs_;
|
||||
vector<BBNode*> parents_;
|
||||
};
|
||||
|
||||
|
||||
class BayesBallGraph
|
||||
{
|
||||
public:
|
||||
BayesBallGraph (void) { }
|
||||
|
||||
void addNode (BBNode* n);
|
||||
|
||||
void addEdge (VarId vid1, VarId vid2);
|
||||
|
||||
const BBNode* getNode (VarId vid) const;
|
||||
|
||||
BBNode* getNode (VarId vid);
|
||||
|
||||
bool empty (void) const { return nodes_.empty(); }
|
||||
|
||||
void setIndexes (void);
|
||||
|
||||
void clear (void);
|
||||
|
||||
void exportToGraphViz (const char*);
|
||||
|
||||
private:
|
||||
vector<BBNode*> nodes_;
|
||||
|
||||
unordered_map<VarId, BBNode*> varMap_;
|
||||
};
|
||||
|
||||
#endif // HORUS_BAYESBALLGRAPH_H
|
||||
|
@ -1,471 +0,0 @@
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "BeliefProp.h"
|
||||
#include "FactorGraph.h"
|
||||
#include "Factor.h"
|
||||
#include "Indexer.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
BeliefProp::BeliefProp (const FactorGraph& fg) : GroundSolver (fg)
|
||||
{
|
||||
runned_ = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BeliefProp::~BeliefProp (void)
|
||||
{
|
||||
for (size_t i = 0; i < varsI_.size(); i++) {
|
||||
delete varsI_[i];
|
||||
}
|
||||
for (size_t i = 0; i < facsI_.size(); i++) {
|
||||
delete facsI_[i];
|
||||
}
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
delete links_[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
BeliefProp::solveQuery (VarIds queryVids)
|
||||
{
|
||||
assert (queryVids.empty() == false);
|
||||
return queryVids.size() == 1
|
||||
? getPosterioriOf (queryVids[0])
|
||||
: getJointDistributionOf (queryVids);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::printSolverFlags (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "belief propagation [" ;
|
||||
ss << "schedule=" ;
|
||||
typedef BpOptions::Schedule Sch;
|
||||
switch (BpOptions::schedule) {
|
||||
case Sch::SEQ_FIXED: ss << "seq_fixed"; break;
|
||||
case Sch::SEQ_RANDOM: ss << "seq_random"; break;
|
||||
case Sch::PARALLEL: ss << "parallel"; break;
|
||||
case Sch::MAX_RESIDUAL: ss << "max_residual"; break;
|
||||
}
|
||||
ss << ",max_iter=" << Util::toString (BpOptions::maxIter);
|
||||
ss << ",accuracy=" << Util::toString (BpOptions::accuracy);
|
||||
ss << ",log_domain=" << Util::toString (Globals::logDomain);
|
||||
ss << "]" ;
|
||||
cout << ss.str() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
BeliefProp::getPosterioriOf (VarId vid)
|
||||
{
|
||||
if (runned_ == false) {
|
||||
runSolver();
|
||||
}
|
||||
assert (fg.getVarNode (vid));
|
||||
VarNode* var = fg.getVarNode (vid);
|
||||
Params probs;
|
||||
if (var->hasEvidence()) {
|
||||
probs.resize (var->range(), LogAware::noEvidence());
|
||||
probs[var->getEvidence()] = LogAware::withEvidence();
|
||||
} else {
|
||||
probs.resize (var->range(), LogAware::multIdenty());
|
||||
const BpLinks& links = ninf(var)->getLinks();
|
||||
if (Globals::logDomain) {
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
probs += links[i]->message();
|
||||
}
|
||||
LogAware::normalize (probs);
|
||||
Util::exp (probs);
|
||||
} else {
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
probs *= links[i]->message();
|
||||
}
|
||||
LogAware::normalize (probs);
|
||||
}
|
||||
}
|
||||
return probs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
BeliefProp::getJointDistributionOf (const VarIds& jointVarIds)
|
||||
{
|
||||
if (runned_ == false) {
|
||||
runSolver();
|
||||
}
|
||||
VarNode* vn = fg.getVarNode (jointVarIds[0]);
|
||||
const FacNodes& facNodes = vn->neighbors();
|
||||
size_t idx = facNodes.size();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
if (facNodes[i]->factor().contains (jointVarIds)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == facNodes.size()) {
|
||||
return getJointByConditioning (jointVarIds);
|
||||
}
|
||||
return getFactorJoint (facNodes[idx], jointVarIds);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
BeliefProp::getFactorJoint (
|
||||
FacNode* fn,
|
||||
const VarIds& jointVarIds)
|
||||
{
|
||||
if (runned_ == false) {
|
||||
runSolver();
|
||||
}
|
||||
Factor res (fn->factor());
|
||||
const BpLinks& links = ninf(fn)->getLinks();
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
Factor msg ({links[i]->varNode()->varId()},
|
||||
{links[i]->varNode()->range()},
|
||||
getVarToFactorMsg (links[i]));
|
||||
res.multiply (msg);
|
||||
}
|
||||
res.sumOutAllExcept (jointVarIds);
|
||||
res.reorderArguments (jointVarIds);
|
||||
res.normalize();
|
||||
Params jointDist = res.params();
|
||||
if (Globals::logDomain) {
|
||||
Util::exp (jointDist);
|
||||
}
|
||||
return jointDist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::runSolver (void)
|
||||
{
|
||||
initializeSolver();
|
||||
nIters_ = 0;
|
||||
while (!converged() && nIters_ < BpOptions::maxIter) {
|
||||
nIters_ ++;
|
||||
if (Globals::verbosity > 1) {
|
||||
Util::printHeader (string ("Iteration ") + Util::toString (nIters_));
|
||||
}
|
||||
switch (BpOptions::schedule) {
|
||||
case BpOptions::Schedule::SEQ_RANDOM:
|
||||
std::random_shuffle (links_.begin(), links_.end());
|
||||
// no break
|
||||
case BpOptions::Schedule::SEQ_FIXED:
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
calculateAndUpdateMessage (links_[i]);
|
||||
}
|
||||
break;
|
||||
case BpOptions::Schedule::PARALLEL:
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
calculateMessage (links_[i]);
|
||||
}
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
updateMessage(links_[i]);
|
||||
}
|
||||
break;
|
||||
case BpOptions::Schedule::MAX_RESIDUAL:
|
||||
maxResidualSchedule();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Globals::verbosity > 0) {
|
||||
if (nIters_ < BpOptions::maxIter) {
|
||||
cout << "Belief propagation converged in " ;
|
||||
cout << nIters_ << " iterations" << endl;
|
||||
} else {
|
||||
cout << "The maximum number of iterations was hit, terminating..." ;
|
||||
cout << endl;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
runned_ = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::createLinks (void)
|
||||
{
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
const VarNodes& neighbors = facNodes[i]->neighbors();
|
||||
for (size_t j = 0; j < neighbors.size(); j++) {
|
||||
links_.push_back (new BpLink (facNodes[i], neighbors[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::maxResidualSchedule (void)
|
||||
{
|
||||
if (nIters_ == 1) {
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
calculateMessage (links_[i]);
|
||||
SortedOrder::iterator it = sortedOrder_.insert (links_[i]);
|
||||
linkMap_.insert (make_pair (links_[i], it));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < links_.size(); c++) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "current residuals:" << endl;
|
||||
for (SortedOrder::iterator it = sortedOrder_.begin();
|
||||
it != sortedOrder_.end(); ++it) {
|
||||
cout << " " << setw (30) << left << (*it)->toString();
|
||||
cout << "residual = " << (*it)->residual() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
SortedOrder::iterator it = sortedOrder_.begin();
|
||||
BpLink* link = *it;
|
||||
if (link->residual() < BpOptions::accuracy) {
|
||||
return;
|
||||
}
|
||||
updateMessage (link);
|
||||
link->clearResidual();
|
||||
sortedOrder_.erase (it);
|
||||
linkMap_.find (link)->second = sortedOrder_.insert (link);
|
||||
|
||||
// update the messages that depend on message source --> destin
|
||||
const FacNodes& factorNeighbors = link->varNode()->neighbors();
|
||||
for (size_t i = 0; i < factorNeighbors.size(); i++) {
|
||||
if (factorNeighbors[i] != link->facNode()) {
|
||||
const BpLinks& links = ninf(factorNeighbors[i])->getLinks();
|
||||
for (size_t j = 0; j < links.size(); j++) {
|
||||
if (links[j]->varNode() != link->varNode()) {
|
||||
calculateMessage (links[j]);
|
||||
BpLinkMap::iterator iter = linkMap_.find (links[j]);
|
||||
sortedOrder_.erase (iter->second);
|
||||
iter->second = sortedOrder_.insert (links[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Globals::verbosity > 1) {
|
||||
Util::printDashedLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::calcFactorToVarMsg (BpLink* link)
|
||||
{
|
||||
FacNode* src = link->facNode();
|
||||
const VarNode* dst = link->varNode();
|
||||
const BpLinks& links = ninf(src)->getLinks();
|
||||
// calculate the product of messages that were sent
|
||||
// to factor `src', except from var `dst'
|
||||
unsigned reps = 1;
|
||||
unsigned msgSize = Util::sizeExpected (src->factor().ranges());
|
||||
Params msgProduct (msgSize, LogAware::multIdenty());
|
||||
if (Globals::logDomain) {
|
||||
for (size_t i = links.size(); i-- > 0; ) {
|
||||
if (links[i]->varNode() != dst) {
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " message from " << links[i]->varNode()->label();
|
||||
cout << ": " ;
|
||||
}
|
||||
Util::apply_n_times (msgProduct, getVarToFactorMsg (links[i]),
|
||||
reps, std::plus<double>());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
reps *= links[i]->varNode()->range();
|
||||
}
|
||||
} else {
|
||||
for (size_t i = links.size(); i-- > 0; ) {
|
||||
if (links[i]->varNode() != dst) {
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " message from " << links[i]->varNode()->label();
|
||||
cout << ": " ;
|
||||
}
|
||||
Util::apply_n_times (msgProduct, getVarToFactorMsg (links[i]),
|
||||
reps, std::multiplies<double>());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
reps *= links[i]->varNode()->range();
|
||||
}
|
||||
}
|
||||
Factor result (src->factor().arguments(),
|
||||
src->factor().ranges(), msgProduct);
|
||||
result.multiply (src->factor());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " message product: " << msgProduct << endl;
|
||||
cout << " original factor: " << src->factor().params() << endl;
|
||||
cout << " factor product: " << result.params() << endl;
|
||||
}
|
||||
result.sumOutAllExcept (dst->varId());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " marginalized: " << result.params() << endl;
|
||||
}
|
||||
link->nextMessage() = result.params();
|
||||
LogAware::normalize (link->nextMessage());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " curr msg: " << link->message() << endl;
|
||||
cout << " next msg: " << link->nextMessage() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
BeliefProp::getVarToFactorMsg (const BpLink* link) const
|
||||
{
|
||||
const VarNode* src = link->varNode();
|
||||
Params msg;
|
||||
if (src->hasEvidence()) {
|
||||
msg.resize (src->range(), LogAware::noEvidence());
|
||||
msg[src->getEvidence()] = LogAware::withEvidence();
|
||||
} else {
|
||||
msg.resize (src->range(), LogAware::one());
|
||||
}
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << msg;
|
||||
}
|
||||
BpLinks::const_iterator it;
|
||||
const BpLinks& links = ninf (src)->getLinks();
|
||||
if (Globals::logDomain) {
|
||||
for (it = links.begin(); it != links.end(); ++it) {
|
||||
if (*it != link) {
|
||||
msg += (*it)->message();
|
||||
}
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " x " << (*it)->message();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (it = links.begin(); it != links.end(); ++it) {
|
||||
if (*it != link) {
|
||||
msg *= (*it)->message();
|
||||
}
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " x " << (*it)->message();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " = " << msg;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
BeliefProp::getJointByConditioning (const VarIds& jointVarIds) const
|
||||
{
|
||||
return GroundSolver::getJointByConditioning (
|
||||
GroundSolverType::BP, fg, jointVarIds);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::initializeSolver (void)
|
||||
{
|
||||
const VarNodes& varNodes = fg.varNodes();
|
||||
varsI_.reserve (varNodes.size());
|
||||
for (size_t i = 0; i < varNodes.size(); i++) {
|
||||
varsI_.push_back (new SPNodeInfo());
|
||||
}
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
facsI_.reserve (facNodes.size());
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
facsI_.push_back (new SPNodeInfo());
|
||||
}
|
||||
createLinks();
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
FacNode* src = links_[i]->facNode();
|
||||
VarNode* dst = links_[i]->varNode();
|
||||
ninf (dst)->addBpLink (links_[i]);
|
||||
ninf (src)->addBpLink (links_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
BeliefProp::converged (void)
|
||||
{
|
||||
if (links_.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
if (nIters_ == 0) {
|
||||
return false;
|
||||
}
|
||||
if (Globals::verbosity > 2) {
|
||||
cout << endl;
|
||||
}
|
||||
if (nIters_ == 1) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "no residuals" << endl << endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool converged = true;
|
||||
if (BpOptions::schedule == BpOptions::Schedule::MAX_RESIDUAL) {
|
||||
double maxResidual = (*(sortedOrder_.begin()))->residual();
|
||||
if (maxResidual > BpOptions::accuracy) {
|
||||
converged = false;
|
||||
} else {
|
||||
converged = true;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
double residual = links_[i]->residual();
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << links_[i]->toString() + " residual = " << residual << endl;
|
||||
}
|
||||
if (residual > BpOptions::accuracy) {
|
||||
converged = false;
|
||||
if (Globals::verbosity < 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
return converged;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BeliefProp::printLinkInformation (void) const
|
||||
{
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
BpLink* l = links_[i];
|
||||
cout << l->toString() << ":" << endl;
|
||||
cout << " curr msg = " ;
|
||||
cout << l->message() << endl;
|
||||
cout << " next msg = " ;
|
||||
cout << l->nextMessage() << endl;
|
||||
cout << " residual = " << l->residual() << endl;
|
||||
}
|
||||
}
|
||||
|
@ -1,188 +0,0 @@
|
||||
#ifndef HORUS_BELIEFPROP_H
|
||||
#define HORUS_BELIEFPROP_H
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "GroundSolver.h"
|
||||
#include "Factor.h"
|
||||
#include "FactorGraph.h"
|
||||
#include "Util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class BpLink
|
||||
{
|
||||
public:
|
||||
BpLink (FacNode* fn, VarNode* vn)
|
||||
{
|
||||
fac_ = fn;
|
||||
var_ = vn;
|
||||
v1_.resize (vn->range(), LogAware::log (1.0 / vn->range()));
|
||||
v2_.resize (vn->range(), LogAware::log (1.0 / vn->range()));
|
||||
currMsg_ = &v1_;
|
||||
nextMsg_ = &v2_;
|
||||
residual_ = 0.0;
|
||||
}
|
||||
|
||||
virtual ~BpLink (void) { };
|
||||
|
||||
FacNode* facNode (void) const { return fac_; }
|
||||
|
||||
VarNode* varNode (void) const { return var_; }
|
||||
|
||||
const Params& message (void) const { return *currMsg_; }
|
||||
|
||||
Params& nextMessage (void) { return *nextMsg_; }
|
||||
|
||||
double residual (void) const { return residual_; }
|
||||
|
||||
void clearResidual (void) { residual_ = 0.0; }
|
||||
|
||||
void updateResidual (void)
|
||||
{
|
||||
residual_ = LogAware::getMaxNorm (v1_,v2_);
|
||||
}
|
||||
|
||||
virtual void updateMessage (void)
|
||||
{
|
||||
swap (currMsg_, nextMsg_);
|
||||
}
|
||||
|
||||
string toString (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << fac_->getLabel();
|
||||
ss << " -- " ;
|
||||
ss << var_->label();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
FacNode* fac_;
|
||||
VarNode* var_;
|
||||
Params v1_;
|
||||
Params v2_;
|
||||
Params* currMsg_;
|
||||
Params* nextMsg_;
|
||||
double residual_;
|
||||
};
|
||||
|
||||
typedef vector<BpLink*> BpLinks;
|
||||
|
||||
|
||||
class SPNodeInfo
|
||||
{
|
||||
public:
|
||||
void addBpLink (BpLink* link) { links_.push_back (link); }
|
||||
const BpLinks& getLinks (void) { return links_; }
|
||||
private:
|
||||
BpLinks links_;
|
||||
};
|
||||
|
||||
|
||||
class BeliefProp : public GroundSolver
|
||||
{
|
||||
public:
|
||||
BeliefProp (const FactorGraph&);
|
||||
|
||||
virtual ~BeliefProp (void);
|
||||
|
||||
Params solveQuery (VarIds);
|
||||
|
||||
virtual void printSolverFlags (void) const;
|
||||
|
||||
virtual Params getPosterioriOf (VarId);
|
||||
|
||||
virtual Params getJointDistributionOf (const VarIds&);
|
||||
|
||||
protected:
|
||||
void runSolver (void);
|
||||
|
||||
virtual void createLinks (void);
|
||||
|
||||
virtual void maxResidualSchedule (void);
|
||||
|
||||
virtual void calcFactorToVarMsg (BpLink*);
|
||||
|
||||
virtual Params getVarToFactorMsg (const BpLink*) const;
|
||||
|
||||
virtual Params getJointByConditioning (const VarIds&) const;
|
||||
|
||||
public:
|
||||
Params getFactorJoint (FacNode* fn, const VarIds&);
|
||||
|
||||
protected:
|
||||
SPNodeInfo* ninf (const VarNode* var) const
|
||||
{
|
||||
return varsI_[var->getIndex()];
|
||||
}
|
||||
|
||||
SPNodeInfo* ninf (const FacNode* fac) const
|
||||
{
|
||||
return facsI_[fac->getIndex()];
|
||||
}
|
||||
|
||||
void calculateAndUpdateMessage (BpLink* link, bool calcResidual = true)
|
||||
{
|
||||
if (Globals::verbosity > 2) {
|
||||
cout << "calculating & updating " << link->toString() << endl;
|
||||
}
|
||||
calcFactorToVarMsg (link);
|
||||
if (calcResidual) {
|
||||
link->updateResidual();
|
||||
}
|
||||
link->updateMessage();
|
||||
}
|
||||
|
||||
void calculateMessage (BpLink* link, bool calcResidual = true)
|
||||
{
|
||||
if (Globals::verbosity > 2) {
|
||||
cout << "calculating " << link->toString() << endl;
|
||||
}
|
||||
calcFactorToVarMsg (link);
|
||||
if (calcResidual) {
|
||||
link->updateResidual();
|
||||
}
|
||||
}
|
||||
|
||||
void updateMessage (BpLink* link)
|
||||
{
|
||||
link->updateMessage();
|
||||
if (Globals::verbosity > 2) {
|
||||
cout << "updating " << link->toString() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
struct CompareResidual
|
||||
{
|
||||
inline bool operator() (const BpLink* link1, const BpLink* link2)
|
||||
{
|
||||
return link1->residual() > link2->residual();
|
||||
}
|
||||
};
|
||||
|
||||
BpLinks links_;
|
||||
unsigned nIters_;
|
||||
vector<SPNodeInfo*> varsI_;
|
||||
vector<SPNodeInfo*> facsI_;
|
||||
bool runned_;
|
||||
|
||||
typedef multiset<BpLink*, CompareResidual> SortedOrder;
|
||||
SortedOrder sortedOrder_;
|
||||
|
||||
typedef unordered_map<BpLink*, SortedOrder::iterator> BpLinkMap;
|
||||
BpLinkMap linkMap_;
|
||||
|
||||
private:
|
||||
void initializeSolver (void);
|
||||
|
||||
bool converged (void);
|
||||
|
||||
virtual void printLinkInformation (void) const;
|
||||
};
|
||||
|
||||
#endif // HORUS_BELIEFPROP_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,237 +0,0 @@
|
||||
#ifndef HORUS_CONSTRAINTTREE_H
|
||||
#define HORUS_CONSTRAINTTREE_H
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "TinySet.h"
|
||||
#include "LiftedUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CTNode;
|
||||
typedef vector<CTNode*> CTNodes;
|
||||
|
||||
class ConstraintTree;
|
||||
typedef vector<ConstraintTree*> ConstraintTrees;
|
||||
|
||||
|
||||
class CTNode
|
||||
{
|
||||
public:
|
||||
|
||||
struct CompareSymbol
|
||||
{
|
||||
bool operator() (const CTNode* n1, const CTNode* n2) const
|
||||
{
|
||||
return n1->symbol() < n2->symbol();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
typedef TinySet<CTNode*, CompareSymbol> CTChilds_;
|
||||
|
||||
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 (void) const { return level_; }
|
||||
|
||||
void setLevel (unsigned level) { level_ = level; }
|
||||
|
||||
Symbol symbol (void) const { return symbol_; }
|
||||
|
||||
void setSymbol (const Symbol s) { symbol_ = s; }
|
||||
|
||||
public:
|
||||
|
||||
CTChilds_& childs (void) { return childs_; }
|
||||
|
||||
const CTChilds_& childs (void) const { return childs_; }
|
||||
|
||||
size_t nrChilds (void) const { return childs_.size(); }
|
||||
|
||||
bool isRoot (void) const { return level_ == 0; }
|
||||
|
||||
bool isLeaf (void) const { return childs_.empty(); }
|
||||
|
||||
CTChilds_::iterator findSymbol (Symbol symb)
|
||||
{
|
||||
CTNode tmp (symb, 0);
|
||||
return childs_.find (&tmp);
|
||||
}
|
||||
|
||||
void mergeSubtree (CTNode*, bool = true);
|
||||
|
||||
void removeChild (CTNode*);
|
||||
|
||||
void removeChilds (void);
|
||||
|
||||
void removeAndDeleteChild (CTNode*);
|
||||
|
||||
void removeAndDeleteAllChilds (void);
|
||||
|
||||
SymbolSet childSymbols (void) const;
|
||||
|
||||
static CTNode* copySubtree (const CTNode*);
|
||||
|
||||
static void deleteSubtree (CTNode*);
|
||||
|
||||
private:
|
||||
void updateChildLevels (CTNode*, unsigned);
|
||||
|
||||
Symbol symbol_;
|
||||
CTChilds_ childs_;
|
||||
unsigned level_;
|
||||
};
|
||||
|
||||
ostream& operator<< (ostream &out, const CTNode&);
|
||||
|
||||
|
||||
typedef TinySet<CTNode*, CTNode::CompareSymbol> CTChilds;
|
||||
|
||||
|
||||
class ConstraintTree
|
||||
{
|
||||
public:
|
||||
ConstraintTree (unsigned);
|
||||
|
||||
ConstraintTree (const LogVars&);
|
||||
|
||||
ConstraintTree (const LogVars&, const Tuples&);
|
||||
|
||||
ConstraintTree (vector<vector<string>> names);
|
||||
|
||||
ConstraintTree (const ConstraintTree&);
|
||||
|
||||
ConstraintTree (const CTChilds& rootChilds, const LogVars& logVars)
|
||||
: root_(new CTNode (0, 0, rootChilds)),
|
||||
logVars_(logVars),
|
||||
logVarSet_(logVars) { }
|
||||
|
||||
~ConstraintTree (void);
|
||||
|
||||
CTNode* root (void) const { return root_; }
|
||||
|
||||
bool empty (void) const { return root_->childs().empty(); }
|
||||
|
||||
const LogVars& logVars (void) const
|
||||
{
|
||||
assert (LogVarSet (logVars_) == logVarSet_);
|
||||
return logVars_;
|
||||
}
|
||||
|
||||
const LogVarSet& logVarSet (void) const
|
||||
{
|
||||
assert (LogVarSet (logVars_) == logVarSet_);
|
||||
return logVarSet_;
|
||||
}
|
||||
|
||||
size_t nrLogVars (void) const
|
||||
{
|
||||
return logVars_.size();
|
||||
assert (LogVarSet (logVars_) == logVarSet_);
|
||||
}
|
||||
|
||||
void addTuple (const Tuple&);
|
||||
|
||||
bool containsTuple (const Tuple&);
|
||||
|
||||
void moveToTop (const LogVars&);
|
||||
|
||||
void moveToBottom (const LogVars&);
|
||||
|
||||
void join (ConstraintTree*, bool oneTwoOne = false);
|
||||
|
||||
unsigned getLevel (LogVar) const;
|
||||
|
||||
void rename (LogVar, LogVar);
|
||||
|
||||
void applySubstitution (const Substitution&);
|
||||
|
||||
void project (const LogVarSet&);
|
||||
|
||||
ConstraintTree projectedCopy (const LogVarSet&);
|
||||
|
||||
void remove (const LogVarSet&);
|
||||
|
||||
bool isSingleton (LogVar);
|
||||
|
||||
LogVarSet singletons (void);
|
||||
|
||||
TupleSet tupleSet (unsigned = 0) const;
|
||||
|
||||
TupleSet tupleSet (const LogVars&);
|
||||
|
||||
unsigned size (void) const;
|
||||
|
||||
unsigned nrSymbols (LogVar);
|
||||
|
||||
void exportToGraphViz (const char*, bool = false) const;
|
||||
|
||||
bool isCountNormalized (const LogVarSet&);
|
||||
|
||||
unsigned getConditionalCount (const LogVarSet&);
|
||||
|
||||
TinySet<unsigned> getConditionalCounts (const LogVarSet&);
|
||||
|
||||
bool isCartesianProduct (const LogVarSet&);
|
||||
|
||||
std::pair<ConstraintTree*, ConstraintTree*> split (const Tuple&);
|
||||
|
||||
std::pair<ConstraintTree*, ConstraintTree*> split (
|
||||
const LogVars&, ConstraintTree*, const LogVars&);
|
||||
|
||||
ConstraintTrees countNormalize (const LogVarSet&);
|
||||
|
||||
ConstraintTrees jointCountNormalize (
|
||||
ConstraintTree*, ConstraintTree*, LogVar, LogVar, LogVar);
|
||||
|
||||
LogVars expand (LogVar);
|
||||
|
||||
ConstraintTrees ground (LogVar);
|
||||
|
||||
void cloneLogVar (LogVar, LogVar);
|
||||
|
||||
ConstraintTree& operator= (const ConstraintTree& ct);
|
||||
|
||||
private:
|
||||
unsigned countTuples (const CTNode*) const;
|
||||
|
||||
CTNodes getNodesBelow (CTNode*) const;
|
||||
|
||||
CTNodes getNodesAtLevel (unsigned) const;
|
||||
|
||||
unsigned nrNodes (const CTNode* n) const;
|
||||
|
||||
void appendOnBottom (CTNode* n1, const CTChilds&);
|
||||
|
||||
void swapLogVar (LogVar);
|
||||
|
||||
bool join (CTNode*, const Tuple&, size_t, CTNode*);
|
||||
|
||||
void getTuples (CTNode*, Tuples, unsigned, Tuples&, CTNodes&) const;
|
||||
|
||||
vector<std::pair<CTNode*, unsigned>> countNormalize (
|
||||
const CTNode*, unsigned);
|
||||
|
||||
static void split (
|
||||
CTNode*, CTNode*, CTChilds&, CTChilds&, unsigned);
|
||||
|
||||
CTNode* root_;
|
||||
LogVars logVars_;
|
||||
LogVarSet logVarSet_;
|
||||
};
|
||||
|
||||
|
||||
#endif // HORUS_CONSTRAINTTREE_H
|
||||
|
@ -1,424 +0,0 @@
|
||||
#include "CountingBp.h"
|
||||
#include "WeightedBp.h"
|
||||
|
||||
|
||||
bool CountingBp::checkForIdenticalFactors = true;
|
||||
|
||||
|
||||
CountingBp::CountingBp (const FactorGraph& fg)
|
||||
: GroundSolver (fg), freeColor_(0)
|
||||
{
|
||||
findIdenticalFactors();
|
||||
setInitialColors();
|
||||
createGroups();
|
||||
compressedFg_ = getCompressedFactorGraph();
|
||||
solver_ = new WeightedBp (*compressedFg_, getWeights());
|
||||
}
|
||||
|
||||
|
||||
|
||||
CountingBp::~CountingBp (void)
|
||||
{
|
||||
delete solver_;
|
||||
delete compressedFg_;
|
||||
for (size_t i = 0; i < varClusters_.size(); i++) {
|
||||
delete varClusters_[i];
|
||||
}
|
||||
for (size_t i = 0; i < facClusters_.size(); i++) {
|
||||
delete facClusters_[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingBp::printSolverFlags (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "counting bp [" ;
|
||||
ss << "schedule=" ;
|
||||
typedef BpOptions::Schedule Sch;
|
||||
switch (BpOptions::schedule) {
|
||||
case Sch::SEQ_FIXED: ss << "seq_fixed"; break;
|
||||
case Sch::SEQ_RANDOM: ss << "seq_random"; break;
|
||||
case Sch::PARALLEL: ss << "parallel"; break;
|
||||
case Sch::MAX_RESIDUAL: ss << "max_residual"; break;
|
||||
}
|
||||
ss << ",max_iter=" << BpOptions::maxIter;
|
||||
ss << ",accuracy=" << BpOptions::accuracy;
|
||||
ss << ",log_domain=" << Util::toString (Globals::logDomain);
|
||||
ss << ",chkif=" <<
|
||||
Util::toString (CountingBp::checkForIdenticalFactors);
|
||||
ss << "]" ;
|
||||
cout << ss.str() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
CountingBp::solveQuery (VarIds queryVids)
|
||||
{
|
||||
assert (queryVids.empty() == false);
|
||||
Params res;
|
||||
if (queryVids.size() == 1) {
|
||||
res = solver_->getPosterioriOf (getRepresentative (queryVids[0]));
|
||||
} else {
|
||||
VarNode* vn = fg.getVarNode (queryVids[0]);
|
||||
const FacNodes& facNodes = vn->neighbors();
|
||||
size_t idx = facNodes.size();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
if (facNodes[i]->factor().contains (queryVids)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
if (idx == facNodes.size()) {
|
||||
res = GroundSolver::getJointByConditioning (
|
||||
GroundSolverType::CBP, fg, queryVids);
|
||||
} else {
|
||||
VarIds reprArgs;
|
||||
for (size_t i = 0; i < queryVids.size(); i++) {
|
||||
reprArgs.push_back (getRepresentative (queryVids[i]));
|
||||
}
|
||||
FacNode* reprFac = getRepresentative (facNodes[idx]);
|
||||
assert (reprFac != 0);
|
||||
res = solver_->getFactorJoint (reprFac, reprArgs);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingBp::findIdenticalFactors()
|
||||
{
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
if (checkForIdenticalFactors == false ||
|
||||
facNodes.size() == 1) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
facNodes[i]->factor().setDistId (Util::maxUnsigned());
|
||||
}
|
||||
unsigned groupCount = 1;
|
||||
for (size_t i = 0; i < facNodes.size() - 1; i++) {
|
||||
Factor& f1 = facNodes[i]->factor();
|
||||
if (f1.distId() != Util::maxUnsigned()) {
|
||||
continue;
|
||||
}
|
||||
f1.setDistId (groupCount);
|
||||
for (size_t j = i + 1; j < facNodes.size(); j++) {
|
||||
Factor& f2 = facNodes[j]->factor();
|
||||
if (f2.distId() != Util::maxUnsigned()) {
|
||||
continue;
|
||||
}
|
||||
if (f1.size() == f2.size() &&
|
||||
f1.ranges() == f2.ranges() &&
|
||||
f1.params() == f2.params()) {
|
||||
f2.setDistId (groupCount);
|
||||
}
|
||||
}
|
||||
groupCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingBp::setInitialColors (void)
|
||||
{
|
||||
varColors_.resize (fg.nrVarNodes());
|
||||
facColors_.resize (fg.nrFacNodes());
|
||||
// create the initial variable colors
|
||||
VarColorMap colorMap;
|
||||
const VarNodes& varNodes = fg.varNodes();
|
||||
for (size_t i = 0; i < varNodes.size(); i++) {
|
||||
unsigned range = varNodes[i]->range();
|
||||
VarColorMap::iterator it = colorMap.find (range);
|
||||
if (it == colorMap.end()) {
|
||||
it = colorMap.insert (make_pair (
|
||||
range, Colors (range + 1, -1))).first;
|
||||
}
|
||||
unsigned idx = varNodes[i]->hasEvidence()
|
||||
? varNodes[i]->getEvidence()
|
||||
: range;
|
||||
Colors& stateColors = it->second;
|
||||
if (stateColors[idx] == -1) {
|
||||
stateColors[idx] = getNewColor();
|
||||
}
|
||||
setColor (varNodes[i], stateColors[idx]);
|
||||
}
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
// create the initial factor colors
|
||||
DistColorMap distColors;
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
unsigned distId = facNodes[i]->factor().distId();
|
||||
DistColorMap::iterator it = distColors.find (distId);
|
||||
if (it == distColors.end()) {
|
||||
it = distColors.insert (make_pair (distId, getNewColor())).first;
|
||||
}
|
||||
setColor (facNodes[i], it->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingBp::createGroups (void)
|
||||
{
|
||||
VarSignMap varGroups;
|
||||
FacSignMap facGroups;
|
||||
unsigned nIters = 0;
|
||||
bool groupsHaveChanged = true;
|
||||
const VarNodes& varNodes = fg.varNodes();
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
|
||||
while (groupsHaveChanged || nIters == 1) {
|
||||
nIters ++;
|
||||
|
||||
// set a new color to the variables with the same signature
|
||||
size_t prevVarGroupsSize = varGroups.size();
|
||||
varGroups.clear();
|
||||
for (size_t i = 0; i < varNodes.size(); i++) {
|
||||
const VarSignature& signature = getSignature (varNodes[i]);
|
||||
VarSignMap::iterator it = varGroups.find (signature);
|
||||
if (it == varGroups.end()) {
|
||||
it = varGroups.insert (make_pair (signature, VarNodes())).first;
|
||||
}
|
||||
it->second.push_back (varNodes[i]);
|
||||
}
|
||||
for (VarSignMap::iterator it = varGroups.begin();
|
||||
it != varGroups.end(); ++it) {
|
||||
Color newColor = getNewColor();
|
||||
VarNodes& groupMembers = it->second;
|
||||
for (size_t i = 0; i < groupMembers.size(); i++) {
|
||||
setColor (groupMembers[i], newColor);
|
||||
}
|
||||
}
|
||||
|
||||
size_t prevFactorGroupsSize = facGroups.size();
|
||||
facGroups.clear();
|
||||
// set a new color to the factors with the same signature
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
const FacSignature& signature = getSignature (facNodes[i]);
|
||||
FacSignMap::iterator it = facGroups.find (signature);
|
||||
if (it == facGroups.end()) {
|
||||
it = facGroups.insert (make_pair (signature, FacNodes())).first;
|
||||
}
|
||||
it->second.push_back (facNodes[i]);
|
||||
}
|
||||
for (FacSignMap::iterator it = facGroups.begin();
|
||||
it != facGroups.end(); ++it) {
|
||||
Color newColor = getNewColor();
|
||||
FacNodes& groupMembers = it->second;
|
||||
for (size_t i = 0; i < groupMembers.size(); i++) {
|
||||
setColor (groupMembers[i], newColor);
|
||||
}
|
||||
}
|
||||
|
||||
groupsHaveChanged = prevVarGroupsSize != varGroups.size()
|
||||
|| prevFactorGroupsSize != facGroups.size();
|
||||
}
|
||||
// printGroups (varGroups, facGroups);
|
||||
createClusters (varGroups, facGroups);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingBp::createClusters (
|
||||
const VarSignMap& varGroups,
|
||||
const FacSignMap& facGroups)
|
||||
{
|
||||
varClusters_.reserve (varGroups.size());
|
||||
for (VarSignMap::const_iterator it = varGroups.begin();
|
||||
it != varGroups.end(); ++it) {
|
||||
const VarNodes& groupVars = it->second;
|
||||
VarCluster* vc = new VarCluster (groupVars);
|
||||
for (size_t i = 0; i < groupVars.size(); i++) {
|
||||
varClusterMap_.insert (make_pair (groupVars[i]->varId(), vc));
|
||||
}
|
||||
varClusters_.push_back (vc);
|
||||
}
|
||||
|
||||
facClusters_.reserve (facGroups.size());
|
||||
for (FacSignMap::const_iterator it = facGroups.begin();
|
||||
it != facGroups.end(); ++it) {
|
||||
FacNode* groupFactor = it->second[0];
|
||||
const VarNodes& neighs = groupFactor->neighbors();
|
||||
VarClusters varClusters;
|
||||
varClusters.reserve (neighs.size());
|
||||
for (size_t i = 0; i < neighs.size(); i++) {
|
||||
VarId vid = neighs[i]->varId();
|
||||
varClusters.push_back (varClusterMap_.find (vid)->second);
|
||||
}
|
||||
facClusters_.push_back (new FacCluster (it->second, varClusters));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
VarSignature
|
||||
CountingBp::getSignature (const VarNode* varNode)
|
||||
{
|
||||
const FacNodes& neighs = varNode->neighbors();
|
||||
VarSignature sign;
|
||||
sign.reserve (neighs.size() + 1);
|
||||
for (size_t i = 0; i < neighs.size(); i++) {
|
||||
sign.push_back (make_pair (
|
||||
getColor (neighs[i]),
|
||||
neighs[i]->factor().indexOf (varNode->varId())));
|
||||
}
|
||||
std::sort (sign.begin(), sign.end());
|
||||
sign.push_back (make_pair (getColor (varNode), 0));
|
||||
return sign;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FacSignature
|
||||
CountingBp::getSignature (const FacNode* facNode)
|
||||
{
|
||||
const VarNodes& neighs = facNode->neighbors();
|
||||
FacSignature sign;
|
||||
sign.reserve (neighs.size() + 1);
|
||||
for (size_t i = 0; i < neighs.size(); i++) {
|
||||
sign.push_back (getColor (neighs[i]));
|
||||
}
|
||||
sign.push_back (getColor (facNode));
|
||||
return sign;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VarId
|
||||
CountingBp::getRepresentative (VarId vid)
|
||||
{
|
||||
assert (Util::contains (varClusterMap_, vid));
|
||||
VarCluster* vc = varClusterMap_.find (vid)->second;
|
||||
return vc->representative()->varId();
|
||||
}
|
||||
|
||||
|
||||
|
||||
FacNode*
|
||||
CountingBp::getRepresentative (FacNode* fn)
|
||||
{
|
||||
for (size_t i = 0; i < facClusters_.size(); i++) {
|
||||
if (Util::contains (facClusters_[i]->members(), fn)) {
|
||||
return facClusters_[i]->representative();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FactorGraph*
|
||||
CountingBp::getCompressedFactorGraph (void)
|
||||
{
|
||||
FactorGraph* fg = new FactorGraph();
|
||||
for (size_t i = 0; i < varClusters_.size(); i++) {
|
||||
VarNode* newVar = new VarNode (varClusters_[i]->first());
|
||||
varClusters_[i]->setRepresentative (newVar);
|
||||
fg->addVarNode (newVar);
|
||||
}
|
||||
for (size_t i = 0; i < facClusters_.size(); i++) {
|
||||
Vars vars;
|
||||
const VarClusters& clusters = facClusters_[i]->varClusters();
|
||||
for (size_t j = 0; j < clusters.size(); j++) {
|
||||
vars.push_back (clusters[j]->representative());
|
||||
}
|
||||
const Factor& groundFac = facClusters_[i]->first()->factor();
|
||||
FacNode* fn = new FacNode (Factor (
|
||||
vars, groundFac.params(), groundFac.distId()));
|
||||
facClusters_[i]->setRepresentative (fn);
|
||||
fg->addFacNode (fn);
|
||||
for (size_t j = 0; j < vars.size(); j++) {
|
||||
fg->addEdge (static_cast<VarNode*> (vars[j]), fn);
|
||||
}
|
||||
}
|
||||
return fg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<vector<unsigned>>
|
||||
CountingBp::getWeights (void) const
|
||||
{
|
||||
vector<vector<unsigned>> weights;
|
||||
weights.reserve (facClusters_.size());
|
||||
for (size_t i = 0; i < facClusters_.size(); i++) {
|
||||
const VarClusters& neighs = facClusters_[i]->varClusters();
|
||||
weights.push_back ({ });
|
||||
weights.back().reserve (neighs.size());
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
weights.back().push_back (getWeight (
|
||||
facClusters_[i], neighs[j], j));
|
||||
}
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
CountingBp::getWeight (
|
||||
const FacCluster* fc,
|
||||
const VarCluster* vc,
|
||||
size_t index) const
|
||||
{
|
||||
unsigned weight = 0;
|
||||
VarId reprVid = vc->representative()->varId();
|
||||
VarNode* groundVar = fg.getVarNode (reprVid);
|
||||
const FacNodes& neighs = groundVar->neighbors();
|
||||
for (size_t i = 0; i < neighs.size(); i++) {
|
||||
FacNodes::const_iterator it;
|
||||
it = std::find (fc->members().begin(), fc->members().end(), neighs[i]);
|
||||
if (it != fc->members().end() &&
|
||||
(*it)->factor().indexOf (reprVid) == index) {
|
||||
weight ++;
|
||||
}
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingBp::printGroups (
|
||||
const VarSignMap& varGroups,
|
||||
const FacSignMap& facGroups) const
|
||||
{
|
||||
unsigned count = 1;
|
||||
cout << "variable groups:" << endl;
|
||||
for (VarSignMap::const_iterator it = varGroups.begin();
|
||||
it != varGroups.end(); ++it) {
|
||||
const VarNodes& groupMembers = it->second;
|
||||
if (groupMembers.size() > 0) {
|
||||
cout << count << ": " ;
|
||||
for (size_t i = 0; i < groupMembers.size(); i++) {
|
||||
cout << groupMembers[i]->label() << " " ;
|
||||
}
|
||||
count ++;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
count = 1;
|
||||
cout << endl << "factor groups:" << endl;
|
||||
for (FacSignMap::const_iterator it = facGroups.begin();
|
||||
it != facGroups.end(); ++it) {
|
||||
const FacNodes& groupMembers = it->second;
|
||||
if (groupMembers.size() > 0) {
|
||||
cout << ++count << ": " ;
|
||||
for (size_t i = 0; i < groupMembers.size(); i++) {
|
||||
cout << groupMembers[i]->getLabel() << " " ;
|
||||
}
|
||||
count ++;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,182 +0,0 @@
|
||||
#ifndef HORUS_COUNTINGBP_H
|
||||
#define HORUS_COUNTINGBP_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "GroundSolver.h"
|
||||
#include "FactorGraph.h"
|
||||
#include "Util.h"
|
||||
#include "Horus.h"
|
||||
|
||||
class VarCluster;
|
||||
class FacCluster;
|
||||
class WeightedBp;
|
||||
|
||||
typedef long Color;
|
||||
typedef vector<Color> Colors;
|
||||
typedef vector<std::pair<Color,unsigned>> VarSignature;
|
||||
typedef vector<Color> FacSignature;
|
||||
|
||||
typedef unordered_map<unsigned, Color> DistColorMap;
|
||||
typedef unordered_map<unsigned, Colors> VarColorMap;
|
||||
|
||||
typedef unordered_map<VarSignature, VarNodes> VarSignMap;
|
||||
typedef unordered_map<FacSignature, FacNodes> FacSignMap;
|
||||
|
||||
typedef unordered_map<VarId, VarCluster*> VarClusterMap;
|
||||
|
||||
typedef vector<VarCluster*> VarClusters;
|
||||
typedef vector<FacCluster*> FacClusters;
|
||||
|
||||
template <class T>
|
||||
inline size_t hash_combine (size_t seed, const T& v)
|
||||
{
|
||||
return seed ^ (hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
||||
}
|
||||
|
||||
|
||||
namespace std {
|
||||
template <typename T1, typename T2> struct hash<std::pair<T1,T2>>
|
||||
{
|
||||
size_t operator() (const std::pair<T1,T2>& p) const
|
||||
{
|
||||
return hash_combine (std::hash<T1>()(p.first), p.second);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct hash<std::vector<T>>
|
||||
{
|
||||
size_t operator() (const std::vector<T>& vec) const
|
||||
{
|
||||
size_t h = 0;
|
||||
typename vector<T>::const_iterator first = vec.begin();
|
||||
typename vector<T>::const_iterator last = vec.end();
|
||||
for (; first != last; ++first) {
|
||||
h = hash_combine (h, *first);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class VarCluster
|
||||
{
|
||||
public:
|
||||
VarCluster (const VarNodes& vs) : members_(vs) { }
|
||||
|
||||
const VarNode* first (void) const { return members_.front(); }
|
||||
|
||||
const VarNodes& members (void) const { return members_; }
|
||||
|
||||
VarNode* representative (void) const { return repr_; }
|
||||
|
||||
void setRepresentative (VarNode* vn) { repr_ = vn; }
|
||||
|
||||
private:
|
||||
VarNodes members_;
|
||||
VarNode* repr_;
|
||||
};
|
||||
|
||||
|
||||
class FacCluster
|
||||
{
|
||||
public:
|
||||
FacCluster (const FacNodes& fcs, const VarClusters& vcs)
|
||||
: members_(fcs), varClusters_(vcs) { }
|
||||
|
||||
const FacNode* first (void) const { return members_.front(); }
|
||||
|
||||
const FacNodes& members (void) const { return members_; }
|
||||
|
||||
FacNode* representative (void) const { return repr_; }
|
||||
|
||||
void setRepresentative (FacNode* fn) { repr_ = fn; }
|
||||
|
||||
VarClusters& varClusters (void) { return varClusters_; }
|
||||
|
||||
private:
|
||||
FacNodes members_;
|
||||
FacNode* repr_;
|
||||
VarClusters varClusters_;
|
||||
};
|
||||
|
||||
|
||||
class CountingBp : public GroundSolver
|
||||
{
|
||||
public:
|
||||
CountingBp (const FactorGraph& fg);
|
||||
|
||||
~CountingBp (void);
|
||||
|
||||
void printSolverFlags (void) const;
|
||||
|
||||
Params solveQuery (VarIds);
|
||||
|
||||
static bool checkForIdenticalFactors;
|
||||
|
||||
private:
|
||||
Color getNewColor (void)
|
||||
{
|
||||
++ freeColor_;
|
||||
return freeColor_ - 1;
|
||||
}
|
||||
|
||||
Color getColor (const VarNode* vn) const
|
||||
{
|
||||
return varColors_[vn->getIndex()];
|
||||
}
|
||||
|
||||
Color getColor (const FacNode* fn) const
|
||||
{
|
||||
return facColors_[fn->getIndex()];
|
||||
}
|
||||
|
||||
void setColor (const VarNode* vn, Color c)
|
||||
{
|
||||
varColors_[vn->getIndex()] = c;
|
||||
}
|
||||
|
||||
void setColor (const FacNode* fn, Color c)
|
||||
{
|
||||
facColors_[fn->getIndex()] = c;
|
||||
}
|
||||
|
||||
void findIdenticalFactors (void);
|
||||
|
||||
void setInitialColors (void);
|
||||
|
||||
void createGroups (void);
|
||||
|
||||
void createClusters (const VarSignMap&, const FacSignMap&);
|
||||
|
||||
VarSignature getSignature (const VarNode*);
|
||||
|
||||
FacSignature getSignature (const FacNode*);
|
||||
|
||||
void printGroups (const VarSignMap&, const FacSignMap&) const;
|
||||
|
||||
VarId getRepresentative (VarId vid);
|
||||
|
||||
FacNode* getRepresentative (FacNode*);
|
||||
|
||||
FactorGraph* getCompressedFactorGraph (void);
|
||||
|
||||
vector<vector<unsigned>> getWeights (void) const;
|
||||
|
||||
unsigned getWeight (const FacCluster*,
|
||||
const VarCluster*, size_t index) const;
|
||||
|
||||
|
||||
Color freeColor_;
|
||||
Colors varColors_;
|
||||
Colors facColors_;
|
||||
VarClusters varClusters_;
|
||||
FacClusters facClusters_;
|
||||
VarClusterMap varClusterMap_;
|
||||
const FactorGraph* compressedFg_;
|
||||
WeightedBp* solver_;
|
||||
};
|
||||
|
||||
#endif // HORUS_COUNTINGBP_H
|
||||
|
@ -1,243 +0,0 @@
|
||||
#include <limits>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "ElimGraph.h"
|
||||
|
||||
ElimHeuristic ElimGraph::elimHeuristic = MIN_NEIGHBORS;
|
||||
|
||||
|
||||
ElimGraph::ElimGraph (const vector<Factor*>& factors)
|
||||
{
|
||||
for (size_t i = 0; i < factors.size(); i++) {
|
||||
if (factors[i] == 0) { // if contained just one var with evidence
|
||||
continue;
|
||||
}
|
||||
const VarIds& vids = factors[i]->arguments();
|
||||
for (size_t j = 0; j < vids.size() - 1; j++) {
|
||||
EgNode* n1 = getEgNode (vids[j]);
|
||||
if (n1 == 0) {
|
||||
n1 = new EgNode (vids[j], factors[i]->range (j));
|
||||
addNode (n1);
|
||||
}
|
||||
for (size_t k = j + 1; k < vids.size(); k++) {
|
||||
EgNode* n2 = getEgNode (vids[k]);
|
||||
if (n2 == 0) {
|
||||
n2 = new EgNode (vids[k], factors[i]->range (k));
|
||||
addNode (n2);
|
||||
}
|
||||
if (neighbors (n1, n2) == false) {
|
||||
addEdge (n1, n2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vids.size() == 1) {
|
||||
if (getEgNode (vids[0]) == 0) {
|
||||
addNode (new EgNode (vids[0], factors[i]->range (0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ElimGraph::~ElimGraph (void)
|
||||
{
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
delete nodes_[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
VarIds
|
||||
ElimGraph::getEliminatingOrder (const VarIds& exclude)
|
||||
{
|
||||
VarIds elimOrder;
|
||||
unmarked_.reserve (nodes_.size());
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
if (Util::contains (exclude, nodes_[i]->varId()) == false) {
|
||||
unmarked_.insert (nodes_[i]);
|
||||
}
|
||||
}
|
||||
size_t nrVarsToEliminate = nodes_.size() - exclude.size();
|
||||
for (size_t i = 0; i < nrVarsToEliminate; i++) {
|
||||
EgNode* node = getLowestCostNode();
|
||||
unmarked_.remove (node);
|
||||
const EGNeighs& neighs = node->neighbors();
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
neighs[j]->removeNeighbor (node);
|
||||
}
|
||||
elimOrder.push_back (node->varId());
|
||||
connectAllNeighbors (node);
|
||||
}
|
||||
return elimOrder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ElimGraph::print (void) const
|
||||
{
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
cout << "node " << nodes_[i]->label() << " neighs:" ;
|
||||
EGNeighs neighs = nodes_[i]->neighbors();
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
cout << " " << neighs[j]->label();
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ElimGraph::exportToGraphViz (
|
||||
const char* fileName,
|
||||
bool showNeighborless,
|
||||
const VarIds& highlightVarIds) const
|
||||
{
|
||||
ofstream out (fileName);
|
||||
if (!out.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
return;
|
||||
}
|
||||
out << "strict graph {" << endl;
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
if (showNeighborless || nodes_[i]->neighbors().size() != 0) {
|
||||
out << '"' << nodes_[i]->label() << '"' << endl;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < highlightVarIds.size(); i++) {
|
||||
EgNode* node =getEgNode (highlightVarIds[i]);
|
||||
if (node) {
|
||||
out << '"' << node->label() << '"' ;
|
||||
out << " [shape=box3d]" << endl;
|
||||
} else {
|
||||
cerr << "Error: invalid variable id: " << highlightVarIds[i] << "." ;
|
||||
cerr << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
EGNeighs neighs = nodes_[i]->neighbors();
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
out << '"' << nodes_[i]->label() << '"' << " -- " ;
|
||||
out << '"' << neighs[j]->label() << '"' << endl;
|
||||
}
|
||||
}
|
||||
out << "}" << endl;
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
VarIds
|
||||
ElimGraph::getEliminationOrder (
|
||||
const Factors& factors,
|
||||
VarIds excludedVids)
|
||||
{
|
||||
if (elimHeuristic == ElimHeuristic::SEQUENTIAL) {
|
||||
VarIds allVids;
|
||||
Factors::const_iterator first = factors.begin();
|
||||
Factors::const_iterator end = factors.end();
|
||||
for (; first != end; ++first) {
|
||||
Util::addToVector (allVids, (*first)->arguments());
|
||||
}
|
||||
TinySet<VarId> elimOrder (allVids);
|
||||
elimOrder -= TinySet<VarId> (excludedVids);
|
||||
return elimOrder.elements();
|
||||
}
|
||||
ElimGraph graph (factors);
|
||||
return graph.getEliminatingOrder (excludedVids);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ElimGraph::addNode (EgNode* n)
|
||||
{
|
||||
nodes_.push_back (n);
|
||||
n->setIndex (nodes_.size() - 1);
|
||||
varMap_.insert (make_pair (n->varId(), n));
|
||||
}
|
||||
|
||||
|
||||
|
||||
EgNode*
|
||||
ElimGraph::getEgNode (VarId vid) const
|
||||
{
|
||||
unordered_map<VarId, EgNode*>::const_iterator it;
|
||||
it = varMap_.find (vid);
|
||||
return (it != varMap_.end()) ? it->second : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EgNode*
|
||||
ElimGraph::getLowestCostNode (void) const
|
||||
{
|
||||
EgNode* bestNode = 0;
|
||||
unsigned minCost = std::numeric_limits<unsigned>::max();
|
||||
EGNeighs::const_iterator it;
|
||||
switch (elimHeuristic) {
|
||||
case MIN_NEIGHBORS: {
|
||||
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
|
||||
unsigned cost = getNeighborsCost (*it);
|
||||
if (cost < minCost) {
|
||||
bestNode = *it;
|
||||
minCost = cost;
|
||||
}
|
||||
}}
|
||||
break;
|
||||
case MIN_WEIGHT: {
|
||||
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
|
||||
unsigned cost = getWeightCost (*it);
|
||||
if (cost < minCost) {
|
||||
bestNode = *it;
|
||||
minCost = cost;
|
||||
}
|
||||
}}
|
||||
break;
|
||||
case MIN_FILL: {
|
||||
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
|
||||
unsigned cost = getFillCost (*it);
|
||||
if (cost < minCost) {
|
||||
bestNode = *it;
|
||||
minCost = cost;
|
||||
}
|
||||
}}
|
||||
break;
|
||||
case WEIGHTED_MIN_FILL: {
|
||||
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
|
||||
unsigned cost = getWeightedFillCost (*it);
|
||||
if (cost < minCost) {
|
||||
bestNode = *it;
|
||||
minCost = cost;
|
||||
}
|
||||
}}
|
||||
break;
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
assert (bestNode);
|
||||
return bestNode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ElimGraph::connectAllNeighbors (const EgNode* n)
|
||||
{
|
||||
const EGNeighs& neighs = n->neighbors();
|
||||
if (neighs.size() > 0) {
|
||||
for (size_t i = 0; i < neighs.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < neighs.size(); j++) {
|
||||
if ( ! neighbors (neighs[i], neighs[j])) {
|
||||
addEdge (neighs[i], neighs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,139 +0,0 @@
|
||||
#ifndef HORUS_ELIMGRAPH_H
|
||||
#define HORUS_ELIMGRAPH_H
|
||||
|
||||
#include "unordered_map"
|
||||
|
||||
#include "FactorGraph.h"
|
||||
#include "TinySet.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum ElimHeuristic
|
||||
{
|
||||
SEQUENTIAL,
|
||||
MIN_NEIGHBORS,
|
||||
MIN_WEIGHT,
|
||||
MIN_FILL,
|
||||
WEIGHTED_MIN_FILL
|
||||
};
|
||||
|
||||
|
||||
class EgNode;
|
||||
|
||||
typedef TinySet<EgNode*> EGNeighs;
|
||||
|
||||
|
||||
class EgNode : public Var
|
||||
{
|
||||
public:
|
||||
EgNode (VarId vid, unsigned range) : Var (vid, range) { }
|
||||
|
||||
void addNeighbor (EgNode* n) { neighs_.insert (n); }
|
||||
|
||||
void removeNeighbor (EgNode* n) { neighs_.remove (n); }
|
||||
|
||||
bool isNeighbor (EgNode* n) const { return neighs_.contains (n); }
|
||||
|
||||
const EGNeighs& neighbors (void) const { return neighs_; }
|
||||
|
||||
private:
|
||||
EGNeighs neighs_;
|
||||
};
|
||||
|
||||
|
||||
class ElimGraph
|
||||
{
|
||||
public:
|
||||
ElimGraph (const Factors&);
|
||||
|
||||
~ElimGraph (void);
|
||||
|
||||
VarIds getEliminatingOrder (const VarIds&);
|
||||
|
||||
void print (void) const;
|
||||
|
||||
void exportToGraphViz (const char*, bool = true,
|
||||
const VarIds& = VarIds()) const;
|
||||
|
||||
static VarIds getEliminationOrder (const Factors&, VarIds);
|
||||
|
||||
static ElimHeuristic elimHeuristic;
|
||||
|
||||
private:
|
||||
|
||||
void addEdge (EgNode* n1, EgNode* n2)
|
||||
{
|
||||
assert (n1 != n2);
|
||||
n1->addNeighbor (n2);
|
||||
n2->addNeighbor (n1);
|
||||
}
|
||||
|
||||
unsigned getNeighborsCost (const EgNode* n) const
|
||||
{
|
||||
return n->neighbors().size();
|
||||
}
|
||||
|
||||
unsigned getWeightCost (const EgNode* n) const
|
||||
{
|
||||
unsigned cost = 1;
|
||||
const EGNeighs& neighs = n->neighbors();
|
||||
for (size_t i = 0; i < neighs.size(); i++) {
|
||||
cost *= neighs[i]->range();
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
unsigned getFillCost (const EgNode* n) const
|
||||
{
|
||||
unsigned cost = 0;
|
||||
const EGNeighs& neighs = n->neighbors();
|
||||
if (neighs.size() > 0) {
|
||||
for (size_t i = 0; i < neighs.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < neighs.size(); j++) {
|
||||
if ( ! neighbors (neighs[i], neighs[j])) {
|
||||
cost ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
unsigned getWeightedFillCost (const EgNode* n) const
|
||||
{
|
||||
unsigned cost = 0;
|
||||
const EGNeighs& neighs = n->neighbors();
|
||||
if (neighs.size() > 0) {
|
||||
for (size_t i = 0; i < neighs.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < neighs.size(); j++) {
|
||||
if ( ! neighbors (neighs[i], neighs[j])) {
|
||||
cost += neighs[i]->range() * neighs[j]->range();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
bool neighbors (EgNode* n1, EgNode* n2) const
|
||||
{
|
||||
return n1->isNeighbor (n2);
|
||||
}
|
||||
|
||||
void addNode (EgNode*);
|
||||
|
||||
EgNode* getEgNode (VarId) const;
|
||||
|
||||
EgNode* getLowestCostNode (void) const;
|
||||
|
||||
void connectAllNeighbors (const EgNode*);
|
||||
|
||||
vector<EgNode*> nodes_;
|
||||
TinySet<EgNode*> unmarked_;
|
||||
unordered_map<VarId, EgNode*> varMap_;
|
||||
};
|
||||
|
||||
#endif // HORUS_ELIMGRAPH_H
|
||||
|
@ -1,237 +0,0 @@
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "Factor.h"
|
||||
#include "Indexer.h"
|
||||
|
||||
|
||||
Factor::Factor (const Factor& g)
|
||||
{
|
||||
clone (g);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Factor::Factor (
|
||||
const VarIds& vids,
|
||||
const Ranges& ranges,
|
||||
const Params& params,
|
||||
unsigned distId)
|
||||
{
|
||||
args_ = vids;
|
||||
ranges_ = ranges;
|
||||
params_ = params;
|
||||
distId_ = distId;
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Factor::Factor (
|
||||
const Vars& vars,
|
||||
const Params& params,
|
||||
unsigned distId)
|
||||
{
|
||||
for (size_t i = 0; i < vars.size(); i++) {
|
||||
args_.push_back (vars[i]->varId());
|
||||
ranges_.push_back (vars[i]->range());
|
||||
}
|
||||
params_ = params;
|
||||
distId_ = distId;
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOut (VarId vid)
|
||||
{
|
||||
if (vid == args_.front() && ranges_.front() == 2) {
|
||||
// optimization
|
||||
sumOutFirstVariable();
|
||||
} else if (vid == args_.back() && ranges_.back() == 2) {
|
||||
// optimization
|
||||
sumOutLastVariable();
|
||||
} else {
|
||||
assert (indexOf (vid) != args_.size());
|
||||
sumOutIndex (indexOf (vid));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOutAllExcept (VarId vid)
|
||||
{
|
||||
assert (indexOf (vid) != args_.size());
|
||||
sumOutAllExceptIndex (indexOf (vid));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOutAllExcept (const VarIds& vids)
|
||||
{
|
||||
vector<bool> mask (args_.size(), false);
|
||||
for (unsigned i = 0; i < vids.size(); i++) {
|
||||
assert (indexOf (vids[i]) != args_.size());
|
||||
mask[indexOf (vids[i])] = true;
|
||||
}
|
||||
sumOutArgs (mask);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOutAllExceptIndex (size_t idx)
|
||||
{
|
||||
assert (idx < args_.size());
|
||||
vector<bool> mask (args_.size(), false);
|
||||
mask[idx] = true;
|
||||
sumOutArgs (mask);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Factor::multiply (Factor& g)
|
||||
{
|
||||
if (args_.size() == 0) {
|
||||
clone (g);
|
||||
return;
|
||||
}
|
||||
TFactor<VarId>::multiply (g);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
Factor::getLabel (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "f(" ;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (i != 0) ss << "," ;
|
||||
ss << Var (args_[i], ranges_[i]).label();
|
||||
}
|
||||
ss << ")" ;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::print (void) const
|
||||
{
|
||||
Vars vars;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
vars.push_back (new Var (args_[i], ranges_[i]));
|
||||
}
|
||||
vector<string> jointStrings = Util::getStateLines (vars);
|
||||
for (size_t i = 0; i < params_.size(); i++) {
|
||||
// cout << "[" << distId_ << "] " ;
|
||||
cout << "f(" << jointStrings[i] << ")" ;
|
||||
cout << " = " << params_[i] << endl;
|
||||
}
|
||||
cout << endl;
|
||||
for (size_t i = 0; i < vars.size(); i++) {
|
||||
delete vars[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOutFirstVariable (void)
|
||||
{
|
||||
size_t sep = params_.size() / 2;
|
||||
if (Globals::logDomain) {
|
||||
std::transform (
|
||||
params_.begin(), params_.begin() + sep,
|
||||
params_.begin() + sep, params_.begin(),
|
||||
Util::logSum);
|
||||
|
||||
} else {
|
||||
std::transform (
|
||||
params_.begin(), params_.begin() + sep,
|
||||
params_.begin() + sep, params_.begin(),
|
||||
std::plus<double>());
|
||||
}
|
||||
params_.resize (sep);
|
||||
args_.erase (args_.begin());
|
||||
ranges_.erase (ranges_.begin());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOutLastVariable (void)
|
||||
{
|
||||
Params::iterator first1 = params_.begin();
|
||||
Params::iterator first2 = params_.begin();
|
||||
Params::iterator last = params_.end();
|
||||
if (Globals::logDomain) {
|
||||
while (first2 != last) {
|
||||
// the arguments can be swaped, but that is ok
|
||||
*first1++ = Util::logSum (*first2++, *first2++);
|
||||
}
|
||||
} else {
|
||||
while (first2 != last) {
|
||||
*first1++ = (*first2++) + (*first2++);
|
||||
}
|
||||
}
|
||||
params_.resize (params_.size() / 2);
|
||||
args_.pop_back();
|
||||
ranges_.pop_back();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::sumOutArgs (const vector<bool>& mask)
|
||||
{
|
||||
assert (mask.size() == args_.size());
|
||||
size_t new_size = 1;
|
||||
Ranges oldRanges = ranges_;
|
||||
args_.clear();
|
||||
ranges_.clear();
|
||||
for (unsigned i = 0; i < mask.size(); i++) {
|
||||
if (mask[i]) {
|
||||
new_size *= ranges_[i];
|
||||
args_.push_back (args_[i]);
|
||||
ranges_.push_back (ranges_[i]);
|
||||
}
|
||||
}
|
||||
Params newps (new_size, LogAware::addIdenty());
|
||||
Params::const_iterator first = params_.begin();
|
||||
Params::const_iterator last = params_.end();
|
||||
MapIndexer indexer (oldRanges, mask);
|
||||
if (Globals::logDomain) {
|
||||
while (first != last) {
|
||||
newps[indexer] = Util::logSum (newps[indexer], *first++);
|
||||
++ indexer;
|
||||
}
|
||||
} else {
|
||||
while (first != last) {
|
||||
newps[indexer] += *first++;
|
||||
++ indexer;
|
||||
}
|
||||
}
|
||||
params_ = newps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Factor::clone (const Factor& g)
|
||||
{
|
||||
args_ = g.arguments();
|
||||
ranges_ = g.ranges();
|
||||
params_ = g.params();
|
||||
distId_ = g.distId();
|
||||
}
|
||||
|
@ -1,294 +0,0 @@
|
||||
#ifndef HORUS_FACTOR_H
|
||||
#define HORUS_FACTOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Var.h"
|
||||
#include "Indexer.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
template <typename T>
|
||||
class TFactor
|
||||
{
|
||||
public:
|
||||
const vector<T>& arguments (void) const { return args_; }
|
||||
|
||||
vector<T>& arguments (void) { return args_; }
|
||||
|
||||
const Ranges& ranges (void) const { return ranges_; }
|
||||
|
||||
const Params& params (void) const { return params_; }
|
||||
|
||||
Params& params (void) { return params_; }
|
||||
|
||||
size_t nrArguments (void) const { return args_.size(); }
|
||||
|
||||
size_t size (void) const { return params_.size(); }
|
||||
|
||||
unsigned distId (void) const { return distId_; }
|
||||
|
||||
void setDistId (unsigned id) { distId_ = id; }
|
||||
|
||||
void normalize (void) { LogAware::normalize (params_); }
|
||||
|
||||
void randomize (void)
|
||||
{
|
||||
for (size_t i = 0; i < params_.size(); ++i) {
|
||||
params_[i] = (double) std::rand() / RAND_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void setParams (const Params& newParams)
|
||||
{
|
||||
params_ = newParams;
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
size_t indexOf (const T& t) const
|
||||
{
|
||||
return Util::indexOf (args_, t);
|
||||
}
|
||||
|
||||
const T& argument (size_t idx) const
|
||||
{
|
||||
assert (idx < args_.size());
|
||||
return args_[idx];
|
||||
}
|
||||
|
||||
T& argument (size_t idx)
|
||||
{
|
||||
assert (idx < args_.size());
|
||||
return args_[idx];
|
||||
}
|
||||
|
||||
unsigned range (size_t idx) const
|
||||
{
|
||||
assert (idx < ranges_.size());
|
||||
return ranges_[idx];
|
||||
}
|
||||
|
||||
void multiply (TFactor<T>& g)
|
||||
{
|
||||
if (args_ == g.arguments()) {
|
||||
// optimization
|
||||
Globals::logDomain
|
||||
? params_ += g.params()
|
||||
: params_ *= g.params();
|
||||
return;
|
||||
}
|
||||
unsigned range_prod = 1;
|
||||
bool share_arguments = false;
|
||||
const vector<T>& g_args = g.arguments();
|
||||
const Ranges& g_ranges = g.ranges();
|
||||
const Params& g_params = g.params();
|
||||
for (size_t i = 0; i < g_args.size(); i++) {
|
||||
size_t idx = indexOf (g_args[i]);
|
||||
if (idx == args_.size()) {
|
||||
range_prod *= g_ranges[i];
|
||||
args_.push_back (g_args[i]);
|
||||
ranges_.push_back (g_ranges[i]);
|
||||
} else {
|
||||
share_arguments = true;
|
||||
}
|
||||
}
|
||||
if (share_arguments == false) {
|
||||
// optimization
|
||||
cartesianProduct (g_params.begin(), g_params.end());
|
||||
} else {
|
||||
extend (range_prod);
|
||||
Params::iterator it = params_.begin();
|
||||
MapIndexer indexer (args_, ranges_, g_args, g_ranges);
|
||||
if (Globals::logDomain) {
|
||||
for (; indexer.valid(); ++it, ++indexer) {
|
||||
*it += g_params[indexer];
|
||||
}
|
||||
} else {
|
||||
for (; indexer.valid(); ++it, ++indexer) {
|
||||
*it *= g_params[indexer];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sumOutIndex (size_t idx)
|
||||
{
|
||||
assert (idx < args_.size());
|
||||
assert (args_.size() > 1);
|
||||
size_t new_size = params_.size() / ranges_[idx];
|
||||
Params newps (new_size, LogAware::addIdenty());
|
||||
Params::const_iterator first = params_.begin();
|
||||
Params::const_iterator last = params_.end();
|
||||
MapIndexer indexer (ranges_, idx);
|
||||
if (Globals::logDomain) {
|
||||
for (; first != last; ++indexer) {
|
||||
newps[indexer] = Util::logSum (newps[indexer], *first++);
|
||||
}
|
||||
} else {
|
||||
for (; first != last; ++indexer) {
|
||||
newps[indexer] += *first++;
|
||||
}
|
||||
}
|
||||
params_ = newps;
|
||||
args_.erase (args_.begin() + idx);
|
||||
ranges_.erase (ranges_.begin() + idx);
|
||||
}
|
||||
|
||||
void absorveEvidence (const T& arg, unsigned obsIdx)
|
||||
{
|
||||
size_t idx = indexOf (arg);
|
||||
assert (idx != args_.size());
|
||||
assert (obsIdx < ranges_[idx]);
|
||||
Params newps;
|
||||
newps.reserve (params_.size() / ranges_[idx]);
|
||||
Indexer indexer (ranges_);
|
||||
for (unsigned i = 0; i < obsIdx; ++i) {
|
||||
indexer.incrementDimension (idx);
|
||||
}
|
||||
while (indexer.valid()) {
|
||||
newps.push_back (params_[indexer]);
|
||||
indexer.incrementExceptDimension (idx);
|
||||
}
|
||||
params_ = newps;
|
||||
args_.erase (args_.begin() + idx);
|
||||
ranges_.erase (ranges_.begin() + idx);
|
||||
}
|
||||
|
||||
void reorderArguments (const vector<T> new_args)
|
||||
{
|
||||
assert (new_args.size() == args_.size());
|
||||
if (new_args == args_) {
|
||||
return; // already on the desired order
|
||||
}
|
||||
Ranges new_ranges;
|
||||
for (size_t i = 0; i < new_args.size(); i++) {
|
||||
size_t idx = indexOf (new_args[i]);
|
||||
assert (idx != args_.size());
|
||||
new_ranges.push_back (ranges_[idx]);
|
||||
}
|
||||
Params newps;
|
||||
newps.reserve (params_.size());
|
||||
MapIndexer indexer (new_args, new_ranges, args_, ranges_);
|
||||
for (; indexer.valid(); ++indexer) {
|
||||
newps.push_back (params_[indexer]);
|
||||
}
|
||||
params_ = newps;
|
||||
args_ = new_args;
|
||||
ranges_ = new_ranges;
|
||||
}
|
||||
|
||||
bool contains (const T& arg) const
|
||||
{
|
||||
return Util::contains (args_, arg);
|
||||
}
|
||||
|
||||
bool contains (const vector<T>& args) const
|
||||
{
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
if (contains (args[i]) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double& operator[] (size_t idx)
|
||||
{
|
||||
assert (idx < params_.size());
|
||||
return params_[idx];
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
vector<T> args_;
|
||||
Ranges ranges_;
|
||||
Params params_;
|
||||
unsigned distId_;
|
||||
|
||||
private:
|
||||
void extend (unsigned range_prod)
|
||||
{
|
||||
Params backup = params_;
|
||||
params_.clear();
|
||||
params_.reserve (backup.size() * range_prod);
|
||||
Params::const_iterator first = backup.begin();
|
||||
Params::const_iterator last = backup.end();
|
||||
for (; first != last; ++first) {
|
||||
for (unsigned reps = 0; reps < range_prod; ++reps) {
|
||||
params_.push_back (*first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cartesianProduct (
|
||||
Params::const_iterator first2,
|
||||
Params::const_iterator last2)
|
||||
{
|
||||
Params backup = params_;
|
||||
params_.clear();
|
||||
params_.reserve (params_.size() * (last2 - first2));
|
||||
Params::const_iterator first1 = backup.begin();
|
||||
Params::const_iterator last1 = backup.end();
|
||||
Params::const_iterator tmp;
|
||||
if (Globals::logDomain) {
|
||||
for (; first1 != last1; ++first1) {
|
||||
for (tmp = first2; tmp != last2; ++tmp) {
|
||||
params_.push_back ((*first1) + (*tmp));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (; first1 != last1; ++first1) {
|
||||
for (tmp = first2; tmp != last2; ++tmp) {
|
||||
params_.push_back ((*first1) * (*tmp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Factor : public TFactor<VarId>
|
||||
{
|
||||
public:
|
||||
Factor (void) { }
|
||||
|
||||
Factor (const Factor&);
|
||||
|
||||
Factor (const VarIds&, const Ranges&, const Params&,
|
||||
unsigned = Util::maxUnsigned());
|
||||
|
||||
Factor (const Vars&, const Params&,
|
||||
unsigned = Util::maxUnsigned());
|
||||
|
||||
void sumOut (VarId);
|
||||
|
||||
void sumOutAllExcept (VarId);
|
||||
|
||||
void sumOutAllExcept (const VarIds&);
|
||||
|
||||
void sumOutAllExceptIndex (size_t idx);
|
||||
|
||||
void multiply (Factor&);
|
||||
|
||||
string getLabel (void) const;
|
||||
|
||||
void print (void) const;
|
||||
|
||||
private:
|
||||
void sumOutFirstVariable (void);
|
||||
|
||||
void sumOutLastVariable (void);
|
||||
|
||||
void sumOutArgs (const vector<bool>& mask);
|
||||
|
||||
void clone (const Factor& f);
|
||||
|
||||
};
|
||||
|
||||
#endif // HORUS_FACTOR_H
|
||||
|
@ -1,454 +0,0 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "FactorGraph.h"
|
||||
#include "Factor.h"
|
||||
#include "BayesBall.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
FactorGraph::FactorGraph (const FactorGraph& fg)
|
||||
{
|
||||
const VarNodes& varNodes = fg.varNodes();
|
||||
for (size_t i = 0; i < varNodes.size(); i++) {
|
||||
addVarNode (new VarNode (varNodes[i]));
|
||||
}
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
FacNode* facNode = new FacNode (facNodes[i]->factor());
|
||||
addFacNode (facNode);
|
||||
const VarNodes& neighs = facNodes[i]->neighbors();
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
addEdge (varNodes_[neighs[j]->getIndex()], facNode);
|
||||
}
|
||||
}
|
||||
bayesFactors_ = fg.bayesianFactors();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::readFromUaiFormat (const char* fileName)
|
||||
{
|
||||
std::ifstream is (fileName);
|
||||
if (!is.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
ignoreLines (is);
|
||||
string line;
|
||||
getline (is, line);
|
||||
if (line != "MARKOV") {
|
||||
cerr << "Error: the network must be a MARKOV network." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// read the number of vars
|
||||
ignoreLines (is);
|
||||
unsigned nrVars;
|
||||
is >> nrVars;
|
||||
// read the range of each var
|
||||
ignoreLines (is);
|
||||
Ranges ranges (nrVars);
|
||||
for (unsigned i = 0; i < nrVars; i++) {
|
||||
is >> ranges[i];
|
||||
}
|
||||
unsigned nrFactors;
|
||||
unsigned nrArgs;
|
||||
unsigned vid;
|
||||
is >> nrFactors;
|
||||
vector<VarIds> factorVarIds;
|
||||
vector<Ranges> factorRanges;
|
||||
for (unsigned i = 0; i < nrFactors; i++) {
|
||||
ignoreLines (is);
|
||||
is >> nrArgs;
|
||||
factorVarIds.push_back ({ });
|
||||
factorRanges.push_back ({ });
|
||||
for (unsigned j = 0; j < nrArgs; j++) {
|
||||
is >> vid;
|
||||
if (vid >= ranges.size()) {
|
||||
cerr << "Error: invalid variable identifier `" << vid << "'. " ;
|
||||
cerr << "Identifiers must be between 0 and " << ranges.size() - 1 ;
|
||||
cerr << "." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
factorVarIds.back().push_back (vid);
|
||||
factorRanges.back().push_back (ranges[vid]);
|
||||
}
|
||||
}
|
||||
// read the parameters
|
||||
unsigned nrParams;
|
||||
for (unsigned i = 0; i < nrFactors; i++) {
|
||||
ignoreLines (is);
|
||||
is >> nrParams;
|
||||
if (nrParams != Util::sizeExpected (factorRanges[i])) {
|
||||
cerr << "Error: invalid number of parameters for factor nº " << i ;
|
||||
cerr << ", " << Util::sizeExpected (factorRanges[i]);
|
||||
cerr << " expected, " << nrParams << " given." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
Params params (nrParams);
|
||||
for (unsigned j = 0; j < nrParams; j++) {
|
||||
is >> params[j];
|
||||
}
|
||||
if (Globals::logDomain) {
|
||||
Util::log (params);
|
||||
}
|
||||
addFactor (Factor (factorVarIds[i], factorRanges[i], params));
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::readFromLibDaiFormat (const char* fileName)
|
||||
{
|
||||
std::ifstream is (fileName);
|
||||
if (!is.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
ignoreLines (is);
|
||||
unsigned nrFactors;
|
||||
unsigned nrArgs;
|
||||
VarId vid;
|
||||
is >> nrFactors;
|
||||
for (unsigned i = 0; i < nrFactors; i++) {
|
||||
ignoreLines (is);
|
||||
// read the factor arguments
|
||||
is >> nrArgs;
|
||||
VarIds vids;
|
||||
for (unsigned j = 0; j < nrArgs; j++) {
|
||||
ignoreLines (is);
|
||||
is >> vid;
|
||||
vids.push_back (vid);
|
||||
}
|
||||
// read ranges
|
||||
Ranges ranges (nrArgs);
|
||||
for (unsigned j = 0; j < nrArgs; j++) {
|
||||
ignoreLines (is);
|
||||
is >> ranges[j];
|
||||
VarNode* var = getVarNode (vids[j]);
|
||||
if (var != 0 && ranges[j] != var->range()) {
|
||||
cerr << "Error: variable `" << vids[j] << "' appears in two or " ;
|
||||
cerr << "more factors with a different range." << endl;
|
||||
}
|
||||
}
|
||||
// read parameters
|
||||
ignoreLines (is);
|
||||
unsigned nNonzeros;
|
||||
is >> nNonzeros;
|
||||
Params params (Util::sizeExpected (ranges), 0);
|
||||
for (unsigned j = 0; j < nNonzeros; j++) {
|
||||
ignoreLines (is);
|
||||
unsigned index;
|
||||
is >> index;
|
||||
ignoreLines (is);
|
||||
double val;
|
||||
is >> val;
|
||||
params[index] = val;
|
||||
}
|
||||
if (Globals::logDomain) {
|
||||
Util::log (params);
|
||||
}
|
||||
std::reverse (vids.begin(), vids.end());
|
||||
Factor f (vids, ranges, params);
|
||||
std::reverse (vids.begin(), vids.end());
|
||||
f.reorderArguments (vids);
|
||||
addFactor (f);
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
FactorGraph::~FactorGraph (void)
|
||||
{
|
||||
for (size_t i = 0; i < varNodes_.size(); i++) {
|
||||
delete varNodes_[i];
|
||||
}
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
delete facNodes_[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::addFactor (const Factor& factor)
|
||||
{
|
||||
FacNode* fn = new FacNode (factor);
|
||||
addFacNode (fn);
|
||||
const VarIds& vids = fn->factor().arguments();
|
||||
for (size_t i = 0; i < vids.size(); i++) {
|
||||
VarMap::const_iterator it = varMap_.find (vids[i]);
|
||||
if (it != varMap_.end()) {
|
||||
addEdge (it->second, fn);
|
||||
} else {
|
||||
VarNode* vn = new VarNode (vids[i], fn->factor().range (i));
|
||||
addVarNode (vn);
|
||||
addEdge (vn, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::addVarNode (VarNode* vn)
|
||||
{
|
||||
varNodes_.push_back (vn);
|
||||
vn->setIndex (varNodes_.size() - 1);
|
||||
varMap_.insert (make_pair (vn->varId(), vn));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::addFacNode (FacNode* fn)
|
||||
{
|
||||
facNodes_.push_back (fn);
|
||||
fn->setIndex (facNodes_.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::addEdge (VarNode* vn, FacNode* fn)
|
||||
{
|
||||
vn->addNeighbor (fn);
|
||||
fn->addNeighbor (vn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
FactorGraph::isTree (void) const
|
||||
{
|
||||
return !containsCycle();
|
||||
}
|
||||
|
||||
|
||||
|
||||
BayesBallGraph&
|
||||
FactorGraph::getStructure (void)
|
||||
{
|
||||
assert (bayesFactors_);
|
||||
if (structure_.empty()) {
|
||||
for (size_t i = 0; i < varNodes_.size(); i++) {
|
||||
structure_.addNode (new BBNode (varNodes_[i]));
|
||||
}
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
const VarIds& vids = facNodes_[i]->factor().arguments();
|
||||
for (size_t j = 1; j < vids.size(); j++) {
|
||||
structure_.addEdge (vids[j], vids[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return structure_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::print (void) const
|
||||
{
|
||||
for (size_t i = 0; i < varNodes_.size(); i++) {
|
||||
cout << "var id = " << varNodes_[i]->varId() << endl;
|
||||
cout << "label = " << varNodes_[i]->label() << endl;
|
||||
cout << "range = " << varNodes_[i]->range() << endl;
|
||||
cout << "evidence = " << varNodes_[i]->getEvidence() << endl;
|
||||
cout << "factors = " ;
|
||||
for (size_t j = 0; j < varNodes_[i]->neighbors().size(); j++) {
|
||||
cout << varNodes_[i]->neighbors()[j]->getLabel() << " " ;
|
||||
}
|
||||
cout << endl << endl;
|
||||
}
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
facNodes_[i]->factor().print();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::exportToGraphViz (const char* fileName) const
|
||||
{
|
||||
ofstream out (fileName);
|
||||
if (!out.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
return;
|
||||
}
|
||||
out << "graph \"" << fileName << "\" {" << endl;
|
||||
for (size_t i = 0; i < varNodes_.size(); i++) {
|
||||
if (varNodes_[i]->hasEvidence()) {
|
||||
out << '"' << varNodes_[i]->label() << '"' ;
|
||||
out << " [style=filled, fillcolor=yellow]" << endl;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
out << '"' << facNodes_[i]->getLabel() << '"' ;
|
||||
out << " [label=\"" << facNodes_[i]->getLabel();
|
||||
out << "\"" << ", shape=box]" << endl;
|
||||
}
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
const VarNodes& myVars = facNodes_[i]->neighbors();
|
||||
for (size_t j = 0; j < myVars.size(); j++) {
|
||||
out << '"' << facNodes_[i]->getLabel() << '"' ;
|
||||
out << " -- " ;
|
||||
out << '"' << myVars[j]->label() << '"' << endl;
|
||||
}
|
||||
}
|
||||
out << "}" << endl;
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::exportToUaiFormat (const char* fileName) const
|
||||
{
|
||||
ofstream out (fileName);
|
||||
if (!out.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
return;
|
||||
}
|
||||
out << "MARKOV" << endl;
|
||||
out << varNodes_.size() << endl;
|
||||
VarNodes sortedVns = varNodes_;
|
||||
std::sort (sortedVns.begin(), sortedVns.end(), sortByVarId());
|
||||
for (size_t i = 0; i < sortedVns.size(); i++) {
|
||||
out << ((i != 0) ? " " : "") << sortedVns[i]->range();
|
||||
}
|
||||
out << endl << facNodes_.size() << endl;
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
VarIds args = facNodes_[i]->factor().arguments();
|
||||
out << args.size() << " " << Util::elementsToString (args) << endl;
|
||||
}
|
||||
out << endl;
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
Params params = facNodes_[i]->factor().params();
|
||||
if (Globals::logDomain) {
|
||||
Util::exp (params);
|
||||
}
|
||||
out << params.size() << endl << " " ;
|
||||
out << Util::elementsToString (params) << endl << endl;
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::exportToLibDaiFormat (const char* fileName) const
|
||||
{
|
||||
ofstream out (fileName);
|
||||
if (!out.is_open()) {
|
||||
cerr << "Error: couldn't open file '" << fileName << "'." ;
|
||||
return;
|
||||
}
|
||||
out << facNodes_.size() << endl << endl;
|
||||
for (size_t i = 0; i < facNodes_.size(); i++) {
|
||||
Factor f (facNodes_[i]->factor());
|
||||
out << f.nrArguments() << endl;
|
||||
out << Util::elementsToString (f.arguments()) << endl;
|
||||
out << Util::elementsToString (f.ranges()) << endl;
|
||||
VarIds args = f.arguments();
|
||||
std::reverse (args.begin(), args.end());
|
||||
f.reorderArguments (args);
|
||||
if (Globals::logDomain) {
|
||||
Util::exp (f.params());
|
||||
}
|
||||
out << f.size() << endl;
|
||||
for (size_t j = 0; j < f.size(); j++) {
|
||||
out << j << " " << f[j] << endl;
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
FactorGraph::ignoreLines (std::ifstream& is) const
|
||||
{
|
||||
string ignoreStr;
|
||||
while (is.peek() == '#' || is.peek() == '\n') {
|
||||
getline (is, ignoreStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
FactorGraph::containsCycle (void) const
|
||||
{
|
||||
vector<bool> visitedVars (varNodes_.size(), false);
|
||||
vector<bool> visitedFactors (facNodes_.size(), false);
|
||||
for (size_t i = 0; i < varNodes_.size(); i++) {
|
||||
int v = varNodes_[i]->getIndex();
|
||||
if (!visitedVars[v]) {
|
||||
if (containsCycle (varNodes_[i], 0, visitedVars, visitedFactors)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
FactorGraph::containsCycle (
|
||||
const VarNode* v,
|
||||
const FacNode* p,
|
||||
vector<bool>& visitedVars,
|
||||
vector<bool>& visitedFactors) const
|
||||
{
|
||||
visitedVars[v->getIndex()] = true;
|
||||
const FacNodes& adjacencies = v->neighbors();
|
||||
for (size_t i = 0; i < adjacencies.size(); i++) {
|
||||
int w = adjacencies[i]->getIndex();
|
||||
if (!visitedFactors[w]) {
|
||||
if (containsCycle (adjacencies[i], v, visitedVars, visitedFactors)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (visitedFactors[w] && adjacencies[i] != p) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // no cycle detected in this component
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
FactorGraph::containsCycle (
|
||||
const FacNode* v,
|
||||
const VarNode* p,
|
||||
vector<bool>& visitedVars,
|
||||
vector<bool>& visitedFactors) const
|
||||
{
|
||||
visitedFactors[v->getIndex()] = true;
|
||||
const VarNodes& adjacencies = v->neighbors();
|
||||
for (size_t i = 0; i < adjacencies.size(); i++) {
|
||||
int w = adjacencies[i]->getIndex();
|
||||
if (!visitedVars[w]) {
|
||||
if (containsCycle (adjacencies[i], v, visitedVars, visitedFactors)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (visitedVars[w] && adjacencies[i] != p) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // no cycle detected in this component
|
||||
}
|
||||
|
@ -1,150 +0,0 @@
|
||||
#ifndef HORUS_FACTORGRAPH_H
|
||||
#define HORUS_FACTORGRAPH_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Factor.h"
|
||||
#include "BayesBallGraph.h"
|
||||
#include "Horus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class FacNode;
|
||||
|
||||
class VarNode : public Var
|
||||
{
|
||||
public:
|
||||
VarNode (VarId varId, unsigned nrStates,
|
||||
int evidence = Constants::NO_EVIDENCE)
|
||||
: Var (varId, nrStates, evidence) { }
|
||||
|
||||
VarNode (const Var* v) : Var (v) { }
|
||||
|
||||
void addNeighbor (FacNode* fn) { neighs_.push_back (fn); }
|
||||
|
||||
const FacNodes& neighbors (void) const { return neighs_; }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (VarNode);
|
||||
|
||||
FacNodes neighs_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FacNode
|
||||
{
|
||||
public:
|
||||
FacNode (const Factor& f) : factor_(f), index_(-1) { }
|
||||
|
||||
const Factor& factor (void) const { return factor_; }
|
||||
|
||||
Factor& factor (void) { return factor_; }
|
||||
|
||||
void addNeighbor (VarNode* vn) { neighs_.push_back (vn); }
|
||||
|
||||
const VarNodes& neighbors (void) const { return neighs_; }
|
||||
|
||||
size_t getIndex (void) const { return index_; }
|
||||
|
||||
void setIndex (size_t index) { index_ = index; }
|
||||
|
||||
string getLabel (void) { return factor_.getLabel(); }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (FacNode);
|
||||
|
||||
VarNodes neighs_;
|
||||
Factor factor_;
|
||||
size_t index_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FactorGraph
|
||||
{
|
||||
public:
|
||||
FactorGraph (void) : bayesFactors_(false) { }
|
||||
|
||||
FactorGraph (const FactorGraph&);
|
||||
|
||||
~FactorGraph (void);
|
||||
|
||||
const VarNodes& varNodes (void) const { return varNodes_; }
|
||||
|
||||
const FacNodes& facNodes (void) const { return facNodes_; }
|
||||
|
||||
void setFactorsAsBayesian (void) { bayesFactors_ = true; }
|
||||
|
||||
bool bayesianFactors (void) const { return bayesFactors_; }
|
||||
|
||||
size_t nrVarNodes (void) const { return varNodes_.size(); }
|
||||
|
||||
size_t nrFacNodes (void) const { return facNodes_.size(); }
|
||||
|
||||
VarNode* getVarNode (VarId vid) const
|
||||
{
|
||||
VarMap::const_iterator it = varMap_.find (vid);
|
||||
return it != varMap_.end() ? it->second : 0;
|
||||
}
|
||||
|
||||
void readFromUaiFormat (const char*);
|
||||
|
||||
void readFromLibDaiFormat (const char*);
|
||||
|
||||
void addFactor (const Factor& factor);
|
||||
|
||||
void addVarNode (VarNode*);
|
||||
|
||||
void addFacNode (FacNode*);
|
||||
|
||||
void addEdge (VarNode*, FacNode*);
|
||||
|
||||
bool isTree (void) const;
|
||||
|
||||
BayesBallGraph& getStructure (void);
|
||||
|
||||
void print (void) const;
|
||||
|
||||
void exportToGraphViz (const char*) const;
|
||||
|
||||
void exportToUaiFormat (const char*) const;
|
||||
|
||||
void exportToLibDaiFormat (const char*) const;
|
||||
|
||||
private:
|
||||
// DISALLOW_COPY_AND_ASSIGN (FactorGraph);
|
||||
|
||||
void ignoreLines (std::ifstream&) const;
|
||||
|
||||
bool containsCycle (void) const;
|
||||
|
||||
bool containsCycle (const VarNode*, const FacNode*,
|
||||
vector<bool>&, vector<bool>&) const;
|
||||
|
||||
bool containsCycle (const FacNode*, const VarNode*,
|
||||
vector<bool>&, vector<bool>&) const;
|
||||
|
||||
VarNodes varNodes_;
|
||||
FacNodes facNodes_;
|
||||
|
||||
BayesBallGraph structure_;
|
||||
bool bayesFactors_;
|
||||
|
||||
typedef unordered_map<unsigned, VarNode*> VarMap;
|
||||
VarMap varMap_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct sortByVarId
|
||||
{
|
||||
bool operator()(VarNode* vn1, VarNode* vn2) {
|
||||
return vn1->varId() < vn2->varId();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // HORUS_FACTORGRAPH_H
|
||||
|
@ -1,107 +0,0 @@
|
||||
#include "GroundSolver.h"
|
||||
#include "Util.h"
|
||||
#include "BeliefProp.h"
|
||||
#include "CountingBp.h"
|
||||
#include "VarElim.h"
|
||||
|
||||
|
||||
void
|
||||
GroundSolver::printAnswer (const VarIds& vids)
|
||||
{
|
||||
Vars unobservedVars;
|
||||
VarIds unobservedVids;
|
||||
for (size_t i = 0; i < vids.size(); i++) {
|
||||
VarNode* vn = fg.getVarNode (vids[i]);
|
||||
if (vn->hasEvidence() == false) {
|
||||
unobservedVars.push_back (vn);
|
||||
unobservedVids.push_back (vids[i]);
|
||||
}
|
||||
}
|
||||
if (unobservedVids.empty() == false) {
|
||||
Params res = solveQuery (unobservedVids);
|
||||
vector<string> stateLines = Util::getStateLines (unobservedVars);
|
||||
for (size_t i = 0; i < res.size(); i++) {
|
||||
cout << "P(" << stateLines[i] << ") = " ;
|
||||
cout << std::setprecision (Constants::PRECISION) << res[i];
|
||||
cout << endl;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
GroundSolver::printAllPosterioris (void)
|
||||
{
|
||||
VarNodes vars = fg.varNodes();
|
||||
std::sort (vars.begin(), vars.end(), sortByVarId());
|
||||
for (size_t i = 0; i < vars.size(); i++) {
|
||||
printAnswer ({vars[i]->varId()});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
GroundSolver::getJointByConditioning (
|
||||
GroundSolverType solverType,
|
||||
FactorGraph fg,
|
||||
const VarIds& jointVarIds) const
|
||||
{
|
||||
VarNodes jointVars;
|
||||
for (size_t i = 0; i < jointVarIds.size(); i++) {
|
||||
assert (fg.getVarNode (jointVarIds[i]));
|
||||
jointVars.push_back (fg.getVarNode (jointVarIds[i]));
|
||||
}
|
||||
|
||||
GroundSolver* solver = 0;
|
||||
switch (solverType) {
|
||||
case GroundSolverType::BP: solver = new BeliefProp (fg); break;
|
||||
case GroundSolverType::CBP: solver = new CountingBp (fg); break;
|
||||
case GroundSolverType::VE: solver = new VarElim (fg); break;
|
||||
}
|
||||
Params prevBeliefs = solver->solveQuery ({jointVarIds[0]});
|
||||
VarIds observedVids = {jointVars[0]->varId()};
|
||||
|
||||
for (size_t i = 1; i < jointVarIds.size(); i++) {
|
||||
assert (jointVars[i]->hasEvidence() == false);
|
||||
Params newBeliefs;
|
||||
Vars observedVars;
|
||||
Ranges observedRanges;
|
||||
for (size_t j = 0; j < observedVids.size(); j++) {
|
||||
observedVars.push_back (fg.getVarNode (observedVids[j]));
|
||||
observedRanges.push_back (observedVars.back()->range());
|
||||
}
|
||||
Indexer indexer (observedRanges, false);
|
||||
while (indexer.valid()) {
|
||||
for (size_t j = 0; j < observedVars.size(); j++) {
|
||||
observedVars[j]->setEvidence (indexer[j]);
|
||||
}
|
||||
delete solver;
|
||||
switch (solverType) {
|
||||
case GroundSolverType::BP: solver = new BeliefProp (fg); break;
|
||||
case GroundSolverType::CBP: solver = new CountingBp (fg); break;
|
||||
case GroundSolverType::VE: solver = new VarElim (fg); break;
|
||||
}
|
||||
Params beliefs = solver->solveQuery ({jointVarIds[i]});
|
||||
for (size_t k = 0; k < beliefs.size(); k++) {
|
||||
newBeliefs.push_back (beliefs[k]);
|
||||
}
|
||||
++ indexer;
|
||||
}
|
||||
|
||||
int count = -1;
|
||||
for (size_t j = 0; j < newBeliefs.size(); j++) {
|
||||
if (j % jointVars[i]->range() == 0) {
|
||||
count ++;
|
||||
}
|
||||
newBeliefs[j] *= prevBeliefs[count];
|
||||
}
|
||||
prevBeliefs = newBeliefs;
|
||||
observedVids.push_back (jointVars[i]->varId());
|
||||
}
|
||||
delete solver;
|
||||
return prevBeliefs;
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
#ifndef HORUS_GROUNDSOLVER_H
|
||||
#define HORUS_GROUNDSOLVER_H
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include "FactorGraph.h"
|
||||
#include "Var.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
class GroundSolver
|
||||
{
|
||||
public:
|
||||
GroundSolver (const FactorGraph& factorGraph) : fg(factorGraph) { }
|
||||
|
||||
virtual ~GroundSolver() { } // ensure that subclass destructor is called
|
||||
|
||||
virtual Params solveQuery (VarIds queryVids) = 0;
|
||||
|
||||
virtual void printSolverFlags (void) const = 0;
|
||||
|
||||
void printAnswer (const VarIds& vids);
|
||||
|
||||
void printAllPosterioris (void);
|
||||
|
||||
Params getJointByConditioning (GroundSolverType,
|
||||
FactorGraph, const VarIds& jointVarIds) const;
|
||||
|
||||
protected:
|
||||
const FactorGraph& fg;
|
||||
};
|
||||
|
||||
#endif // HORUS_GROUNDSOLVER_H
|
||||
|
@ -1,146 +0,0 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include "Histogram.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
HistogramSet::HistogramSet (unsigned size, unsigned range)
|
||||
{
|
||||
size_ = size;
|
||||
hist_.resize (range, 0);
|
||||
hist_[0] = size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
HistogramSet::nextHistogram (void)
|
||||
{
|
||||
for (size_t i = hist_.size() - 1; i-- > 0; ) {
|
||||
if (hist_[i] > 0) {
|
||||
hist_[i] --;
|
||||
hist_[i + 1] = maxCount (i + 1);
|
||||
clearAfter (i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (std::accumulate (hist_.begin(), hist_.end(), 0)
|
||||
== (int) size_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
HistogramSet::operator[] (size_t idx) const
|
||||
{
|
||||
assert (idx < hist_.size());
|
||||
return hist_[idx];
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
HistogramSet::nrHistograms (void) const
|
||||
{
|
||||
return HistogramSet::nrHistograms (size_, hist_.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
HistogramSet::reset (void)
|
||||
{
|
||||
std::fill (hist_.begin() + 1, hist_.end(), 0);
|
||||
hist_[0] = size_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<Histogram>
|
||||
HistogramSet::getHistograms (unsigned N, unsigned R)
|
||||
{
|
||||
HistogramSet hs (N, R);
|
||||
unsigned H = hs.nrHistograms();
|
||||
vector<Histogram> histograms;
|
||||
histograms.reserve (H);
|
||||
for (unsigned i = 0; i < H; i++) {
|
||||
histograms.push_back (hs.hist_);
|
||||
hs.nextHistogram();
|
||||
}
|
||||
return histograms;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
HistogramSet::nrHistograms (unsigned N, unsigned R)
|
||||
{
|
||||
return Util::nrCombinations (N + R - 1, R - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t
|
||||
HistogramSet::findIndex (
|
||||
const Histogram& h,
|
||||
const vector<Histogram>& hists)
|
||||
{
|
||||
vector<Histogram>::const_iterator it = std::lower_bound (
|
||||
hists.begin(), hists.end(), h, std::greater<Histogram>());
|
||||
assert (it != hists.end() && *it == h);
|
||||
return std::distance (hists.begin(), it);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<double>
|
||||
HistogramSet::getNumAssigns (unsigned N, unsigned R)
|
||||
{
|
||||
HistogramSet hs (N, R);
|
||||
double N_fac = Util::logFactorial (N);
|
||||
unsigned H = hs.nrHistograms();
|
||||
vector<double> numAssigns;
|
||||
numAssigns.reserve (H);
|
||||
for (unsigned h = 0; h < H; h++) {
|
||||
double prod = 0.0;
|
||||
for (unsigned r = 0; r < R; r++) {
|
||||
prod += Util::logFactorial (hs[r]);
|
||||
}
|
||||
double res = N_fac - prod;
|
||||
numAssigns.push_back (Globals::logDomain ? res : std::exp (res));
|
||||
hs.nextHistogram();
|
||||
}
|
||||
return numAssigns;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const HistogramSet& hs)
|
||||
{
|
||||
os << "#" << hs.hist_;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
HistogramSet::maxCount (size_t idx) const
|
||||
{
|
||||
unsigned sum = 0;
|
||||
for (size_t i = 0; i < idx; i++) {
|
||||
sum += hist_[i];
|
||||
}
|
||||
return size_ - sum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
HistogramSet::clearAfter (size_t idx)
|
||||
{
|
||||
std::fill (hist_.begin() + idx + 1, hist_.end(), 0);
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
#ifndef HORUS_HISTOGRAM_H
|
||||
#define HORUS_HISTOGRAM_H
|
||||
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned> Histogram;
|
||||
|
||||
class HistogramSet
|
||||
{
|
||||
public:
|
||||
HistogramSet (unsigned, unsigned);
|
||||
|
||||
void nextHistogram (void);
|
||||
|
||||
unsigned operator[] (size_t idx) const;
|
||||
|
||||
unsigned nrHistograms (void) const;
|
||||
|
||||
void reset (void);
|
||||
|
||||
static vector<Histogram> getHistograms (unsigned ,unsigned);
|
||||
|
||||
static unsigned nrHistograms (unsigned, unsigned);
|
||||
|
||||
static size_t findIndex (
|
||||
const Histogram&, const vector<Histogram>&);
|
||||
|
||||
static vector<double> getNumAssigns (unsigned, unsigned);
|
||||
|
||||
friend std::ostream& operator<< (ostream &os, const HistogramSet& hs);
|
||||
|
||||
private:
|
||||
unsigned maxCount (size_t) const;
|
||||
|
||||
void clearAfter (size_t);
|
||||
|
||||
unsigned size_;
|
||||
Histogram hist_;
|
||||
};
|
||||
|
||||
#endif // HORUS_HISTOGRAM_H
|
||||
|
@ -1,87 +0,0 @@
|
||||
#ifndef HORUS_HORUS_H
|
||||
#define HORUS_HORUS_H
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Var;
|
||||
class Factor;
|
||||
class VarNode;
|
||||
class FacNode;
|
||||
|
||||
typedef vector<double> Params;
|
||||
typedef unsigned VarId;
|
||||
typedef vector<VarId> VarIds;
|
||||
typedef vector<Var*> Vars;
|
||||
typedef vector<VarNode*> VarNodes;
|
||||
typedef vector<FacNode*> FacNodes;
|
||||
typedef vector<Factor*> Factors;
|
||||
typedef vector<string> States;
|
||||
typedef vector<unsigned> Ranges;
|
||||
typedef unsigned long long ullong;
|
||||
|
||||
|
||||
enum LiftedSolverType
|
||||
{
|
||||
LVE, // generalized counting first-order variable elimination (GC-FOVE)
|
||||
LBP, // lifted first-order belief propagation
|
||||
LKC // lifted first-order knowledge compilation
|
||||
};
|
||||
|
||||
|
||||
enum GroundSolverType
|
||||
{
|
||||
VE, // variable elimination
|
||||
BP, // belief propagation
|
||||
CBP // counting belief propagation
|
||||
};
|
||||
|
||||
|
||||
namespace Globals {
|
||||
|
||||
extern bool logDomain;
|
||||
|
||||
// level of debug information
|
||||
extern unsigned verbosity;
|
||||
|
||||
extern LiftedSolverType liftedSolver;
|
||||
extern GroundSolverType groundSolver;
|
||||
|
||||
};
|
||||
|
||||
|
||||
namespace Constants {
|
||||
|
||||
// show message calculation for belief propagation
|
||||
const bool SHOW_BP_CALCS = false;
|
||||
|
||||
const int NO_EVIDENCE = -1;
|
||||
|
||||
// number of digits to show when printing a parameter
|
||||
const unsigned PRECISION = 6;
|
||||
|
||||
};
|
||||
|
||||
|
||||
namespace BpOptions
|
||||
{
|
||||
enum Schedule {
|
||||
SEQ_FIXED,
|
||||
SEQ_RANDOM,
|
||||
PARALLEL,
|
||||
MAX_RESIDUAL
|
||||
};
|
||||
extern Schedule schedule;
|
||||
extern double accuracy;
|
||||
extern unsigned maxIter;
|
||||
}
|
||||
|
||||
#endif // HORUS_HORUS_H
|
||||
|
@ -1,187 +0,0 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "FactorGraph.h"
|
||||
#include "VarElim.h"
|
||||
#include "BeliefProp.h"
|
||||
#include "CountingBp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int readHorusFlags (int, const char* []);
|
||||
void readFactorGraph (FactorGraph&, const char*);
|
||||
VarIds readQueryAndEvidence (FactorGraph&, int, const char* [], int);
|
||||
|
||||
void runSolver (const FactorGraph&, const VarIds&);
|
||||
|
||||
const string USAGE = "usage: ./hcli [HORUS_FLAG=VALUE] \
|
||||
MODEL_FILE [VARIABLE | OBSERVED_VARIABLE=EVIDENCE] ..." ;
|
||||
|
||||
|
||||
int
|
||||
main (int argc, const char* argv[])
|
||||
{
|
||||
if (argc <= 1) {
|
||||
cerr << "Error: no probabilistic graphical model was given." << endl;
|
||||
cerr << USAGE << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
int idx = readHorusFlags (argc, argv);
|
||||
FactorGraph fg;
|
||||
readFactorGraph (fg, argv[idx]);
|
||||
VarIds queryIds = readQueryAndEvidence (fg, argc, argv, idx + 1);
|
||||
runSolver (fg, queryIds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
readHorusFlags (int argc, const char* argv[])
|
||||
{
|
||||
int i = 1;
|
||||
for (; i < argc; i++) {
|
||||
const string& arg = argv[i];
|
||||
size_t pos = arg.find ('=');
|
||||
if (pos == std::string::npos) {
|
||||
return i;
|
||||
}
|
||||
string leftArg = arg.substr (0, pos);
|
||||
string rightArg = arg.substr (pos + 1);
|
||||
if (leftArg.empty()) {
|
||||
cerr << "Error: missing left argument." << endl;
|
||||
cerr << USAGE << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (rightArg.empty()) {
|
||||
cerr << "Error: missing right argument." << endl;
|
||||
cerr << USAGE << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
Util::setHorusFlag (leftArg, rightArg);
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
readFactorGraph (FactorGraph& fg, const char* s)
|
||||
{
|
||||
string fileName (s);
|
||||
string extension = fileName.substr (fileName.find_last_of ('.') + 1);
|
||||
if (extension == "uai") {
|
||||
fg.readFromUaiFormat (fileName.c_str());
|
||||
} else if (extension == "fg") {
|
||||
fg.readFromLibDaiFormat (fileName.c_str());
|
||||
} else {
|
||||
cerr << "Error: the probabilistic graphical model must be " ;
|
||||
cerr << "defined either in a UAI or libDAI file." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
VarIds
|
||||
readQueryAndEvidence (
|
||||
FactorGraph& fg,
|
||||
int argc,
|
||||
const char* argv[],
|
||||
int start)
|
||||
{
|
||||
VarIds queryIds;
|
||||
for (int i = start; i < argc; i++) {
|
||||
const string& arg = argv[i];
|
||||
if (arg.find ('=') == std::string::npos) {
|
||||
if (Util::isInteger (arg) == false) {
|
||||
cerr << "Error: `" << arg << "' " ;
|
||||
cerr << "is not a variable id." ;
|
||||
cerr << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
VarId vid = Util::stringToUnsigned (arg);
|
||||
VarNode* queryVar = fg.getVarNode (vid);
|
||||
if (queryVar == false) {
|
||||
cerr << "Error: unknow variable with id " ;
|
||||
cerr << "`" << vid << "'." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
queryIds.push_back (vid);
|
||||
} else {
|
||||
size_t pos = arg.find ('=');
|
||||
string leftArg = arg.substr (0, pos);
|
||||
string rightArg = arg.substr (pos + 1);
|
||||
if (leftArg.empty()) {
|
||||
cerr << "Error: missing left argument." << endl;
|
||||
cerr << USAGE << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (Util::isInteger (leftArg) == false) {
|
||||
cerr << "Error: `" << leftArg << "' " ;
|
||||
cerr << "is not a variable id." << endl ;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
VarId vid = Util::stringToUnsigned (leftArg);
|
||||
VarNode* observedVar = fg.getVarNode (vid);
|
||||
if (observedVar == false) {
|
||||
cerr << "Error: unknow variable with id " ;
|
||||
cerr << "`" << vid << "'." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (rightArg.empty()) {
|
||||
cerr << "Error: missing right argument." << endl;
|
||||
cerr << USAGE << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (Util::isInteger (rightArg) == false) {
|
||||
cerr << "Error: `" << rightArg << "' " ;
|
||||
cerr << "is not a state index." << endl ;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
unsigned stateIdx = Util::stringToUnsigned (rightArg);
|
||||
if (observedVar->isValidState (stateIdx) == false) {
|
||||
cerr << "Error: `" << stateIdx << "' " ;
|
||||
cerr << "is not a valid state index for variable with id " ;
|
||||
cerr << "`" << vid << "'." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
observedVar->setEvidence (stateIdx);
|
||||
}
|
||||
}
|
||||
return queryIds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
runSolver (const FactorGraph& fg, const VarIds& queryIds)
|
||||
{
|
||||
GroundSolver* solver = 0;
|
||||
switch (Globals::groundSolver) {
|
||||
case GroundSolverType::VE:
|
||||
solver = new VarElim (fg);
|
||||
break;
|
||||
case GroundSolverType::BP:
|
||||
solver = new BeliefProp (fg);
|
||||
break;
|
||||
case GroundSolverType::CBP:
|
||||
solver = new CountingBp (fg);
|
||||
break;
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
if (Globals::verbosity > 0) {
|
||||
solver->printSolverFlags();
|
||||
cout << endl;
|
||||
}
|
||||
if (queryIds.empty()) {
|
||||
solver->printAllPosterioris();
|
||||
} else {
|
||||
solver->printAnswer (queryIds);
|
||||
}
|
||||
delete solver;
|
||||
}
|
||||
|
@ -1,570 +0,0 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <YapInterface.h>
|
||||
|
||||
#include "ParfactorList.h"
|
||||
#include "FactorGraph.h"
|
||||
#include "LiftedOperations.h"
|
||||
#include "LiftedVe.h"
|
||||
#include "VarElim.h"
|
||||
#include "LiftedBp.h"
|
||||
#include "CountingBp.h"
|
||||
#include "BeliefProp.h"
|
||||
#include "LiftedKc.h"
|
||||
#include "ElimGraph.h"
|
||||
#include "BayesBall.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef std::pair<ParfactorList*, ObservedFormulas*> LiftedNetwork;
|
||||
|
||||
Parfactor* readParfactor (YAP_Term);
|
||||
|
||||
void readLiftedEvidence (YAP_Term, ObservedFormulas&);
|
||||
|
||||
vector<unsigned> readUnsignedList (YAP_Term list);
|
||||
|
||||
Params readParameters (YAP_Term);
|
||||
|
||||
YAP_Term fillAnswersPrologList (vector<Params>& results);
|
||||
|
||||
|
||||
|
||||
int
|
||||
createLiftedNetwork (void)
|
||||
{
|
||||
Parfactors parfactors;
|
||||
YAP_Term parfactorList = YAP_ARG1;
|
||||
while (parfactorList != YAP_TermNil()) {
|
||||
YAP_Term pfTerm = YAP_HeadOfTerm (parfactorList);
|
||||
parfactors.push_back (readParfactor (pfTerm));
|
||||
parfactorList = YAP_TailOfTerm (parfactorList);
|
||||
}
|
||||
|
||||
// LiftedUtils::printSymbolDictionary();
|
||||
if (Globals::verbosity > 2) {
|
||||
Util::printHeader ("INITIAL PARFACTORS");
|
||||
for (size_t i = 0; i < parfactors.size(); i++) {
|
||||
parfactors[i]->print();
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
ParfactorList* pfList = new ParfactorList (parfactors);
|
||||
|
||||
if (Globals::verbosity > 2) {
|
||||
Util::printHeader ("SHATTERED PARFACTORS");
|
||||
pfList->print();
|
||||
}
|
||||
|
||||
// read evidence
|
||||
ObservedFormulas* obsFormulas = new ObservedFormulas();
|
||||
readLiftedEvidence (YAP_ARG2, *(obsFormulas));
|
||||
|
||||
LiftedNetwork* net = new LiftedNetwork (pfList, obsFormulas);
|
||||
|
||||
YAP_Int p = (YAP_Int) (net);
|
||||
return YAP_Unify (YAP_MkIntTerm (p), YAP_ARG3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
createGroundNetwork (void)
|
||||
{
|
||||
string factorsType ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG1)));
|
||||
FactorGraph* fg = new FactorGraph();
|
||||
if (factorsType == "bayes") {
|
||||
fg->setFactorsAsBayesian();
|
||||
}
|
||||
YAP_Term factorList = YAP_ARG2;
|
||||
while (factorList != YAP_TermNil()) {
|
||||
YAP_Term factor = YAP_HeadOfTerm (factorList);
|
||||
// read the var ids
|
||||
VarIds varIds = readUnsignedList (YAP_ArgOfTerm (1, factor));
|
||||
// read the ranges
|
||||
Ranges ranges = readUnsignedList (YAP_ArgOfTerm (2, factor));
|
||||
// read the parameters
|
||||
Params params = readParameters (YAP_ArgOfTerm (3, factor));
|
||||
// read dist id
|
||||
unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (4, factor));
|
||||
fg->addFactor (Factor (varIds, ranges, params, distId));
|
||||
factorList = YAP_TailOfTerm (factorList);
|
||||
}
|
||||
unsigned nrObservedVars = 0;
|
||||
YAP_Term evidenceList = YAP_ARG3;
|
||||
while (evidenceList != YAP_TermNil()) {
|
||||
YAP_Term evTerm = YAP_HeadOfTerm (evidenceList);
|
||||
unsigned vid = (unsigned) YAP_IntOfTerm ((YAP_ArgOfTerm (1, evTerm)));
|
||||
unsigned ev = (unsigned) YAP_IntOfTerm ((YAP_ArgOfTerm (2, evTerm)));
|
||||
assert (fg->getVarNode (vid));
|
||||
fg->getVarNode (vid)->setEvidence (ev);
|
||||
evidenceList = YAP_TailOfTerm (evidenceList);
|
||||
nrObservedVars ++;
|
||||
}
|
||||
if (Globals::verbosity > 0) {
|
||||
cout << "factor graph contains " ;
|
||||
cout << fg->nrVarNodes() << " variables " ;
|
||||
cout << "(" << nrObservedVars << " observed) and " ;
|
||||
cout << fg->nrFacNodes() << " factors " << endl;
|
||||
}
|
||||
YAP_Int p = (YAP_Int) (fg);
|
||||
return YAP_Unify (YAP_MkIntTerm (p), YAP_ARG4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
runLiftedSolver (void)
|
||||
{
|
||||
LiftedNetwork* network = (LiftedNetwork*) YAP_IntOfTerm (YAP_ARG1);
|
||||
ParfactorList pfListCopy (*network->first);
|
||||
LiftedOperations::absorveEvidence (pfListCopy, *network->second);
|
||||
|
||||
LiftedSolver* solver = 0;
|
||||
switch (Globals::liftedSolver) {
|
||||
case LiftedSolverType::LVE: solver = new LiftedVe (pfListCopy); break;
|
||||
case LiftedSolverType::LBP: solver = new LiftedBp (pfListCopy); break;
|
||||
case LiftedSolverType::LKC: solver = new LiftedKc (pfListCopy); break;
|
||||
}
|
||||
|
||||
if (Globals::verbosity > 0) {
|
||||
solver->printSolverFlags();
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
YAP_Term taskList = YAP_ARG2;
|
||||
vector<Params> results;
|
||||
while (taskList != YAP_TermNil()) {
|
||||
Grounds queryVars;
|
||||
YAP_Term jointList = YAP_HeadOfTerm (taskList);
|
||||
while (jointList != YAP_TermNil()) {
|
||||
YAP_Term ground = YAP_HeadOfTerm (jointList);
|
||||
if (YAP_IsAtomTerm (ground)) {
|
||||
string name ((char*) YAP_AtomName (YAP_AtomOfTerm (ground)));
|
||||
queryVars.push_back (Ground (LiftedUtils::getSymbol (name)));
|
||||
} else {
|
||||
assert (YAP_IsApplTerm (ground));
|
||||
YAP_Functor yapFunctor = YAP_FunctorOfTerm (ground);
|
||||
string name ((char*) (YAP_AtomName (YAP_NameOfFunctor (yapFunctor))));
|
||||
unsigned arity = (unsigned) YAP_ArityOfFunctor (yapFunctor);
|
||||
Symbol functor = LiftedUtils::getSymbol (name);
|
||||
Symbols args;
|
||||
for (unsigned i = 1; i <= arity; i++) {
|
||||
YAP_Term ti = YAP_ArgOfTerm (i, ground);
|
||||
assert (YAP_IsAtomTerm (ti));
|
||||
string arg ((char *) YAP_AtomName (YAP_AtomOfTerm (ti)));
|
||||
args.push_back (LiftedUtils::getSymbol (arg));
|
||||
}
|
||||
queryVars.push_back (Ground (functor, args));
|
||||
}
|
||||
jointList = YAP_TailOfTerm (jointList);
|
||||
}
|
||||
results.push_back (solver->solveQuery (queryVars));
|
||||
taskList = YAP_TailOfTerm (taskList);
|
||||
}
|
||||
|
||||
delete solver;
|
||||
|
||||
return YAP_Unify (fillAnswersPrologList (results), YAP_ARG3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
runGroundSolver (void)
|
||||
{
|
||||
FactorGraph* fg = (FactorGraph*) YAP_IntOfTerm (YAP_ARG1);
|
||||
|
||||
vector<VarIds> tasks;
|
||||
YAP_Term taskList = YAP_ARG2;
|
||||
while (taskList != YAP_TermNil()) {
|
||||
tasks.push_back (readUnsignedList (YAP_HeadOfTerm (taskList)));
|
||||
taskList = YAP_TailOfTerm (taskList);
|
||||
}
|
||||
|
||||
FactorGraph* mfg = fg;
|
||||
if (fg->bayesianFactors()) {
|
||||
std::set<VarId> vids;
|
||||
for (size_t i = 0; i < tasks.size(); i++) {
|
||||
Util::addToSet (vids, tasks[i]);
|
||||
}
|
||||
mfg = BayesBall::getMinimalFactorGraph (
|
||||
*fg, VarIds (vids.begin(), vids.end()));
|
||||
}
|
||||
|
||||
GroundSolver* solver = 0;
|
||||
CountingBp::checkForIdenticalFactors = false;
|
||||
switch (Globals::groundSolver) {
|
||||
case GroundSolverType::VE: solver = new VarElim (*mfg); break;
|
||||
case GroundSolverType::BP: solver = new BeliefProp (*mfg); break;
|
||||
case GroundSolverType::CBP: solver = new CountingBp (*mfg); break;
|
||||
}
|
||||
|
||||
if (Globals::verbosity > 0) {
|
||||
solver->printSolverFlags();
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
vector<Params> results;
|
||||
results.reserve (tasks.size());
|
||||
for (size_t i = 0; i < tasks.size(); i++) {
|
||||
results.push_back (solver->solveQuery (tasks[i]));
|
||||
}
|
||||
|
||||
delete solver;
|
||||
if (fg->bayesianFactors()) {
|
||||
delete mfg;
|
||||
}
|
||||
|
||||
return YAP_Unify (fillAnswersPrologList (results), YAP_ARG3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
setParfactorsParams (void)
|
||||
{
|
||||
LiftedNetwork* network = (LiftedNetwork*) YAP_IntOfTerm (YAP_ARG1);
|
||||
ParfactorList* pfList = network->first;
|
||||
YAP_Term distIdsList = YAP_ARG2;
|
||||
YAP_Term paramsList = YAP_ARG3;
|
||||
unordered_map<unsigned, Params> paramsMap;
|
||||
while (distIdsList != YAP_TermNil()) {
|
||||
unsigned distId = (unsigned) YAP_IntOfTerm (
|
||||
YAP_HeadOfTerm (distIdsList));
|
||||
assert (Util::contains (paramsMap, distId) == false);
|
||||
paramsMap[distId] = readParameters (YAP_HeadOfTerm (paramsList));
|
||||
distIdsList = YAP_TailOfTerm (distIdsList);
|
||||
paramsList = YAP_TailOfTerm (paramsList);
|
||||
}
|
||||
ParfactorList::iterator it = pfList->begin();
|
||||
while (it != pfList->end()) {
|
||||
assert (Util::contains (paramsMap, (*it)->distId()));
|
||||
(*it)->setParams (paramsMap[(*it)->distId()]);
|
||||
++ it;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
setFactorsParams (void)
|
||||
{
|
||||
FactorGraph* fg = (FactorGraph*) YAP_IntOfTerm (YAP_ARG1);
|
||||
YAP_Term distIdsList = YAP_ARG2;
|
||||
YAP_Term paramsList = YAP_ARG3;
|
||||
unordered_map<unsigned, Params> paramsMap;
|
||||
while (distIdsList != YAP_TermNil()) {
|
||||
unsigned distId = (unsigned) YAP_IntOfTerm (
|
||||
YAP_HeadOfTerm (distIdsList));
|
||||
assert (Util::contains (paramsMap, distId) == false);
|
||||
paramsMap[distId] = readParameters (YAP_HeadOfTerm (paramsList));
|
||||
distIdsList = YAP_TailOfTerm (distIdsList);
|
||||
paramsList = YAP_TailOfTerm (paramsList);
|
||||
}
|
||||
const FacNodes& facNodes = fg->facNodes();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
unsigned distId = facNodes[i]->factor().distId();
|
||||
assert (Util::contains (paramsMap, distId));
|
||||
facNodes[i]->factor().setParams (paramsMap[distId]);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
setVarsInformation (void)
|
||||
{
|
||||
Var::clearVarsInfo();
|
||||
vector<string> labels;
|
||||
YAP_Term labelsL = YAP_ARG1;
|
||||
while (labelsL != YAP_TermNil()) {
|
||||
YAP_Atom atom = YAP_AtomOfTerm (YAP_HeadOfTerm (labelsL));
|
||||
labels.push_back ((char*) YAP_AtomName (atom));
|
||||
labelsL = YAP_TailOfTerm (labelsL);
|
||||
}
|
||||
unsigned count = 0;
|
||||
YAP_Term stateNamesL = YAP_ARG2;
|
||||
while (stateNamesL != YAP_TermNil()) {
|
||||
States states;
|
||||
YAP_Term namesL = YAP_HeadOfTerm (stateNamesL);
|
||||
while (namesL != YAP_TermNil()) {
|
||||
YAP_Atom atom = YAP_AtomOfTerm (YAP_HeadOfTerm (namesL));
|
||||
states.push_back ((char*) YAP_AtomName (atom));
|
||||
namesL = YAP_TailOfTerm (namesL);
|
||||
}
|
||||
Var::addVarInfo (count, labels[count], states);
|
||||
count ++;
|
||||
stateNamesL = YAP_TailOfTerm (stateNamesL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
setHorusFlag (void)
|
||||
{
|
||||
string key ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG1)));
|
||||
string value;
|
||||
if (key == "verbosity") {
|
||||
stringstream ss;
|
||||
ss << (int) YAP_IntOfTerm (YAP_ARG2);
|
||||
ss >> value;
|
||||
} else if (key == "accuracy") {
|
||||
stringstream ss;
|
||||
ss << (float) YAP_FloatOfTerm (YAP_ARG2);
|
||||
ss >> value;
|
||||
} else if (key == "max_iter") {
|
||||
stringstream ss;
|
||||
ss << (int) YAP_IntOfTerm (YAP_ARG2);
|
||||
ss >> value;
|
||||
} else {
|
||||
value = ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG2)));
|
||||
}
|
||||
return Util::setHorusFlag (key, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
freeGroundNetwork (void)
|
||||
{
|
||||
delete (FactorGraph*) YAP_IntOfTerm (YAP_ARG1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
freeLiftedNetwork (void)
|
||||
{
|
||||
LiftedNetwork* network = (LiftedNetwork*) YAP_IntOfTerm (YAP_ARG1);
|
||||
delete network->first;
|
||||
delete network->second;
|
||||
delete network;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactor*
|
||||
readParfactor (YAP_Term pfTerm)
|
||||
{
|
||||
// read dist id
|
||||
unsigned distId = YAP_IntOfTerm (YAP_ArgOfTerm (1, pfTerm));
|
||||
|
||||
// read the ranges
|
||||
Ranges ranges;
|
||||
YAP_Term rangeList = YAP_ArgOfTerm (3, pfTerm);
|
||||
while (rangeList != YAP_TermNil()) {
|
||||
unsigned range = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (rangeList));
|
||||
ranges.push_back (range);
|
||||
rangeList = YAP_TailOfTerm (rangeList);
|
||||
}
|
||||
|
||||
// read parametric random vars
|
||||
ProbFormulas formulas;
|
||||
unsigned count = 0;
|
||||
unordered_map<YAP_Term, LogVar> lvMap;
|
||||
YAP_Term pvList = YAP_ArgOfTerm (2, pfTerm);
|
||||
while (pvList != YAP_TermNil()) {
|
||||
YAP_Term formulaTerm = YAP_HeadOfTerm (pvList);
|
||||
if (YAP_IsAtomTerm (formulaTerm)) {
|
||||
string name ((char*) YAP_AtomName (YAP_AtomOfTerm (formulaTerm)));
|
||||
Symbol functor = LiftedUtils::getSymbol (name);
|
||||
formulas.push_back (ProbFormula (functor, ranges[count]));
|
||||
} else {
|
||||
LogVars logVars;
|
||||
YAP_Functor yapFunctor = YAP_FunctorOfTerm (formulaTerm);
|
||||
string name ((char*) YAP_AtomName (YAP_NameOfFunctor (yapFunctor)));
|
||||
Symbol functor = LiftedUtils::getSymbol (name);
|
||||
unsigned arity = (unsigned) YAP_ArityOfFunctor (yapFunctor);
|
||||
for (unsigned i = 1; i <= arity; i++) {
|
||||
YAP_Term ti = YAP_ArgOfTerm (i, formulaTerm);
|
||||
unordered_map<YAP_Term, LogVar>::iterator it = lvMap.find (ti);
|
||||
if (it != lvMap.end()) {
|
||||
logVars.push_back (it->second);
|
||||
} else {
|
||||
unsigned newLv = lvMap.size();
|
||||
lvMap[ti] = newLv;
|
||||
logVars.push_back (newLv);
|
||||
}
|
||||
}
|
||||
formulas.push_back (ProbFormula (functor, logVars, ranges[count]));
|
||||
}
|
||||
count ++;
|
||||
pvList = YAP_TailOfTerm (pvList);
|
||||
}
|
||||
|
||||
// read the parameters
|
||||
const Params& params = readParameters (YAP_ArgOfTerm (4, pfTerm));
|
||||
|
||||
// read the constraint
|
||||
Tuples tuples;
|
||||
if (lvMap.size() >= 1) {
|
||||
YAP_Term tupleList = YAP_ArgOfTerm (5, pfTerm);
|
||||
while (tupleList != YAP_TermNil()) {
|
||||
YAP_Term term = YAP_HeadOfTerm (tupleList);
|
||||
assert (YAP_IsApplTerm (term));
|
||||
YAP_Functor yapFunctor = YAP_FunctorOfTerm (term);
|
||||
unsigned arity = (unsigned) YAP_ArityOfFunctor (yapFunctor);
|
||||
assert (lvMap.size() == arity);
|
||||
Tuple tuple (arity);
|
||||
for (unsigned i = 1; i <= arity; i++) {
|
||||
YAP_Term ti = YAP_ArgOfTerm (i, term);
|
||||
if (YAP_IsAtomTerm (ti) == false) {
|
||||
cerr << "Error: the constraint contains free variables." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
string name ((char*) YAP_AtomName (YAP_AtomOfTerm (ti)));
|
||||
tuple[i - 1] = LiftedUtils::getSymbol (name);
|
||||
}
|
||||
tuples.push_back (tuple);
|
||||
tupleList = YAP_TailOfTerm (tupleList);
|
||||
}
|
||||
}
|
||||
return new Parfactor (formulas, params, tuples, distId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
readLiftedEvidence (
|
||||
YAP_Term observedList,
|
||||
ObservedFormulas& obsFormulas)
|
||||
{
|
||||
while (observedList != YAP_TermNil()) {
|
||||
YAP_Term pair = YAP_HeadOfTerm (observedList);
|
||||
YAP_Term ground = YAP_ArgOfTerm (1, pair);
|
||||
Symbol functor;
|
||||
Symbols args;
|
||||
if (YAP_IsAtomTerm (ground)) {
|
||||
string name ((char*) YAP_AtomName (YAP_AtomOfTerm (ground)));
|
||||
functor = LiftedUtils::getSymbol (name);
|
||||
} else {
|
||||
assert (YAP_IsApplTerm (ground));
|
||||
YAP_Functor yapFunctor = YAP_FunctorOfTerm (ground);
|
||||
string name ((char*) (YAP_AtomName (YAP_NameOfFunctor (yapFunctor))));
|
||||
functor = LiftedUtils::getSymbol (name);
|
||||
unsigned arity = (unsigned) YAP_ArityOfFunctor (yapFunctor);
|
||||
for (unsigned i = 1; i <= arity; i++) {
|
||||
YAP_Term ti = YAP_ArgOfTerm (i, ground);
|
||||
assert (YAP_IsAtomTerm (ti));
|
||||
string arg ((char *) YAP_AtomName (YAP_AtomOfTerm (ti)));
|
||||
args.push_back (LiftedUtils::getSymbol (arg));
|
||||
}
|
||||
}
|
||||
unsigned evidence = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (2, pair));
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < obsFormulas.size(); i++) {
|
||||
if (obsFormulas[i].functor() == functor &&
|
||||
obsFormulas[i].arity() == args.size() &&
|
||||
obsFormulas[i].evidence() == evidence) {
|
||||
obsFormulas[i].addTuple (args);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
obsFormulas.push_back (ObservedFormula (functor, evidence, args));
|
||||
}
|
||||
observedList = YAP_TailOfTerm (observedList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<unsigned>
|
||||
readUnsignedList (YAP_Term list)
|
||||
{
|
||||
vector<unsigned> vec;
|
||||
while (list != YAP_TermNil()) {
|
||||
vec.push_back ((unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (list)));
|
||||
list = YAP_TailOfTerm (list);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
readParameters (YAP_Term paramL)
|
||||
{
|
||||
Params params;
|
||||
assert (YAP_IsPairTerm (paramL));
|
||||
while (paramL != YAP_TermNil()) {
|
||||
params.push_back ((double) YAP_FloatOfTerm (YAP_HeadOfTerm (paramL)));
|
||||
paramL = YAP_TailOfTerm (paramL);
|
||||
}
|
||||
if (Globals::logDomain) {
|
||||
Util::log (params);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
|
||||
YAP_Term
|
||||
fillAnswersPrologList (vector<Params>& results)
|
||||
{
|
||||
YAP_Term list = YAP_TermNil();
|
||||
for (size_t i = results.size(); i-- > 0; ) {
|
||||
const Params& beliefs = results[i];
|
||||
YAP_Term queryBeliefsL = YAP_TermNil();
|
||||
for (size_t j = beliefs.size(); j-- > 0; ) {
|
||||
YAP_Int sl1 = YAP_InitSlot (list);
|
||||
YAP_Term belief = YAP_MkFloatTerm (beliefs[j]);
|
||||
queryBeliefsL = YAP_MkPairTerm (belief, queryBeliefsL);
|
||||
list = YAP_GetFromSlot (sl1);
|
||||
YAP_RecoverSlots (1);
|
||||
}
|
||||
list = YAP_MkPairTerm (queryBeliefsL, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" void
|
||||
init_predicates (void)
|
||||
{
|
||||
YAP_UserCPredicate ("cpp_create_lifted_network",
|
||||
createLiftedNetwork, 3);
|
||||
|
||||
YAP_UserCPredicate ("cpp_create_ground_network",
|
||||
createGroundNetwork, 4);
|
||||
|
||||
YAP_UserCPredicate ("cpp_run_lifted_solver",
|
||||
runLiftedSolver, 3);
|
||||
|
||||
YAP_UserCPredicate ("cpp_run_ground_solver",
|
||||
runGroundSolver, 3);
|
||||
|
||||
YAP_UserCPredicate ("cpp_set_parfactors_params",
|
||||
setParfactorsParams, 3);
|
||||
|
||||
YAP_UserCPredicate ("cpp_set_factors_params",
|
||||
setFactorsParams, 3);
|
||||
|
||||
YAP_UserCPredicate ("cpp_set_vars_information",
|
||||
setVarsInformation, 2);
|
||||
|
||||
YAP_UserCPredicate ("cpp_set_horus_flag",
|
||||
setHorusFlag, 2);
|
||||
|
||||
YAP_UserCPredicate ("cpp_free_lifted_network",
|
||||
freeLiftedNetwork, 1);
|
||||
|
||||
YAP_UserCPredicate ("cpp_free_ground_network",
|
||||
freeGroundNetwork, 1);
|
||||
}
|
||||
|
@ -1,258 +0,0 @@
|
||||
#ifndef HORUS_INDEXER_H
|
||||
#define HORUS_INDEXER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
class Indexer
|
||||
{
|
||||
public:
|
||||
Indexer (const Ranges& ranges, bool calcOffsets = true)
|
||||
: index_(0), indices_(ranges.size(), 0), ranges_(ranges),
|
||||
size_(Util::sizeExpected (ranges))
|
||||
{
|
||||
if (calcOffsets) {
|
||||
calculateOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
void increment (void)
|
||||
{
|
||||
for (size_t i = ranges_.size(); i-- > 0; ) {
|
||||
indices_[i] ++;
|
||||
if (indices_[i] != ranges_[i]) {
|
||||
break;
|
||||
} else {
|
||||
indices_[i] = 0;
|
||||
}
|
||||
}
|
||||
index_ ++;
|
||||
}
|
||||
|
||||
void incrementDimension (size_t dim)
|
||||
{
|
||||
assert (dim < ranges_.size());
|
||||
assert (ranges_.size() == offsets_.size());
|
||||
assert (indices_[dim] < ranges_[dim]);
|
||||
indices_[dim] ++;
|
||||
index_ += offsets_[dim];
|
||||
}
|
||||
|
||||
void incrementExceptDimension (size_t dim)
|
||||
{
|
||||
assert (ranges_.size() == offsets_.size());
|
||||
for (size_t i = ranges_.size(); i-- > 0; ) {
|
||||
if (i != dim) {
|
||||
indices_[i] ++;
|
||||
index_ += offsets_[i];
|
||||
if (indices_[i] != ranges_[i]) {
|
||||
return;
|
||||
} else {
|
||||
indices_[i] = 0;
|
||||
index_ -= offsets_[i] * ranges_[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
index_ = size_;
|
||||
}
|
||||
|
||||
Indexer& operator++ (void)
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator size_t (void) const
|
||||
{
|
||||
return index_;
|
||||
}
|
||||
|
||||
unsigned operator[] (size_t dim) const
|
||||
{
|
||||
assert (valid());
|
||||
assert (dim < ranges_.size());
|
||||
return indices_[dim];
|
||||
}
|
||||
|
||||
bool valid (void) const
|
||||
{
|
||||
return index_ < size_;
|
||||
}
|
||||
|
||||
void reset (void)
|
||||
{
|
||||
std::fill (indices_.begin(), indices_.end(), 0);
|
||||
index_ = 0;
|
||||
}
|
||||
|
||||
void resetDimension (size_t dim)
|
||||
{
|
||||
indices_[dim] = 0;
|
||||
index_ -= offsets_[dim] * ranges_[dim];
|
||||
}
|
||||
|
||||
size_t size (void) const
|
||||
{
|
||||
return size_ ;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< (std::ostream&, const Indexer&);
|
||||
|
||||
private:
|
||||
void calculateOffsets (void)
|
||||
{
|
||||
size_t prod = 1;
|
||||
offsets_.resize (ranges_.size());
|
||||
for (size_t i = ranges_.size(); i-- > 0; ) {
|
||||
offsets_[i] = prod;
|
||||
prod *= ranges_[i];
|
||||
}
|
||||
}
|
||||
|
||||
size_t index_;
|
||||
Ranges indices_;
|
||||
const Ranges& ranges_;
|
||||
size_t size_;
|
||||
vector<size_t> offsets_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline std::ostream&
|
||||
operator<< (std::ostream& os, const Indexer& indexer)
|
||||
{
|
||||
os << "(" ;
|
||||
os << std::setw (2) << std::setfill('0') << indexer.index_;
|
||||
os << ") " ;
|
||||
os << indexer.indices_;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class MapIndexer
|
||||
{
|
||||
public:
|
||||
MapIndexer (const Ranges& ranges, const vector<bool>& mask)
|
||||
: index_(0), indices_(ranges.size(), 0), ranges_(ranges),
|
||||
valid_(true)
|
||||
{
|
||||
size_t prod = 1;
|
||||
offsets_.resize (ranges.size(), 0);
|
||||
for (size_t i = ranges.size(); i-- > 0; ) {
|
||||
if (mask[i]) {
|
||||
offsets_[i] = prod;
|
||||
prod *= ranges[i];
|
||||
}
|
||||
}
|
||||
assert (ranges.size() == mask.size());
|
||||
}
|
||||
|
||||
MapIndexer (const Ranges& ranges, size_t dim)
|
||||
: index_(0), indices_(ranges.size(), 0), ranges_(ranges),
|
||||
valid_(true)
|
||||
{
|
||||
size_t prod = 1;
|
||||
offsets_.resize (ranges.size(), 0);
|
||||
for (size_t i = ranges.size(); i-- > 0; ) {
|
||||
if (i != dim) {
|
||||
offsets_[i] = prod;
|
||||
prod *= ranges[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MapIndexer (
|
||||
const vector<T>& allArgs,
|
||||
const Ranges& allRanges,
|
||||
const vector<T>& wantedArgs,
|
||||
const Ranges& wantedRanges)
|
||||
: index_(0), indices_(allArgs.size(), 0), ranges_(allRanges),
|
||||
valid_(true)
|
||||
{
|
||||
size_t prod = 1;
|
||||
vector<size_t> offsets (wantedRanges.size());
|
||||
for (size_t i = wantedRanges.size(); i-- > 0; ) {
|
||||
offsets[i] = prod;
|
||||
prod *= wantedRanges[i];
|
||||
}
|
||||
offsets_.reserve (allArgs.size());
|
||||
for (size_t i = 0; i < allArgs.size(); i++) {
|
||||
size_t idx = Util::indexOf (wantedArgs, allArgs[i]);
|
||||
offsets_.push_back (idx != wantedArgs.size() ? offsets[idx] : 0);
|
||||
}
|
||||
}
|
||||
|
||||
MapIndexer& operator++ (void)
|
||||
{
|
||||
assert (valid_);
|
||||
for (size_t i = ranges_.size(); i-- > 0; ) {
|
||||
indices_[i] ++;
|
||||
index_ += offsets_[i];
|
||||
if (indices_[i] != ranges_[i]) {
|
||||
return *this;
|
||||
} else {
|
||||
indices_[i] = 0;
|
||||
index_ -= offsets_[i] * ranges_[i];
|
||||
}
|
||||
}
|
||||
valid_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator size_t (void) const
|
||||
{
|
||||
assert (valid());
|
||||
return index_;
|
||||
}
|
||||
|
||||
unsigned operator[] (size_t dim) const
|
||||
{
|
||||
assert (valid());
|
||||
assert (dim < ranges_.size());
|
||||
return indices_[dim];
|
||||
}
|
||||
|
||||
bool valid (void) const
|
||||
{
|
||||
return valid_;
|
||||
}
|
||||
|
||||
void reset (void)
|
||||
{
|
||||
std::fill (indices_.begin(), indices_.end(), 0);
|
||||
index_ = 0;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< (std::ostream&, const MapIndexer&);
|
||||
|
||||
private:
|
||||
size_t index_;
|
||||
Ranges indices_;
|
||||
const Ranges& ranges_;
|
||||
bool valid_;
|
||||
vector<size_t> offsets_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline std::ostream&
|
||||
operator<< (std::ostream &os, const MapIndexer& indexer)
|
||||
{
|
||||
os << "(" ;
|
||||
os << std::setw (2) << std::setfill('0') << indexer.index_;
|
||||
os << ") " ;
|
||||
os << indexer.indices_;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
#endif // HORUS_INDEXER_H
|
||||
|
@ -1,234 +0,0 @@
|
||||
#include "LiftedBp.h"
|
||||
#include "WeightedBp.h"
|
||||
#include "FactorGraph.h"
|
||||
#include "LiftedOperations.h"
|
||||
|
||||
|
||||
LiftedBp::LiftedBp (const ParfactorList& parfactorList)
|
||||
: LiftedSolver (parfactorList)
|
||||
{
|
||||
refineParfactors();
|
||||
createFactorGraph();
|
||||
solver_ = new WeightedBp (*fg_, getWeights());
|
||||
}
|
||||
|
||||
|
||||
|
||||
LiftedBp::~LiftedBp (void)
|
||||
{
|
||||
delete solver_;
|
||||
delete fg_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
LiftedBp::solveQuery (const Grounds& query)
|
||||
{
|
||||
assert (query.empty() == false);
|
||||
Params res;
|
||||
vector<PrvGroup> groups = getQueryGroups (query);
|
||||
if (query.size() == 1) {
|
||||
res = solver_->getPosterioriOf (groups[0]);
|
||||
} else {
|
||||
ParfactorList::iterator it = pfList_.begin();
|
||||
size_t idx = pfList_.size();
|
||||
size_t count = 0;
|
||||
while (it != pfList_.end()) {
|
||||
if ((*it)->containsGrounds (query)) {
|
||||
idx = count;
|
||||
break;
|
||||
}
|
||||
++ it;
|
||||
++ count;
|
||||
}
|
||||
if (idx == pfList_.size()) {
|
||||
res = getJointByConditioning (pfList_, query);
|
||||
} else {
|
||||
VarIds queryVids;
|
||||
for (unsigned i = 0; i < groups.size(); i++) {
|
||||
queryVids.push_back (groups[i]);
|
||||
}
|
||||
res = solver_->getFactorJoint (fg_->facNodes()[idx], queryVids);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedBp::printSolverFlags (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "lifted bp [" ;
|
||||
ss << "schedule=" ;
|
||||
typedef BpOptions::Schedule Sch;
|
||||
switch (BpOptions::schedule) {
|
||||
case Sch::SEQ_FIXED: ss << "seq_fixed"; break;
|
||||
case Sch::SEQ_RANDOM: ss << "seq_random"; break;
|
||||
case Sch::PARALLEL: ss << "parallel"; break;
|
||||
case Sch::MAX_RESIDUAL: ss << "max_residual"; break;
|
||||
}
|
||||
ss << ",max_iter=" << BpOptions::maxIter;
|
||||
ss << ",accuracy=" << BpOptions::accuracy;
|
||||
ss << ",log_domain=" << Util::toString (Globals::logDomain);
|
||||
ss << "]" ;
|
||||
cout << ss.str() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedBp::refineParfactors (void)
|
||||
{
|
||||
pfList_ = parfactorList;
|
||||
while (iterate() == false);
|
||||
|
||||
if (Globals::verbosity > 2) {
|
||||
Util::printHeader ("AFTER REFINEMENT");
|
||||
pfList_.print();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
LiftedBp::iterate (void)
|
||||
{
|
||||
ParfactorList::iterator it = pfList_.begin();
|
||||
while (it != pfList_.end()) {
|
||||
const ProbFormulas& args = (*it)->arguments();
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
LogVarSet lvs = (*it)->logVarSet() - args[i].logVars();
|
||||
if ((*it)->constr()->isCountNormalized (lvs) == false) {
|
||||
Parfactors pfs = LiftedOperations::countNormalize (*it, lvs);
|
||||
it = pfList_.removeAndDelete (it);
|
||||
pfList_.add (pfs);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<PrvGroup>
|
||||
LiftedBp::getQueryGroups (const Grounds& query)
|
||||
{
|
||||
vector<PrvGroup> queryGroups;
|
||||
for (unsigned i = 0; i < query.size(); i++) {
|
||||
ParfactorList::const_iterator it = pfList_.begin();
|
||||
for (; it != pfList_.end(); ++it) {
|
||||
if ((*it)->containsGround (query[i])) {
|
||||
queryGroups.push_back ((*it)->findGroup (query[i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (queryGroups.size() == query.size());
|
||||
return queryGroups;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedBp::createFactorGraph (void)
|
||||
{
|
||||
fg_ = new FactorGraph();
|
||||
ParfactorList::const_iterator it = pfList_.begin();
|
||||
for (; it != pfList_.end(); ++it) {
|
||||
vector<PrvGroup> groups = (*it)->getAllGroups();
|
||||
VarIds varIds;
|
||||
for (size_t i = 0; i < groups.size(); i++) {
|
||||
varIds.push_back (groups[i]);
|
||||
}
|
||||
fg_->addFactor (Factor (varIds, (*it)->ranges(), (*it)->params()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<vector<unsigned>>
|
||||
LiftedBp::getWeights (void) const
|
||||
{
|
||||
vector<vector<unsigned>> weights;
|
||||
weights.reserve (pfList_.size());
|
||||
ParfactorList::const_iterator it = pfList_.begin();
|
||||
for (; it != pfList_.end(); ++it) {
|
||||
const ProbFormulas& args = (*it)->arguments();
|
||||
weights.push_back ({ });
|
||||
weights.back().reserve (args.size());
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
LogVarSet lvs = (*it)->logVarSet() - args[i].logVars();
|
||||
weights.back().push_back ((*it)->constr()->getConditionalCount (lvs));
|
||||
}
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
LiftedBp::rangeOfGround (const Ground& gr)
|
||||
{
|
||||
ParfactorList::iterator it = pfList_.begin();
|
||||
while (it != pfList_.end()) {
|
||||
if ((*it)->containsGround (gr)) {
|
||||
PrvGroup prvGroup = (*it)->findGroup (gr);
|
||||
return (*it)->range ((*it)->indexOfGroup (prvGroup));
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
LiftedBp::getJointByConditioning (
|
||||
const ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
LiftedBp solver (pfList);
|
||||
Params prevBeliefs = solver.solveQuery ({query[0]});
|
||||
Grounds obsGrounds = {query[0]};
|
||||
for (size_t i = 1; i < query.size(); i++) {
|
||||
Params newBeliefs;
|
||||
vector<ObservedFormula> obsFs;
|
||||
Ranges obsRanges;
|
||||
for (size_t j = 0; j < obsGrounds.size(); j++) {
|
||||
obsFs.push_back (ObservedFormula (
|
||||
obsGrounds[j].functor(), 0, obsGrounds[j].args()));
|
||||
obsRanges.push_back (rangeOfGround (obsGrounds[j]));
|
||||
}
|
||||
Indexer indexer (obsRanges, false);
|
||||
while (indexer.valid()) {
|
||||
for (size_t j = 0; j < obsFs.size(); j++) {
|
||||
obsFs[j].setEvidence (indexer[j]);
|
||||
}
|
||||
ParfactorList tempPfList (pfList);
|
||||
LiftedOperations::absorveEvidence (tempPfList, obsFs);
|
||||
LiftedBp solver (tempPfList);
|
||||
Params beliefs = solver.solveQuery ({query[i]});
|
||||
for (size_t k = 0; k < beliefs.size(); k++) {
|
||||
newBeliefs.push_back (beliefs[k]);
|
||||
}
|
||||
++ indexer;
|
||||
}
|
||||
int count = -1;
|
||||
unsigned range = rangeOfGround (query[i]);
|
||||
for (size_t j = 0; j < newBeliefs.size(); j++) {
|
||||
if (j % range == 0) {
|
||||
count ++;
|
||||
}
|
||||
newBeliefs[j] *= prevBeliefs[count];
|
||||
}
|
||||
prevBeliefs = newBeliefs;
|
||||
obsGrounds.push_back (query[i]);
|
||||
}
|
||||
return prevBeliefs;
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDBP_H
|
||||
#define HORUS_LIFTEDBP_H
|
||||
|
||||
#include "LiftedSolver.h"
|
||||
#include "ParfactorList.h"
|
||||
|
||||
class FactorGraph;
|
||||
class WeightedBp;
|
||||
|
||||
class LiftedBp : public LiftedSolver
|
||||
{
|
||||
public:
|
||||
LiftedBp (const ParfactorList& pfList);
|
||||
|
||||
~LiftedBp (void);
|
||||
|
||||
Params solveQuery (const Grounds&);
|
||||
|
||||
void printSolverFlags (void) const;
|
||||
|
||||
private:
|
||||
void refineParfactors (void);
|
||||
|
||||
bool iterate (void);
|
||||
|
||||
vector<PrvGroup> getQueryGroups (const Grounds&);
|
||||
|
||||
void createFactorGraph (void);
|
||||
|
||||
vector<vector<unsigned>> getWeights (void) const;
|
||||
|
||||
unsigned rangeOfGround (const Ground&);
|
||||
|
||||
Params getJointByConditioning (const ParfactorList&, const Grounds&);
|
||||
|
||||
ParfactorList pfList_;
|
||||
WeightedBp* solver_;
|
||||
FactorGraph* fg_;
|
||||
|
||||
};
|
||||
|
||||
#endif // HORUS_LIFTEDBP_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,300 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDKC_H
|
||||
#define HORUS_LIFTEDKC_H
|
||||
|
||||
|
||||
#include "LiftedWCNF.h"
|
||||
#include "LiftedSolver.h"
|
||||
#include "ParfactorList.h"
|
||||
|
||||
|
||||
enum CircuitNodeType {
|
||||
OR_NODE,
|
||||
AND_NODE,
|
||||
SET_OR_NODE,
|
||||
SET_AND_NODE,
|
||||
INC_EXC_NODE,
|
||||
LEAF_NODE,
|
||||
SMOOTH_NODE,
|
||||
TRUE_NODE,
|
||||
COMPILATION_FAILED_NODE
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CircuitNode
|
||||
{
|
||||
public:
|
||||
CircuitNode (void) { }
|
||||
|
||||
virtual ~CircuitNode (void) { }
|
||||
|
||||
virtual double weight (void) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class OrNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
OrNode (void) : CircuitNode(), leftBranch_(0), rightBranch_(0) { }
|
||||
|
||||
~OrNode (void);
|
||||
|
||||
CircuitNode** leftBranch (void) { return &leftBranch_; }
|
||||
CircuitNode** rightBranch (void) { return &rightBranch_; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
CircuitNode* leftBranch_;
|
||||
CircuitNode* rightBranch_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AndNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
AndNode (void) : CircuitNode(), leftBranch_(0), rightBranch_(0) { }
|
||||
|
||||
AndNode (CircuitNode* leftBranch, CircuitNode* rightBranch)
|
||||
: CircuitNode(), leftBranch_(leftBranch), rightBranch_(rightBranch) { }
|
||||
|
||||
~AndNode (void);
|
||||
|
||||
CircuitNode** leftBranch (void) { return &leftBranch_; }
|
||||
CircuitNode** rightBranch (void) { return &rightBranch_; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
CircuitNode* leftBranch_;
|
||||
CircuitNode* rightBranch_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SetOrNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
SetOrNode (unsigned nrGroundings)
|
||||
: CircuitNode(), follow_(0), nrGroundings_(nrGroundings) { }
|
||||
|
||||
~SetOrNode (void);
|
||||
|
||||
CircuitNode** follow (void) { return &follow_; }
|
||||
|
||||
static unsigned nrPositives (void) { return nrPos_; }
|
||||
|
||||
static unsigned nrNegatives (void) { return nrNeg_; }
|
||||
|
||||
static bool isSet (void) { return nrPos_ >= 0; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
CircuitNode* follow_;
|
||||
unsigned nrGroundings_;
|
||||
static int nrPos_;
|
||||
static int nrNeg_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SetAndNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
SetAndNode (unsigned nrGroundings)
|
||||
: CircuitNode(), follow_(0), nrGroundings_(nrGroundings) { }
|
||||
|
||||
~SetAndNode (void);
|
||||
|
||||
CircuitNode** follow (void) { return &follow_; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
CircuitNode* follow_;
|
||||
unsigned nrGroundings_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class IncExcNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
IncExcNode (void)
|
||||
: CircuitNode(), plus1Branch_(0), plus2Branch_(0), minusBranch_(0) { }
|
||||
|
||||
~IncExcNode (void);
|
||||
|
||||
CircuitNode** plus1Branch (void) { return &plus1Branch_; }
|
||||
CircuitNode** plus2Branch (void) { return &plus2Branch_; }
|
||||
CircuitNode** minusBranch (void) { return &minusBranch_; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
CircuitNode* plus1Branch_;
|
||||
CircuitNode* plus2Branch_;
|
||||
CircuitNode* minusBranch_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LeafNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
LeafNode (Clause* clause, const LiftedWCNF& lwcnf)
|
||||
: CircuitNode(), clause_(clause), lwcnf_(lwcnf) { }
|
||||
|
||||
~LeafNode (void);
|
||||
|
||||
const Clause* clause (void) const { return clause_; }
|
||||
|
||||
Clause* clause (void) { return clause_; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
Clause* clause_;
|
||||
const LiftedWCNF& lwcnf_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SmoothNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
SmoothNode (const Clauses& clauses, const LiftedWCNF& lwcnf)
|
||||
: CircuitNode(), clauses_(clauses), lwcnf_(lwcnf) { }
|
||||
|
||||
~SmoothNode (void);
|
||||
|
||||
const Clauses& clauses (void) const { return clauses_; }
|
||||
|
||||
Clauses clauses (void) { return clauses_; }
|
||||
|
||||
double weight (void) const;
|
||||
|
||||
private:
|
||||
Clauses clauses_;
|
||||
const LiftedWCNF& lwcnf_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TrueNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
TrueNode (void) : CircuitNode() { }
|
||||
|
||||
double weight (void) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CompilationFailedNode : public CircuitNode
|
||||
{
|
||||
public:
|
||||
CompilationFailedNode (void) : CircuitNode() { }
|
||||
|
||||
double weight (void) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LiftedCircuit
|
||||
{
|
||||
public:
|
||||
LiftedCircuit (const LiftedWCNF* lwcnf);
|
||||
|
||||
~LiftedCircuit (void);
|
||||
|
||||
bool isCompilationSucceeded (void) const;
|
||||
|
||||
double getWeightedModelCount (void) const;
|
||||
|
||||
void exportToGraphViz (const char*);
|
||||
|
||||
private:
|
||||
|
||||
void compile (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
bool tryUnitPropagation (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
bool tryIndependence (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
bool tryShannonDecomp (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
bool tryInclusionExclusion (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
bool tryIndepPartialGrounding (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
bool tryIndepPartialGroundingAux (Clauses& clauses, ConstraintTree& ct,
|
||||
LogVars& rootLogVars);
|
||||
|
||||
bool tryAtomCounting (CircuitNode** follow, Clauses& clauses);
|
||||
|
||||
void shatterCountedLogVars (Clauses& clauses);
|
||||
|
||||
bool shatterCountedLogVarsAux (Clauses& clauses);
|
||||
|
||||
bool shatterCountedLogVarsAux (Clauses& clauses, size_t idx1, size_t idx2);
|
||||
|
||||
bool independentClause (Clause& clause, Clauses& otherClauses) const;
|
||||
|
||||
bool independentLiteral (const Literal& lit,
|
||||
const Literals& otherLits) const;
|
||||
|
||||
LitLvTypesSet smoothCircuit (CircuitNode* node);
|
||||
|
||||
void createSmoothNode (const LitLvTypesSet& lids,
|
||||
CircuitNode** prev);
|
||||
|
||||
vector<LogVarTypes> getAllPossibleTypes (unsigned nrLogVars) const;
|
||||
|
||||
bool containsTypes (const LogVarTypes& typesA,
|
||||
const LogVarTypes& typesB) const;
|
||||
|
||||
CircuitNodeType getCircuitNodeType (const CircuitNode* node) const;
|
||||
|
||||
void exportToGraphViz (CircuitNode* node, ofstream&);
|
||||
|
||||
void printClauses (CircuitNode* node, ofstream&,
|
||||
string extraOptions = "");
|
||||
|
||||
string escapeNode (const CircuitNode* node) const;
|
||||
|
||||
string getExplanationString (CircuitNode* node);
|
||||
|
||||
CircuitNode* root_;
|
||||
const LiftedWCNF* lwcnf_;
|
||||
bool compilationSucceeded_;
|
||||
Clauses backupClauses_;
|
||||
unordered_map<CircuitNode*, Clauses> originClausesMap_;
|
||||
unordered_map<CircuitNode*, string> explanationMap_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LiftedKc : public LiftedSolver
|
||||
{
|
||||
public:
|
||||
LiftedKc (const ParfactorList& pfList)
|
||||
: LiftedSolver(pfList) { }
|
||||
|
||||
~LiftedKc (void);
|
||||
|
||||
Params solveQuery (const Grounds&);
|
||||
|
||||
void printSolverFlags (void) const;
|
||||
|
||||
private:
|
||||
LiftedWCNF* lwcnf_;
|
||||
LiftedCircuit* circuit_;
|
||||
ParfactorList pfList_;
|
||||
};
|
||||
|
||||
#endif // HORUS_LIFTEDKC_H
|
||||
|
@ -1,271 +0,0 @@
|
||||
#include "LiftedOperations.h"
|
||||
|
||||
|
||||
void
|
||||
LiftedOperations::shatterAgainstQuery (
|
||||
ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
for (size_t i = 0; i < query.size(); i++) {
|
||||
if (query[i].isAtom()) {
|
||||
continue;
|
||||
}
|
||||
bool found = false;
|
||||
Parfactors newPfs;
|
||||
ParfactorList::iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
if ((*it)->containsGround (query[i])) {
|
||||
found = true;
|
||||
std::pair<ConstraintTree*, ConstraintTree*> split;
|
||||
LogVars queryLvs (
|
||||
(*it)->constr()->logVars().begin(),
|
||||
(*it)->constr()->logVars().begin() + query[i].arity());
|
||||
split = (*it)->constr()->split (query[i].args());
|
||||
ConstraintTree* commCt = split.first;
|
||||
ConstraintTree* exclCt = split.second;
|
||||
newPfs.push_back (new Parfactor (*it, commCt));
|
||||
if (exclCt->empty() == false) {
|
||||
newPfs.push_back (new Parfactor (*it, exclCt));
|
||||
} else {
|
||||
delete exclCt;
|
||||
}
|
||||
it = pfList.removeAndDelete (it);
|
||||
} else {
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
cerr << "Error: could not find a parfactor with ground " ;
|
||||
cerr << "`" << query[i] << "'." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
pfList.add (newPfs);
|
||||
}
|
||||
if (Globals::verbosity > 2) {
|
||||
Util::printAsteriskLine();
|
||||
cout << "SHATTERED AGAINST THE QUERY" << endl;
|
||||
for (size_t i = 0; i < query.size(); i++) {
|
||||
cout << " -> " << query[i] << endl;
|
||||
}
|
||||
Util::printAsteriskLine();
|
||||
pfList.print();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedOperations::runWeakBayesBall (
|
||||
ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
queue<PrvGroup> todo; // groups to process
|
||||
set<PrvGroup> done; // processed or in queue
|
||||
for (size_t i = 0; i < query.size(); i++) {
|
||||
ParfactorList::iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
PrvGroup group = (*it)->findGroup (query[i]);
|
||||
if (group != numeric_limits<PrvGroup>::max()) {
|
||||
todo.push (group);
|
||||
done.insert (group);
|
||||
break;
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
set<Parfactor*> requiredPfs;
|
||||
while (todo.empty() == false) {
|
||||
PrvGroup group = todo.front();
|
||||
ParfactorList::iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
if (Util::contains (requiredPfs, *it) == false &&
|
||||
(*it)->containsGroup (group)) {
|
||||
vector<PrvGroup> groups = (*it)->getAllGroups();
|
||||
for (size_t i = 0; i < groups.size(); i++) {
|
||||
if (Util::contains (done, groups[i]) == false) {
|
||||
todo.push (groups[i]);
|
||||
done.insert (groups[i]);
|
||||
}
|
||||
}
|
||||
requiredPfs.insert (*it);
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
todo.pop();
|
||||
}
|
||||
|
||||
ParfactorList::iterator it = pfList.begin();
|
||||
bool foundNotRequired = false;
|
||||
while (it != pfList.end()) {
|
||||
if (Util::contains (requiredPfs, *it) == false) {
|
||||
if (Globals::verbosity > 2) {
|
||||
if (foundNotRequired == false) {
|
||||
Util::printHeader ("PARFACTORS TO DISCARD");
|
||||
foundNotRequired = true;
|
||||
}
|
||||
(*it)->print();
|
||||
}
|
||||
it = pfList.removeAndDelete (it);
|
||||
} else {
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedOperations::absorveEvidence (
|
||||
ParfactorList& pfList,
|
||||
ObservedFormulas& obsFormulas)
|
||||
{
|
||||
for (size_t i = 0; i < obsFormulas.size(); i++) {
|
||||
Parfactors newPfs;
|
||||
ParfactorList::iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
Parfactor* pf = *it;
|
||||
it = pfList.remove (it);
|
||||
Parfactors absorvedPfs = absorve (obsFormulas[i], pf);
|
||||
if (absorvedPfs.empty() == false) {
|
||||
if (absorvedPfs.size() == 1 && absorvedPfs[0] == 0) {
|
||||
// just remove pf;
|
||||
} else {
|
||||
Util::addToVector (newPfs, absorvedPfs);
|
||||
}
|
||||
delete pf;
|
||||
} else {
|
||||
it = pfList.insertShattered (it, pf);
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
pfList.add (newPfs);
|
||||
}
|
||||
if (Globals::verbosity > 2 && obsFormulas.empty() == false) {
|
||||
Util::printAsteriskLine();
|
||||
cout << "AFTER EVIDENCE ABSORVED" << endl;
|
||||
for (size_t i = 0; i < obsFormulas.size(); i++) {
|
||||
cout << " -> " << obsFormulas[i] << endl;
|
||||
}
|
||||
Util::printAsteriskLine();
|
||||
pfList.print();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactors
|
||||
LiftedOperations::countNormalize (
|
||||
Parfactor* g,
|
||||
const LogVarSet& set)
|
||||
{
|
||||
Parfactors normPfs;
|
||||
if (set.empty()) {
|
||||
normPfs.push_back (new Parfactor (*g));
|
||||
} else {
|
||||
ConstraintTrees normCts = g->constr()->countNormalize (set);
|
||||
for (size_t i = 0; i < normCts.size(); i++) {
|
||||
normPfs.push_back (new Parfactor (g, normCts[i]));
|
||||
}
|
||||
}
|
||||
return normPfs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactor
|
||||
LiftedOperations::calcGroundMultiplication (Parfactor pf)
|
||||
{
|
||||
LogVarSet lvs = pf.constr()->logVarSet();
|
||||
lvs -= pf.constr()->singletons();
|
||||
Parfactors newPfs = {new Parfactor (pf)};
|
||||
for (size_t i = 0; i < lvs.size(); i++) {
|
||||
Parfactors pfs = newPfs;
|
||||
newPfs.clear();
|
||||
for (size_t j = 0; j < pfs.size(); j++) {
|
||||
bool countedLv = pfs[j]->countedLogVars().contains (lvs[i]);
|
||||
if (countedLv) {
|
||||
pfs[j]->fullExpand (lvs[i]);
|
||||
newPfs.push_back (pfs[j]);
|
||||
} else {
|
||||
ConstraintTrees cts = pfs[j]->constr()->ground (lvs[i]);
|
||||
for (size_t k = 0; k < cts.size(); k++) {
|
||||
newPfs.push_back (new Parfactor (pfs[j], cts[k]));
|
||||
}
|
||||
delete pfs[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
ParfactorList pfList (newPfs);
|
||||
Parfactors groundShatteredPfs (pfList.begin(),pfList.end());
|
||||
for (size_t i = 1; i < groundShatteredPfs.size(); i++) {
|
||||
groundShatteredPfs[0]->multiply (*groundShatteredPfs[i]);
|
||||
}
|
||||
return Parfactor (*groundShatteredPfs[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactors
|
||||
LiftedOperations::absorve (
|
||||
ObservedFormula& obsFormula,
|
||||
Parfactor* g)
|
||||
{
|
||||
Parfactors absorvedPfs;
|
||||
const ProbFormulas& formulas = g->arguments();
|
||||
for (size_t i = 0; i < formulas.size(); i++) {
|
||||
if (obsFormula.functor() == formulas[i].functor() &&
|
||||
obsFormula.arity() == formulas[i].arity()) {
|
||||
|
||||
if (obsFormula.isAtom()) {
|
||||
if (formulas.size() > 1) {
|
||||
g->absorveEvidence (formulas[i], obsFormula.evidence());
|
||||
} else {
|
||||
// hack to erase parfactor g
|
||||
absorvedPfs.push_back (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
g->constr()->moveToTop (formulas[i].logVars());
|
||||
std::pair<ConstraintTree*, ConstraintTree*> res;
|
||||
res = g->constr()->split (
|
||||
formulas[i].logVars(),
|
||||
&(obsFormula.constr()),
|
||||
obsFormula.constr().logVars());
|
||||
ConstraintTree* commCt = res.first;
|
||||
ConstraintTree* exclCt = res.second;
|
||||
|
||||
if (commCt->empty() == false) {
|
||||
if (formulas.size() > 1) {
|
||||
LogVarSet excl = g->exclusiveLogVars (i);
|
||||
Parfactor tempPf (g, commCt);
|
||||
Parfactors countNormPfs = LiftedOperations::countNormalize (
|
||||
&tempPf, excl);
|
||||
for (size_t j = 0; j < countNormPfs.size(); j++) {
|
||||
countNormPfs[j]->absorveEvidence (
|
||||
formulas[i], obsFormula.evidence());
|
||||
absorvedPfs.push_back (countNormPfs[j]);
|
||||
}
|
||||
} else {
|
||||
delete commCt;
|
||||
}
|
||||
if (exclCt->empty() == false) {
|
||||
absorvedPfs.push_back (new Parfactor (g, exclCt));
|
||||
} else {
|
||||
delete exclCt;
|
||||
}
|
||||
if (absorvedPfs.empty()) {
|
||||
// hack to erase parfactor g
|
||||
absorvedPfs.push_back (0);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
delete commCt;
|
||||
delete exclCt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return absorvedPfs;
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDOPERATIONS_H
|
||||
#define HORUS_LIFTEDOPERATIONS_H
|
||||
|
||||
#include "ParfactorList.h"
|
||||
|
||||
class LiftedOperations
|
||||
{
|
||||
public:
|
||||
static void shatterAgainstQuery (
|
||||
ParfactorList& pfList, const Grounds& query);
|
||||
|
||||
static void runWeakBayesBall (
|
||||
ParfactorList& pfList, const Grounds&);
|
||||
|
||||
static void absorveEvidence (
|
||||
ParfactorList& pfList, ObservedFormulas& obsFormulas);
|
||||
|
||||
static Parfactors countNormalize (Parfactor*, const LogVarSet&);
|
||||
|
||||
static Parfactor calcGroundMultiplication (Parfactor pf);
|
||||
|
||||
private:
|
||||
static Parfactors absorve (ObservedFormula&, Parfactor*);
|
||||
};
|
||||
|
||||
#endif // HORUS_LIFTEDOPERATIONS_H
|
||||
|
@ -1,27 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDSOLVER_H
|
||||
#define HORUS_LIFTEDSOLVER_H
|
||||
|
||||
#include "ParfactorList.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
class LiftedSolver
|
||||
{
|
||||
public:
|
||||
LiftedSolver (const ParfactorList& pfList)
|
||||
: parfactorList(pfList) { }
|
||||
|
||||
virtual ~LiftedSolver() { } // ensure that subclass destructor is called
|
||||
|
||||
virtual Params solveQuery (const Grounds& query) = 0;
|
||||
|
||||
virtual void printSolverFlags (void) const = 0;
|
||||
|
||||
protected:
|
||||
const ParfactorList& parfactorList;
|
||||
};
|
||||
|
||||
#endif // HORUS_LIFTEDSOLVER_H
|
||||
|
@ -1,131 +0,0 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "LiftedUtils.h"
|
||||
#include "ConstraintTree.h"
|
||||
|
||||
|
||||
namespace LiftedUtils {
|
||||
|
||||
|
||||
unordered_map<string, unsigned> symbolDict;
|
||||
|
||||
|
||||
Symbol
|
||||
getSymbol (const string& symbolName)
|
||||
{
|
||||
unordered_map<string, unsigned>::iterator it
|
||||
= symbolDict.find (symbolName);
|
||||
if (it != symbolDict.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
symbolDict[symbolName] = symbolDict.size() - 1;
|
||||
return symbolDict.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
printSymbolDictionary (void)
|
||||
{
|
||||
unordered_map<string, unsigned>::const_iterator it
|
||||
= symbolDict.begin();
|
||||
while (it != symbolDict.end()) {
|
||||
cout << it->first << " -> " << it->second << endl;
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const Symbol& s)
|
||||
{
|
||||
unordered_map<string, unsigned>::const_iterator it
|
||||
= LiftedUtils::symbolDict.begin();
|
||||
while (it != LiftedUtils::symbolDict.end() && it->second != s) {
|
||||
++ it;
|
||||
}
|
||||
assert (it != LiftedUtils::symbolDict.end());
|
||||
os << it->first;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const LogVar& X)
|
||||
{
|
||||
const string labels[] = {
|
||||
"A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I", "J", "K", "M" };
|
||||
(X >= 12) ? os << "X_" << X.id_ : os << labels[X];
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const Tuple& t)
|
||||
{
|
||||
os << "(" ;
|
||||
for (size_t i = 0; i < t.size(); i++) {
|
||||
os << ((i != 0) ? "," : "") << t[i];
|
||||
}
|
||||
os << ")" ;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const Ground& gr)
|
||||
{
|
||||
os << gr.functor();
|
||||
os << "(" ;
|
||||
for (size_t i = 0; i < gr.args().size(); i++) {
|
||||
if (i != 0) os << ", " ;
|
||||
os << gr.args()[i];
|
||||
}
|
||||
os << ")" ;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVars
|
||||
Substitution::getDiscardedLogVars (void) const
|
||||
{
|
||||
LogVars discardedLvs;
|
||||
set<LogVar> doneLvs;
|
||||
unordered_map<LogVar, LogVar>::const_iterator it;
|
||||
it = subs_.begin();
|
||||
while (it != subs_.end()) {
|
||||
if (Util::contains (doneLvs, it->second)) {
|
||||
discardedLvs.push_back (it->first);
|
||||
} else {
|
||||
doneLvs.insert (it->second);
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
return discardedLvs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const Substitution& theta)
|
||||
{
|
||||
unordered_map<LogVar, LogVar>::const_iterator it;
|
||||
os << "[" ;
|
||||
it = theta.subs_.begin();
|
||||
while (it != theta.subs_.end()) {
|
||||
if (it != theta.subs_.begin()) os << ", " ;
|
||||
os << it->first << "->" << it->second ;
|
||||
++ it;
|
||||
}
|
||||
os << "]" ;
|
||||
return os;
|
||||
}
|
||||
|
@ -1,166 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDUTILS_H
|
||||
#define HORUS_LIFTEDUTILS_H
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
#include "TinySet.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class Symbol
|
||||
{
|
||||
public:
|
||||
Symbol (void) : id_(Util::maxUnsigned()) { }
|
||||
|
||||
Symbol (unsigned id) : id_(id) { }
|
||||
|
||||
operator unsigned (void) const { return id_; }
|
||||
|
||||
bool valid (void) const { return id_ != Util::maxUnsigned(); }
|
||||
|
||||
static Symbol invalid (void) { return Symbol(); }
|
||||
|
||||
friend ostream& operator<< (ostream &os, const Symbol& s);
|
||||
|
||||
private:
|
||||
unsigned id_;
|
||||
};
|
||||
|
||||
|
||||
class LogVar
|
||||
{
|
||||
public:
|
||||
LogVar (void) : id_(Util::maxUnsigned()) { }
|
||||
|
||||
LogVar (unsigned id) : id_(id) { }
|
||||
|
||||
operator unsigned (void) const { return id_; }
|
||||
|
||||
LogVar& operator++ (void)
|
||||
{
|
||||
assert (valid());
|
||||
id_ ++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool valid (void) const
|
||||
{
|
||||
return id_ != Util::maxUnsigned();
|
||||
}
|
||||
|
||||
friend ostream& operator<< (ostream &os, const LogVar& X);
|
||||
|
||||
private:
|
||||
unsigned id_;
|
||||
};
|
||||
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<Symbol> {
|
||||
size_t operator() (const Symbol& s) const {
|
||||
return std::hash<unsigned>() (s);
|
||||
}};
|
||||
|
||||
template <> struct hash<LogVar> {
|
||||
size_t operator() (const LogVar& X) const {
|
||||
return std::hash<unsigned>() (X);
|
||||
}};
|
||||
};
|
||||
|
||||
|
||||
typedef vector<Symbol> Symbols;
|
||||
typedef vector<Symbol> Tuple;
|
||||
typedef vector<Tuple> Tuples;
|
||||
typedef vector<LogVar> LogVars;
|
||||
typedef TinySet<Symbol> SymbolSet;
|
||||
typedef TinySet<LogVar> LogVarSet;
|
||||
typedef TinySet<Tuple> TupleSet;
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const Tuple& t);
|
||||
|
||||
|
||||
namespace LiftedUtils {
|
||||
Symbol getSymbol (const string&);
|
||||
void printSymbolDictionary (void);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Ground
|
||||
{
|
||||
public:
|
||||
Ground (Symbol f) : functor_(f) { }
|
||||
|
||||
Ground (Symbol f, const Symbols& args) : functor_(f), args_(args) { }
|
||||
|
||||
Symbol functor (void) const { return functor_; }
|
||||
|
||||
Symbols args (void) const { return args_; }
|
||||
|
||||
size_t arity (void) const { return args_.size(); }
|
||||
|
||||
bool isAtom (void) const { return args_.size() == 0; }
|
||||
|
||||
friend ostream& operator<< (ostream &os, const Ground& gr);
|
||||
|
||||
private:
|
||||
Symbol functor_;
|
||||
Symbols args_;
|
||||
};
|
||||
|
||||
typedef vector<Ground> Grounds;
|
||||
|
||||
|
||||
|
||||
class Substitution
|
||||
{
|
||||
public:
|
||||
void add (LogVar X_old, LogVar X_new)
|
||||
{
|
||||
assert (Util::contains (subs_, X_old) == false);
|
||||
subs_.insert (make_pair (X_old, X_new));
|
||||
}
|
||||
|
||||
void rename (LogVar X_old, LogVar X_new)
|
||||
{
|
||||
assert (Util::contains (subs_, X_old));
|
||||
subs_.find (X_old)->second = X_new;
|
||||
}
|
||||
|
||||
LogVar newNameFor (LogVar X) const
|
||||
{
|
||||
unordered_map<LogVar, LogVar>::const_iterator it;
|
||||
it = subs_.find (X);
|
||||
if (it != subs_.end()) {
|
||||
return subs_.find (X)->second;
|
||||
}
|
||||
return X;
|
||||
}
|
||||
|
||||
bool containsReplacementFor (LogVar X) const
|
||||
{
|
||||
return Util::contains (subs_, X);
|
||||
}
|
||||
|
||||
size_t nrReplacements (void) const { return subs_.size(); }
|
||||
|
||||
LogVars getDiscardedLogVars (void) const;
|
||||
|
||||
friend ostream& operator<< (ostream &os, const Substitution& theta);
|
||||
|
||||
private:
|
||||
unordered_map<LogVar, LogVar> subs_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // HORUS_LIFTEDUTILS_H
|
||||
|
@ -1,728 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
#include "LiftedVe.h"
|
||||
#include "LiftedOperations.h"
|
||||
#include "Histogram.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
vector<LiftedOperator*>
|
||||
LiftedOperator::getValidOps (
|
||||
ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
vector<LiftedOperator*> validOps;
|
||||
vector<ProductOperator*> multOps;
|
||||
|
||||
multOps = ProductOperator::getValidOps (pfList);
|
||||
validOps.insert (validOps.end(), multOps.begin(), multOps.end());
|
||||
|
||||
if (Globals::verbosity > 1 || multOps.empty()) {
|
||||
vector<SumOutOperator*> sumOutOps;
|
||||
vector<CountingOperator*> countOps;
|
||||
vector<GroundOperator*> groundOps;
|
||||
sumOutOps = SumOutOperator::getValidOps (pfList, query);
|
||||
countOps = CountingOperator::getValidOps (pfList);
|
||||
groundOps = GroundOperator::getValidOps (pfList);
|
||||
validOps.insert (validOps.end(), sumOutOps.begin(), sumOutOps.end());
|
||||
validOps.insert (validOps.end(), countOps.begin(), countOps.end());
|
||||
validOps.insert (validOps.end(), groundOps.begin(), groundOps.end());
|
||||
}
|
||||
|
||||
return validOps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedOperator::printValidOps (
|
||||
ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
vector<LiftedOperator*> validOps;
|
||||
validOps = LiftedOperator::getValidOps (pfList, query);
|
||||
for (size_t i = 0; i < validOps.size(); i++) {
|
||||
cout << "-> " << validOps[i]->toString();
|
||||
delete validOps[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<ParfactorList::iterator>
|
||||
LiftedOperator::getParfactorsWithGroup (
|
||||
ParfactorList& pfList, PrvGroup group)
|
||||
{
|
||||
vector<ParfactorList::iterator> iters;
|
||||
ParfactorList::iterator pflIt = pfList.begin();
|
||||
while (pflIt != pfList.end()) {
|
||||
if ((*pflIt)->containsGroup (group)) {
|
||||
iters.push_back (pflIt);
|
||||
}
|
||||
++ pflIt;
|
||||
}
|
||||
return iters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
ProductOperator::getLogCost (void)
|
||||
{
|
||||
return std::log (0.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProductOperator::apply (void)
|
||||
{
|
||||
Parfactor* g1 = *g1_;
|
||||
Parfactor* g2 = *g2_;
|
||||
g1->multiply (*g2);
|
||||
pfList_.remove (g1_);
|
||||
pfList_.removeAndDelete (g2_);
|
||||
pfList_.addShattered (g1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<ProductOperator*>
|
||||
ProductOperator::getValidOps (ParfactorList& pfList)
|
||||
{
|
||||
vector<ProductOperator*> validOps;
|
||||
ParfactorList::iterator it1 = pfList.begin();
|
||||
ParfactorList::iterator penultimate = -- pfList.end();
|
||||
set<Parfactor*> pfs;
|
||||
while (it1 != penultimate) {
|
||||
if (Util::contains (pfs, *it1)) {
|
||||
++ it1;
|
||||
continue;
|
||||
}
|
||||
ParfactorList::iterator it2 = it1;
|
||||
++ it2;
|
||||
while (it2 != pfList.end()) {
|
||||
if (Util::contains (pfs, *it2)) {
|
||||
++ it2;
|
||||
continue;
|
||||
} else {
|
||||
if (validOp (*it1, *it2)) {
|
||||
pfs.insert (*it1);
|
||||
pfs.insert (*it2);
|
||||
validOps.push_back (new ProductOperator (
|
||||
it1, it2, pfList));
|
||||
if (Globals::verbosity < 2) {
|
||||
return validOps;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
return validOps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
ProductOperator::toString (void)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "just multiplicate " ;
|
||||
ss << (*g1_)->getAllGroups();
|
||||
ss << " x " ;
|
||||
ss << (*g2_)->getAllGroups();
|
||||
ss << " [cost=" << std::exp (getLogCost()) << "]" << endl;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ProductOperator::validOp (Parfactor* g1, Parfactor* g2)
|
||||
{
|
||||
TinySet<PrvGroup> g1_gs (g1->getAllGroups());
|
||||
TinySet<PrvGroup> g2_gs (g2->getAllGroups());
|
||||
if (g1_gs.contains (g2_gs) || g2_gs.contains (g1_gs)) {
|
||||
TinySet<PrvGroup> intersect = g1_gs & g2_gs;
|
||||
for (size_t i = 0; i < intersect.size(); i++) {
|
||||
if (g1->nrFormulasWithGroup (intersect[i]) != 1 ||
|
||||
g2->nrFormulasWithGroup (intersect[i]) != 1) {
|
||||
return false;
|
||||
}
|
||||
size_t idx1 = g1->indexOfGroup (intersect[i]);
|
||||
size_t idx2 = g2->indexOfGroup (intersect[i]);
|
||||
if (g1->range (idx1) != g2->range (idx2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return Parfactor::canMultiply (g1, g2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
SumOutOperator::getLogCost (void)
|
||||
{
|
||||
TinySet<PrvGroup> groupSet;
|
||||
ParfactorList::const_iterator pfIter = pfList_.begin();
|
||||
unsigned nrProdFactors = 0;
|
||||
while (pfIter != pfList_.end()) {
|
||||
if ((*pfIter)->containsGroup (group_)) {
|
||||
vector<PrvGroup> groups = (*pfIter)->getAllGroups();
|
||||
groupSet |= TinySet<PrvGroup> (groups);
|
||||
++ nrProdFactors;
|
||||
}
|
||||
++ pfIter;
|
||||
}
|
||||
if (nrProdFactors == 1) {
|
||||
// best possible case
|
||||
return std::log (0.0);
|
||||
}
|
||||
double cost = 1.0;
|
||||
for (size_t i = 0; i < groupSet.size(); i++) {
|
||||
pfIter = pfList_.begin();
|
||||
while (pfIter != pfList_.end()) {
|
||||
if ((*pfIter)->containsGroup (groupSet[i])) {
|
||||
size_t idx = (*pfIter)->indexOfGroup (groupSet[i]);
|
||||
cost *= (*pfIter)->range (idx);
|
||||
break;
|
||||
}
|
||||
++ pfIter;
|
||||
}
|
||||
}
|
||||
return std::log (cost);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
SumOutOperator::apply (void)
|
||||
{
|
||||
vector<ParfactorList::iterator> iters;
|
||||
iters = getParfactorsWithGroup (pfList_, group_);
|
||||
Parfactor* product = *(iters[0]);
|
||||
pfList_.remove (iters[0]);
|
||||
for (size_t i = 1; i < iters.size(); i++) {
|
||||
product->multiply (**(iters[i]));
|
||||
pfList_.removeAndDelete (iters[i]);
|
||||
}
|
||||
if (product->nrArguments() == 1) {
|
||||
delete product;
|
||||
return;
|
||||
}
|
||||
size_t fIdx = product->indexOfGroup (group_);
|
||||
LogVarSet excl = product->exclusiveLogVars (fIdx);
|
||||
if (product->constr()->isCountNormalized (excl)) {
|
||||
product->sumOutIndex (fIdx);
|
||||
pfList_.addShattered (product);
|
||||
} else {
|
||||
Parfactors pfs = LiftedOperations::countNormalize (product, excl);
|
||||
for (size_t i = 0; i < pfs.size(); i++) {
|
||||
pfs[i]->sumOutIndex (fIdx);
|
||||
pfList_.add (pfs[i]);
|
||||
}
|
||||
delete product;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<SumOutOperator*>
|
||||
SumOutOperator::getValidOps (
|
||||
ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
vector<SumOutOperator*> validOps;
|
||||
set<PrvGroup> allGroups;
|
||||
ParfactorList::const_iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
const ProbFormulas& formulas = (*it)->arguments();
|
||||
for (size_t i = 0; i < formulas.size(); i++) {
|
||||
allGroups.insert (formulas[i].group());
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
set<PrvGroup>::const_iterator groupIt = allGroups.begin();
|
||||
while (groupIt != allGroups.end()) {
|
||||
if (validOp (*groupIt, pfList, query)) {
|
||||
validOps.push_back (new SumOutOperator (*groupIt, pfList));
|
||||
}
|
||||
++ groupIt;
|
||||
}
|
||||
return validOps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
SumOutOperator::toString (void)
|
||||
{
|
||||
stringstream ss;
|
||||
vector<ParfactorList::iterator> pfIters;
|
||||
pfIters = getParfactorsWithGroup (pfList_, group_);
|
||||
size_t idx = (*pfIters[0])->indexOfGroup (group_);
|
||||
ProbFormula f = (*pfIters[0])->argument (idx);
|
||||
TupleSet tupleSet = (*pfIters[0])->constr()->tupleSet (f.logVars());
|
||||
ss << "sum out " << f.functor() << "/" << f.arity();
|
||||
ss << "|" << tupleSet << " (group " << group_ << ")";
|
||||
ss << " [cost=" << std::exp (getLogCost()) << "]" << endl;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
SumOutOperator::validOp (
|
||||
PrvGroup group,
|
||||
ParfactorList& pfList,
|
||||
const Grounds& query)
|
||||
{
|
||||
vector<ParfactorList::iterator> pfIters;
|
||||
pfIters = getParfactorsWithGroup (pfList, group);
|
||||
if (isToEliminate (*pfIters[0], group, query) == false) {
|
||||
return false;
|
||||
}
|
||||
int range = -1;
|
||||
for (size_t i = 0; i < pfIters.size(); i++) {
|
||||
if ((*pfIters[i])->nrFormulasWithGroup (group) > 1) {
|
||||
return false;
|
||||
}
|
||||
size_t fIdx = (*pfIters[i])->indexOfGroup (group);
|
||||
if ((*pfIters[i])->argument (fIdx).contains (
|
||||
(*pfIters[i])->elimLogVars()) == false) {
|
||||
return false;
|
||||
}
|
||||
if (range == -1) {
|
||||
range = (*pfIters[i])->range (fIdx);
|
||||
} else if ((int)(*pfIters[i])->range (fIdx) != range) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
SumOutOperator::isToEliminate (
|
||||
Parfactor* g,
|
||||
PrvGroup group,
|
||||
const Grounds& query)
|
||||
{
|
||||
size_t fIdx = g->indexOfGroup (group);
|
||||
const ProbFormula& formula = g->argument (fIdx);
|
||||
bool toElim = true;
|
||||
for (size_t i = 0; i < query.size(); i++) {
|
||||
if (formula.functor() == query[i].functor() &&
|
||||
formula.arity() == query[i].arity()) {
|
||||
g->constr()->moveToTop (formula.logVars());
|
||||
if (g->constr()->containsTuple (query[i].args())) {
|
||||
toElim = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return toElim;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
CountingOperator::getLogCost (void)
|
||||
{
|
||||
double cost = 0.0;
|
||||
size_t fIdx = (*pfIter_)->indexOfLogVar (X_);
|
||||
unsigned range = (*pfIter_)->range (fIdx);
|
||||
unsigned size = (*pfIter_)->size() / range;
|
||||
TinySet<unsigned> counts;
|
||||
counts = (*pfIter_)->constr()->getConditionalCounts (X_);
|
||||
for (size_t i = 0; i < counts.size(); i++) {
|
||||
cost += size * HistogramSet::nrHistograms (counts[i], range);
|
||||
}
|
||||
PrvGroup group = (*pfIter_)->argument (fIdx).group();
|
||||
size_t lvIndex = Util::indexOf (
|
||||
(*pfIter_)->argument (fIdx).logVars(), X_);
|
||||
assert (lvIndex != (*pfIter_)->argument (fIdx).logVars().size());
|
||||
ParfactorList::iterator pfIter = pfList_.begin();
|
||||
while (pfIter != pfList_.end()) {
|
||||
if (pfIter != pfIter_) {
|
||||
size_t fIdx2 = (*pfIter)->indexOfGroup (group);
|
||||
if (fIdx2 != (*pfIter)->nrArguments()) {
|
||||
LogVar Y = ((*pfIter)->argument (fIdx2).logVars()[lvIndex]);
|
||||
if ((*pfIter)->canCountConvert (Y) == false) {
|
||||
// the real cost should be the cost of grounding Y
|
||||
cost *= 10.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
++ pfIter;
|
||||
}
|
||||
return std::log (cost);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CountingOperator::apply (void)
|
||||
{
|
||||
if ((*pfIter_)->constr()->isCountNormalized (X_)) {
|
||||
(*pfIter_)->countConvert (X_);
|
||||
} else {
|
||||
Parfactor* pf = *pfIter_;
|
||||
pfList_.remove (pfIter_);
|
||||
Parfactors pfs = LiftedOperations::countNormalize (pf, X_);
|
||||
for (size_t i = 0; i < pfs.size(); i++) {
|
||||
unsigned condCount = pfs[i]->constr()->getConditionalCount (X_);
|
||||
bool cartProduct = pfs[i]->constr()->isCartesianProduct (
|
||||
pfs[i]->countedLogVars() | X_);
|
||||
if (condCount > 1 && cartProduct) {
|
||||
pfs[i]->countConvert (X_);
|
||||
}
|
||||
pfList_.add (pfs[i]);
|
||||
}
|
||||
delete pf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<CountingOperator*>
|
||||
CountingOperator::getValidOps (ParfactorList& pfList)
|
||||
{
|
||||
vector<CountingOperator*> validOps;
|
||||
ParfactorList::iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
LogVarSet candidates = (*it)->uncountedLogVars();
|
||||
for (size_t i = 0; i < candidates.size(); i++) {
|
||||
if (validOp (*it, candidates[i])) {
|
||||
validOps.push_back (new CountingOperator (
|
||||
it, candidates[i], pfList));
|
||||
} else {
|
||||
}
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
return validOps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
CountingOperator::toString (void)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "count convert " << X_ << " in " ;
|
||||
ss << (*pfIter_)->getLabel();
|
||||
ss << " [cost=" << std::exp (getLogCost()) << "]" << endl;
|
||||
Parfactors pfs = LiftedOperations::countNormalize (*pfIter_, X_);
|
||||
if ((*pfIter_)->constr()->isCountNormalized (X_) == false) {
|
||||
for (size_t i = 0; i < pfs.size(); i++) {
|
||||
ss << " º " << pfs[i]->getLabel() << endl;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < pfs.size(); i++) {
|
||||
delete pfs[i];
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
CountingOperator::validOp (Parfactor* g, LogVar X)
|
||||
{
|
||||
if (g->nrFormulas (X) != 1) {
|
||||
return false;
|
||||
}
|
||||
size_t fIdx = g->indexOfLogVar (X);
|
||||
if (g->argument (fIdx).isCounting()) {
|
||||
return false;
|
||||
}
|
||||
bool countNormalized = g->constr()->isCountNormalized (X);
|
||||
if (countNormalized) {
|
||||
return g->canCountConvert (X);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
GroundOperator::getLogCost (void)
|
||||
{
|
||||
vector<pair<PrvGroup, unsigned>> affectedFormulas;
|
||||
affectedFormulas = getAffectedFormulas();
|
||||
// cout << "affected formulas: " ;
|
||||
// for (size_t i = 0; i < affectedFormulas.size(); i++) {
|
||||
// cout << affectedFormulas[i].first << ":" ;
|
||||
// cout << affectedFormulas[i].second << " " ;
|
||||
// }
|
||||
// cout << "cost =" ;
|
||||
double totalCost = std::log (0.0);
|
||||
ParfactorList::iterator pflIt = pfList_.begin();
|
||||
while (pflIt != pfList_.end()) {
|
||||
Parfactor* pf = *pflIt;
|
||||
double reps = 0.0;
|
||||
double pfSize = std::log (pf->size());
|
||||
bool willBeAffected = false;
|
||||
LogVarSet lvsToGround;
|
||||
for (size_t i = 0; i < affectedFormulas.size(); i++) {
|
||||
size_t fIdx = pf->indexOfGroup (affectedFormulas[i].first);
|
||||
if (fIdx != pf->nrArguments()) {
|
||||
ProbFormula f = pf->argument (fIdx);
|
||||
LogVar X = f.logVars()[affectedFormulas[i].second];
|
||||
bool isCountingLv = pf->countedLogVars().contains (X);
|
||||
if (isCountingLv) {
|
||||
unsigned nrHists = pf->range (fIdx);
|
||||
unsigned nrSymbols = pf->constr()->getConditionalCount (X);
|
||||
unsigned range = pf->argument (fIdx).range();
|
||||
double power = std::log (range) * nrSymbols;
|
||||
pfSize = (pfSize - std::log (nrHists)) + power;
|
||||
} else {
|
||||
if (lvsToGround.contains (X) == false) {
|
||||
reps += std::log (pf->constr()->nrSymbols (X));
|
||||
lvsToGround.insert (X);
|
||||
}
|
||||
}
|
||||
willBeAffected = true;
|
||||
}
|
||||
}
|
||||
if (willBeAffected) {
|
||||
// cout << " + " << std::exp (reps) << "x" << std::exp (pfSize);
|
||||
double pfCost = reps + pfSize;
|
||||
totalCost = Util::logSum (totalCost, pfCost);
|
||||
}
|
||||
++ pflIt;
|
||||
}
|
||||
// cout << endl;
|
||||
return totalCost + 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
GroundOperator::apply (void)
|
||||
{
|
||||
ParfactorList::iterator pfIter;
|
||||
pfIter = getParfactorsWithGroup (pfList_, group_).front();
|
||||
Parfactor* pf = *pfIter;
|
||||
size_t idx = pf->indexOfGroup (group_);
|
||||
ProbFormula f = pf->argument (idx);
|
||||
LogVar X = f.logVars()[lvIndex_];
|
||||
bool countedLv = pf->countedLogVars().contains (X);
|
||||
pfList_.remove (pfIter);
|
||||
if (countedLv) {
|
||||
pf->fullExpand (X);
|
||||
pfList_.add (pf);
|
||||
} else {
|
||||
ConstraintTrees cts = pf->constr()->ground (X);
|
||||
for (size_t i = 0; i < cts.size(); i++) {
|
||||
pfList_.add (new Parfactor (pf, cts[i]));
|
||||
}
|
||||
delete pf;
|
||||
}
|
||||
ParfactorList::iterator pflIt = pfList_.begin();
|
||||
while (pflIt != pfList_.end()) {
|
||||
(*pflIt)->simplifyGrounds();
|
||||
++ pflIt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<GroundOperator*>
|
||||
GroundOperator::getValidOps (ParfactorList& pfList)
|
||||
{
|
||||
vector<GroundOperator*> validOps;
|
||||
set<PrvGroup> allGroups;
|
||||
ParfactorList::const_iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
const ProbFormulas& formulas = (*it)->arguments();
|
||||
for (size_t i = 0; i < formulas.size(); i++) {
|
||||
if (Util::contains (allGroups, formulas[i].group()) == false) {
|
||||
const LogVars& lvs = formulas[i].logVars();
|
||||
for (size_t j = 0; j < lvs.size(); j++) {
|
||||
if ((*it)->constr()->isSingleton (lvs[j]) == false) {
|
||||
validOps.push_back (new GroundOperator (
|
||||
formulas[i].group(), j, pfList));
|
||||
}
|
||||
}
|
||||
allGroups.insert (formulas[i].group());
|
||||
}
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
return validOps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
GroundOperator::toString (void)
|
||||
{
|
||||
stringstream ss;
|
||||
vector<ParfactorList::iterator> pfIters;
|
||||
pfIters = getParfactorsWithGroup (pfList_, group_);
|
||||
Parfactor* pf = *(getParfactorsWithGroup (pfList_, group_).front());
|
||||
size_t idx = pf->indexOfGroup (group_);
|
||||
ProbFormula f = pf->argument (idx);
|
||||
LogVar lv = f.logVars()[lvIndex_];
|
||||
TupleSet tupleSet = pf->constr()->tupleSet ({lv});
|
||||
string pos = "th";
|
||||
if (lvIndex_ == 0) {
|
||||
pos = "st" ;
|
||||
} else if (lvIndex_ == 1) {
|
||||
pos = "nd" ;
|
||||
} else if (lvIndex_ == 2) {
|
||||
pos = "rd" ;
|
||||
}
|
||||
ss << "grounding " << lvIndex_ + 1 << pos << " log var in " ;
|
||||
ss << f.functor() << "/" << f.arity();
|
||||
ss << "|" << tupleSet << " (group " << group_ << ")";
|
||||
ss << " [cost=" << std::exp (getLogCost()) << "]" << endl;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<pair<PrvGroup, unsigned>>
|
||||
GroundOperator::getAffectedFormulas (void)
|
||||
{
|
||||
vector<pair<PrvGroup, unsigned>> affectedFormulas;
|
||||
affectedFormulas.push_back (make_pair (group_, lvIndex_));
|
||||
queue<pair<PrvGroup, unsigned>> q;
|
||||
q.push (make_pair (group_, lvIndex_));
|
||||
while (q.empty() == false) {
|
||||
pair<PrvGroup, unsigned> front = q.front();
|
||||
ParfactorList::iterator pflIt = pfList_.begin();
|
||||
while (pflIt != pfList_.end()) {
|
||||
size_t idx = (*pflIt)->indexOfGroup (front.first);
|
||||
if (idx != (*pflIt)->nrArguments()) {
|
||||
ProbFormula f = (*pflIt)->argument (idx);
|
||||
LogVar X = f.logVars()[front.second];
|
||||
const ProbFormulas& fs = (*pflIt)->arguments();
|
||||
for (size_t i = 0; i < fs.size(); i++) {
|
||||
if (i != idx && fs[i].contains (X)) {
|
||||
pair<PrvGroup, unsigned> pair = make_pair (
|
||||
fs[i].group(), fs[i].indexOf (X));
|
||||
if (Util::contains (affectedFormulas, pair) == false) {
|
||||
q.push (pair);
|
||||
affectedFormulas.push_back (pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++ pflIt;
|
||||
}
|
||||
q.pop();
|
||||
}
|
||||
return affectedFormulas;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
LiftedVe::solveQuery (const Grounds& query)
|
||||
{
|
||||
assert (query.empty() == false);
|
||||
pfList_ = parfactorList;
|
||||
runSolver (query);
|
||||
(*pfList_.begin())->normalize();
|
||||
Params params = (*pfList_.begin())->params();
|
||||
if (Globals::logDomain) {
|
||||
Util::exp (params);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedVe::printSolverFlags (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "lve [" ;
|
||||
ss << "log_domain=" << Util::toString (Globals::logDomain);
|
||||
ss << "]" ;
|
||||
cout << ss.str() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedVe::runSolver (const Grounds& query)
|
||||
{
|
||||
largestCost_ = std::log (0);
|
||||
LiftedOperations::shatterAgainstQuery (pfList_, query);
|
||||
LiftedOperations::runWeakBayesBall (pfList_, query);
|
||||
while (true) {
|
||||
if (Globals::verbosity > 2) {
|
||||
Util::printDashedLine();
|
||||
pfList_.print();
|
||||
if (Globals::verbosity > 3) {
|
||||
LiftedOperator::printValidOps (pfList_, query);
|
||||
}
|
||||
}
|
||||
LiftedOperator* op = getBestOperation (query);
|
||||
if (op == 0) {
|
||||
break;
|
||||
}
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "best operation: " << op->toString();
|
||||
if (Globals::verbosity > 2) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
op->apply();
|
||||
delete op;
|
||||
}
|
||||
assert (pfList_.size() > 0);
|
||||
if (pfList_.size() > 1) {
|
||||
ParfactorList::iterator pfIter = pfList_.begin();
|
||||
++ pfIter;
|
||||
while (pfIter != pfList_.end()) {
|
||||
(*pfList_.begin())->multiply (**pfIter);
|
||||
++ pfIter;
|
||||
}
|
||||
}
|
||||
if (Globals::verbosity > 0) {
|
||||
cout << "largest cost = " << std::exp (largestCost_) << endl;
|
||||
cout << endl;
|
||||
}
|
||||
(*pfList_.begin())->simplifyGrounds();
|
||||
(*pfList_.begin())->reorderAccordingGrounds (query);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LiftedOperator*
|
||||
LiftedVe::getBestOperation (const Grounds& query)
|
||||
{
|
||||
double bestCost = 0.0;
|
||||
LiftedOperator* bestOp = 0;
|
||||
vector<LiftedOperator*> validOps;
|
||||
validOps = LiftedOperator::getValidOps (pfList_, query);
|
||||
for (size_t i = 0; i < validOps.size(); i++) {
|
||||
double cost = validOps[i]->getLogCost();
|
||||
if ((bestOp == 0) || (cost < bestCost)) {
|
||||
bestOp = validOps[i];
|
||||
bestCost = cost;
|
||||
}
|
||||
}
|
||||
if (bestCost > largestCost_) {
|
||||
largestCost_ = bestCost;
|
||||
}
|
||||
for (size_t i = 0; i < validOps.size(); i++) {
|
||||
if (validOps[i] != bestOp) {
|
||||
delete validOps[i];
|
||||
}
|
||||
}
|
||||
return bestOp;
|
||||
}
|
||||
|
@ -1,155 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDVE_H
|
||||
#define HORUS_LIFTEDVE_H
|
||||
|
||||
#include "LiftedSolver.h"
|
||||
#include "ParfactorList.h"
|
||||
|
||||
|
||||
class LiftedOperator
|
||||
{
|
||||
public:
|
||||
virtual ~LiftedOperator (void) { }
|
||||
|
||||
virtual double getLogCost (void) = 0;
|
||||
|
||||
virtual void apply (void) = 0;
|
||||
|
||||
virtual string toString (void) = 0;
|
||||
|
||||
static vector<LiftedOperator*> getValidOps (
|
||||
ParfactorList&, const Grounds&);
|
||||
|
||||
static void printValidOps (ParfactorList&, const Grounds&);
|
||||
|
||||
static vector<ParfactorList::iterator> getParfactorsWithGroup (
|
||||
ParfactorList&, PrvGroup group);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ProductOperator : public LiftedOperator
|
||||
{
|
||||
public:
|
||||
ProductOperator (
|
||||
ParfactorList::iterator g1, ParfactorList::iterator g2,
|
||||
ParfactorList& pfList) : g1_(g1), g2_(g2), pfList_(pfList) { }
|
||||
|
||||
double getLogCost (void);
|
||||
|
||||
void apply (void);
|
||||
|
||||
static vector<ProductOperator*> getValidOps (ParfactorList&);
|
||||
|
||||
string toString (void);
|
||||
|
||||
private:
|
||||
static bool validOp (Parfactor*, Parfactor*);
|
||||
|
||||
ParfactorList::iterator g1_;
|
||||
ParfactorList::iterator g2_;
|
||||
ParfactorList& pfList_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SumOutOperator : public LiftedOperator
|
||||
{
|
||||
public:
|
||||
SumOutOperator (PrvGroup group, ParfactorList& pfList)
|
||||
: group_(group), pfList_(pfList) { }
|
||||
|
||||
double getLogCost (void);
|
||||
|
||||
void apply (void);
|
||||
|
||||
static vector<SumOutOperator*> getValidOps (
|
||||
ParfactorList&, const Grounds&);
|
||||
|
||||
string toString (void);
|
||||
|
||||
private:
|
||||
static bool validOp (PrvGroup, ParfactorList&, const Grounds&);
|
||||
|
||||
static bool isToEliminate (Parfactor*, PrvGroup, const Grounds&);
|
||||
|
||||
PrvGroup group_;
|
||||
ParfactorList& pfList_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CountingOperator : public LiftedOperator
|
||||
{
|
||||
public:
|
||||
CountingOperator (
|
||||
ParfactorList::iterator pfIter,
|
||||
LogVar X,
|
||||
ParfactorList& pfList)
|
||||
: pfIter_(pfIter), X_(X), pfList_(pfList) { }
|
||||
|
||||
double getLogCost (void);
|
||||
|
||||
void apply (void);
|
||||
|
||||
static vector<CountingOperator*> getValidOps (ParfactorList&);
|
||||
|
||||
string toString (void);
|
||||
|
||||
private:
|
||||
static bool validOp (Parfactor*, LogVar);
|
||||
|
||||
ParfactorList::iterator pfIter_;
|
||||
LogVar X_;
|
||||
ParfactorList& pfList_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class GroundOperator : public LiftedOperator
|
||||
{
|
||||
public:
|
||||
GroundOperator (
|
||||
PrvGroup group,
|
||||
unsigned lvIndex,
|
||||
ParfactorList& pfList)
|
||||
: group_(group), lvIndex_(lvIndex), pfList_(pfList) { }
|
||||
|
||||
double getLogCost (void);
|
||||
|
||||
void apply (void);
|
||||
|
||||
static vector<GroundOperator*> getValidOps (ParfactorList&);
|
||||
|
||||
string toString (void);
|
||||
|
||||
private:
|
||||
vector<pair<PrvGroup, unsigned>> getAffectedFormulas (void);
|
||||
|
||||
PrvGroup group_;
|
||||
unsigned lvIndex_;
|
||||
ParfactorList& pfList_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LiftedVe : public LiftedSolver
|
||||
{
|
||||
public:
|
||||
LiftedVe (const ParfactorList& pfList)
|
||||
: LiftedSolver(pfList) { }
|
||||
|
||||
Params solveQuery (const Grounds&);
|
||||
|
||||
void printSolverFlags (void) const;
|
||||
|
||||
private:
|
||||
void runSolver (const Grounds&);
|
||||
|
||||
LiftedOperator* getBestOperation (const Grounds&);
|
||||
|
||||
ParfactorList pfList_;
|
||||
double largestCost_;
|
||||
};
|
||||
|
||||
#endif // HORUS_LIFTEDVE_H
|
||||
|
@ -1,658 +0,0 @@
|
||||
#include "LiftedWCNF.h"
|
||||
#include "ConstraintTree.h"
|
||||
#include "Indexer.h"
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Literal::isGround (ConstraintTree constr, LogVarSet ipgLogVars) const
|
||||
{
|
||||
if (logVars_.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
LogVarSet lvs (logVars_);
|
||||
lvs -= ipgLogVars;
|
||||
return constr.singletons().contains (lvs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t
|
||||
Literal::indexOfLogVar (LogVar X) const
|
||||
{
|
||||
return Util::indexOf (logVars_, X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
Literal::toString (
|
||||
LogVarSet ipgLogVars,
|
||||
LogVarSet posCountedLvs,
|
||||
LogVarSet negCountedLvs) const
|
||||
{
|
||||
stringstream ss;
|
||||
negated_ ? ss << "¬" : ss << "" ;
|
||||
ss << "λ" ;
|
||||
ss << lid_ ;
|
||||
if (logVars_.empty() == false) {
|
||||
ss << "(" ;
|
||||
for (size_t i = 0; i < logVars_.size(); i++) {
|
||||
if (i != 0) ss << ",";
|
||||
if (posCountedLvs.contains (logVars_[i])) {
|
||||
ss << "+" << logVars_[i];
|
||||
} else if (negCountedLvs.contains (logVars_[i])) {
|
||||
ss << "-" << logVars_[i];
|
||||
} else if (ipgLogVars.contains (logVars_[i])) {
|
||||
LogVar X = logVars_[i];
|
||||
const string labels[] = {
|
||||
"a", "b", "c", "d", "e", "f",
|
||||
"g", "h", "i", "j", "k", "m" };
|
||||
(X >= 12) ? ss << "x_" << X : ss << labels[X];
|
||||
} else {
|
||||
ss << logVars_[i];
|
||||
}
|
||||
}
|
||||
ss << ")" ;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostream&
|
||||
operator<< (ostream &os, const Literal& lit)
|
||||
{
|
||||
os << lit.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::addLiteralComplemented (const Literal& lit)
|
||||
{
|
||||
assert (constr_.logVarSet().contains (lit.logVars()));
|
||||
literals_.push_back (lit);
|
||||
literals_.back().complement();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::containsLiteral (LiteralId lid) const
|
||||
{
|
||||
for (size_t i = 0; i < literals_.size(); i++) {
|
||||
if (literals_[i].lid() == lid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::containsPositiveLiteral (
|
||||
LiteralId lid,
|
||||
const LogVarTypes& types) const
|
||||
{
|
||||
for (size_t i = 0; i < literals_.size(); i++) {
|
||||
if (literals_[i].lid() == lid
|
||||
&& literals_[i].isPositive()
|
||||
&& logVarTypes (i) == types) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::containsNegativeLiteral (
|
||||
LiteralId lid,
|
||||
const LogVarTypes& types) const
|
||||
{
|
||||
for (size_t i = 0; i < literals_.size(); i++) {
|
||||
if (literals_[i].lid() == lid
|
||||
&& literals_[i].isNegative()
|
||||
&& logVarTypes (i) == types) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::removeLiterals (LiteralId lid)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i != literals_.size()) {
|
||||
if (literals_[i].lid() == lid) {
|
||||
removeLiteral (i);
|
||||
} else {
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::removePositiveLiterals (
|
||||
LiteralId lid,
|
||||
const LogVarTypes& types)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i != literals_.size()) {
|
||||
if (literals_[i].lid() == lid
|
||||
&& literals_[i].isPositive()
|
||||
&& logVarTypes (i) == types) {
|
||||
removeLiteral (i);
|
||||
} else {
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::removeNegativeLiterals (
|
||||
LiteralId lid,
|
||||
const LogVarTypes& types)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i != literals_.size()) {
|
||||
if (literals_[i].lid() == lid
|
||||
&& literals_[i].isNegative()
|
||||
&& logVarTypes (i) == types) {
|
||||
removeLiteral (i);
|
||||
} else {
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::isCountedLogVar (LogVar X) const
|
||||
{
|
||||
assert (constr_.logVarSet().contains (X));
|
||||
return posCountedLvs_.contains (X)
|
||||
|| negCountedLvs_.contains (X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::isPositiveCountedLogVar (LogVar X) const
|
||||
{
|
||||
assert (constr_.logVarSet().contains (X));
|
||||
return posCountedLvs_.contains (X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::isNegativeCountedLogVar (LogVar X) const
|
||||
{
|
||||
assert (constr_.logVarSet().contains (X));
|
||||
return negCountedLvs_.contains (X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::isIpgLogVar (LogVar X) const
|
||||
{
|
||||
assert (constr_.logVarSet().contains (X));
|
||||
return ipgLvs_.contains (X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TinySet<LiteralId>
|
||||
Clause::lidSet (void) const
|
||||
{
|
||||
TinySet<LiteralId> lidSet;
|
||||
for (size_t i = 0; i < literals_.size(); i++) {
|
||||
lidSet.insert (literals_[i].lid());
|
||||
}
|
||||
return lidSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarSet
|
||||
Clause::ipgCandidates (void) const
|
||||
{
|
||||
LogVarSet candidates;
|
||||
LogVarSet allLvs = constr_.logVarSet();
|
||||
allLvs -= ipgLvs_;
|
||||
allLvs -= posCountedLvs_;
|
||||
allLvs -= negCountedLvs_;
|
||||
for (size_t i = 0; i < allLvs.size(); i++) {
|
||||
bool valid = true;
|
||||
for (size_t j = 0; j < literals_.size(); j++) {
|
||||
if (Util::contains (literals_[j].logVars(), allLvs[i]) == false) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
candidates.insert (allLvs[i]);
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarTypes
|
||||
Clause::logVarTypes (size_t litIdx) const
|
||||
{
|
||||
LogVarTypes types;
|
||||
const LogVars& lvs = literals_[litIdx].logVars();
|
||||
for (size_t i = 0; i < lvs.size(); i++) {
|
||||
if (posCountedLvs_.contains (lvs[i])) {
|
||||
types.push_back (LogVarType::POS_LV);
|
||||
} else if (negCountedLvs_.contains (lvs[i])) {
|
||||
types.push_back (LogVarType::NEG_LV);
|
||||
} else {
|
||||
types.push_back (LogVarType::FULL_LV);
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::removeLiteral (size_t litIdx)
|
||||
{
|
||||
LogVarSet lvsToRemove = literals_[litIdx].logVarSet()
|
||||
- getLogVarSetExcluding (litIdx);
|
||||
ipgLvs_ -= lvsToRemove;
|
||||
posCountedLvs_ -= lvsToRemove;
|
||||
negCountedLvs_ -= lvsToRemove;
|
||||
constr_.remove (lvsToRemove);
|
||||
literals_.erase (literals_.begin() + litIdx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Clause::independentClauses (Clause& c1, Clause& c2)
|
||||
{
|
||||
const Literals& lits1 = c1.literals();
|
||||
const Literals& lits2 = c2.literals();
|
||||
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()
|
||||
&& c1.logVarTypes (i) == c2.logVarTypes (j)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Clauses
|
||||
Clause::copyClauses (const Clauses& clauses)
|
||||
{
|
||||
Clauses copy;
|
||||
copy.reserve (clauses.size());
|
||||
for (size_t i = 0; i < clauses.size(); i++) {
|
||||
copy.push_back (new Clause (*clauses[i]));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::printClauses (const Clauses& clauses)
|
||||
{
|
||||
for (size_t i = 0; i < clauses.size(); i++) {
|
||||
cout << *clauses[i] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Clause::deleteClauses (Clauses& clauses)
|
||||
{
|
||||
for (size_t i = 0; i < clauses.size(); i++) {
|
||||
delete clauses[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostream&
|
||||
operator<< (ostream &os, const Clause& clause)
|
||||
{
|
||||
for (unsigned i = 0; i < clause.literals_.size(); i++) {
|
||||
if (i != 0) os << " v " ;
|
||||
os << clause.literals_[i].toString (clause.ipgLvs_,
|
||||
clause.posCountedLvs_, clause.negCountedLvs_);
|
||||
}
|
||||
if (clause.constr_.empty() == false) {
|
||||
ConstraintTree copy (clause.constr_);
|
||||
copy.moveToTop (copy.logVarSet().elements());
|
||||
os << " | " << copy.tupleSet();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarSet
|
||||
Clause::getLogVarSetExcluding (size_t idx) const
|
||||
{
|
||||
LogVarSet lvs;
|
||||
for (size_t i = 0; i < literals_.size(); i++) {
|
||||
if (i != idx) {
|
||||
lvs |= literals_[i].logVars();
|
||||
}
|
||||
}
|
||||
return lvs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostream&
|
||||
operator<< (std::ostream &os, const LitLvTypes& lit)
|
||||
{
|
||||
os << lit.lid_ << "<" ;
|
||||
for (size_t i = 0; i < lit.lvTypes_.size(); i++) {
|
||||
switch (lit.lvTypes_[i]) {
|
||||
case LogVarType::FULL_LV: os << "F" ; break;
|
||||
case LogVarType::POS_LV: os << "P" ; break;
|
||||
case LogVarType::NEG_LV: os << "N" ; break;
|
||||
}
|
||||
}
|
||||
os << ">" ;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LiftedWCNF::LiftedWCNF (const ParfactorList& pfList)
|
||||
: freeLiteralId_(0), pfList_(pfList)
|
||||
{
|
||||
addIndicatorClauses (pfList);
|
||||
addParameterClauses (pfList);
|
||||
|
||||
/*
|
||||
// INCLUSION-EXCLUSION TEST
|
||||
clauses_.clear();
|
||||
vector<vector<string>> names = {
|
||||
{"a1","b1"},{"a2","b2"}
|
||||
};
|
||||
Clause* c1 = new Clause (names);
|
||||
c1->addLiteral (Literal (0, LogVars() = {0}));
|
||||
c1->addLiteral (Literal (1, LogVars() = {1}));
|
||||
clauses_.push_back(c1);
|
||||
*/
|
||||
|
||||
/*
|
||||
// INDEPENDENT PARTIAL GROUND TEST
|
||||
clauses_.clear();
|
||||
vector<vector<string>> names = {
|
||||
{"a1","b1"},{"a2","b2"}
|
||||
};
|
||||
Clause* c1 = new Clause (names);
|
||||
c1->addLiteral (Literal (0, LogVars() = {0,1}));
|
||||
c1->addLiteral (Literal (1, LogVars() = {0,1}));
|
||||
clauses_.push_back(c1);
|
||||
Clause* c2 = new Clause (names);
|
||||
c2->addLiteral (Literal (2, LogVars() = {0}));
|
||||
c2->addLiteral (Literal (1, LogVars() = {0,1}));
|
||||
clauses_.push_back(c2);
|
||||
*/
|
||||
|
||||
/*
|
||||
// ATOM-COUNTING TEST
|
||||
clauses_.clear();
|
||||
vector<vector<string>> names = {
|
||||
{"p1","p1"},{"p1","p2"},{"p1","p3"},
|
||||
{"p2","p1"},{"p2","p2"},{"p2","p3"},
|
||||
{"p3","p1"},{"p3","p2"},{"p3","p3"}
|
||||
};
|
||||
Clause* c1 = new Clause (names);
|
||||
c1->addLiteral (Literal (0, LogVars() = {0}));
|
||||
c1->addLiteralComplemented (Literal (1, {0,1}));
|
||||
clauses_.push_back(c1);
|
||||
Clause* c2 = new Clause (names);
|
||||
c2->addLiteral (Literal (0, LogVars()={0}));
|
||||
c2->addLiteralComplemented (Literal (1, {1,0}));
|
||||
clauses_.push_back(c2);
|
||||
*/
|
||||
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "FORMULA INDICATORS:" << endl;
|
||||
printFormulaIndicators();
|
||||
cout << endl;
|
||||
cout << "WEIGHTED INDICATORS:" << endl;
|
||||
printWeights();
|
||||
cout << endl;
|
||||
cout << "CLAUSES:" << endl;
|
||||
printClauses();
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LiftedWCNF::~LiftedWCNF (void)
|
||||
{
|
||||
Clause::deleteClauses (clauses_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedWCNF::addWeight (LiteralId lid, double posW, double negW)
|
||||
{
|
||||
weights_[lid] = make_pair (posW, negW);
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
LiftedWCNF::posWeight (LiteralId lid) const
|
||||
{
|
||||
unordered_map<LiteralId, std::pair<double,double>>::const_iterator it;
|
||||
it = weights_.find (lid);
|
||||
return it != weights_.end() ? it->second.first : LogAware::one();
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
LiftedWCNF::negWeight (LiteralId lid) const
|
||||
{
|
||||
unordered_map<LiteralId, std::pair<double,double>>::const_iterator it;
|
||||
it = weights_.find (lid);
|
||||
return it != weights_.end() ? it->second.second : LogAware::one();
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<LiteralId>
|
||||
LiftedWCNF::prvGroupLiterals (PrvGroup prvGroup)
|
||||
{
|
||||
assert (Util::contains (map_, prvGroup));
|
||||
return map_[prvGroup];
|
||||
}
|
||||
|
||||
|
||||
|
||||
Clause*
|
||||
LiftedWCNF::createClause (LiteralId lid) const
|
||||
{
|
||||
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].lid() == lid) {
|
||||
ConstraintTree ct = clauses_[i]->constr().projectedCopy (
|
||||
literals[j].logVars());
|
||||
Clause* c = new Clause (ct);
|
||||
c->addLiteral (literals[j]);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LiteralId
|
||||
LiftedWCNF::getLiteralId (PrvGroup prvGroup, unsigned range)
|
||||
{
|
||||
assert (Util::contains (map_, prvGroup));
|
||||
return map_[prvGroup][range];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedWCNF::addIndicatorClauses (const ParfactorList& pfList)
|
||||
{
|
||||
ParfactorList::const_iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
const ProbFormulas& formulas = (*it)->arguments();
|
||||
for (size_t i = 0; i < formulas.size(); i++) {
|
||||
if (Util::contains (map_, formulas[i].group()) == false) {
|
||||
ConstraintTree tempConstr = (*it)->constr()->projectedCopy(
|
||||
formulas[i].logVars());
|
||||
Clause* clause = new Clause (tempConstr);
|
||||
vector<LiteralId> lids;
|
||||
for (size_t j = 0; j < formulas[i].range(); j++) {
|
||||
clause->addLiteral (Literal (freeLiteralId_, formulas[i].logVars()));
|
||||
lids.push_back (freeLiteralId_);
|
||||
freeLiteralId_ ++;
|
||||
}
|
||||
clauses_.push_back (clause);
|
||||
for (size_t j = 0; j < formulas[i].range() - 1; j++) {
|
||||
for (size_t k = j + 1; k < formulas[i].range(); k++) {
|
||||
ConstraintTree tempConstr2 = (*it)->constr()->projectedCopy (
|
||||
formulas[i].logVars());
|
||||
Clause* clause2 = new Clause (tempConstr2);
|
||||
clause2->addLiteralComplemented (Literal (clause->literals()[j]));
|
||||
clause2->addLiteralComplemented (Literal (clause->literals()[k]));
|
||||
clauses_.push_back (clause2);
|
||||
}
|
||||
}
|
||||
map_[formulas[i].group()] = lids;
|
||||
}
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedWCNF::addParameterClauses (const ParfactorList& pfList)
|
||||
{
|
||||
ParfactorList::const_iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
Indexer indexer ((*it)->ranges());
|
||||
vector<PrvGroup> groups = (*it)->getAllGroups();
|
||||
while (indexer.valid()) {
|
||||
LiteralId paramVarLid = freeLiteralId_;
|
||||
// λu1 ∧ ... ∧ λun ∧ λxi <=> θxi|u1,...,un
|
||||
//
|
||||
// ¬λu1 ... ¬λun v θxi|u1,...,un -> clause1
|
||||
// ¬θxi|u1,...,un v λu1 -> tempClause
|
||||
// ¬θxi|u1,...,un v λu2 -> tempClause
|
||||
double posWeight = (**it)[indexer];
|
||||
addWeight (paramVarLid, posWeight, LogAware::one());
|
||||
|
||||
Clause* clause1 = new Clause (*(*it)->constr());
|
||||
|
||||
for (unsigned i = 0; i < groups.size(); i++) {
|
||||
LiteralId lid = getLiteralId (groups[i], indexer[i]);
|
||||
|
||||
clause1->addLiteralComplemented (
|
||||
Literal (lid, (*it)->argument(i).logVars()));
|
||||
|
||||
ConstraintTree ct = *(*it)->constr();
|
||||
Clause* tempClause = new Clause (ct);
|
||||
tempClause->addLiteralComplemented (Literal (
|
||||
paramVarLid, (*it)->constr()->logVars()));
|
||||
tempClause->addLiteral (Literal (lid, (*it)->argument(i).logVars()));
|
||||
clauses_.push_back (tempClause);
|
||||
}
|
||||
clause1->addLiteral (Literal (paramVarLid, (*it)->constr()->logVars()));
|
||||
clauses_.push_back (clause1);
|
||||
freeLiteralId_ ++;
|
||||
++ indexer;
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedWCNF::printFormulaIndicators (void) const
|
||||
{
|
||||
if (map_.empty()) {
|
||||
return;
|
||||
}
|
||||
set<PrvGroup> allGroups;
|
||||
ParfactorList::const_iterator it = pfList_.begin();
|
||||
while (it != pfList_.end()) {
|
||||
const ProbFormulas& formulas = (*it)->arguments();
|
||||
for (size_t i = 0; i < formulas.size(); i++) {
|
||||
if (Util::contains (allGroups, formulas[i].group()) == false) {
|
||||
allGroups.insert (formulas[i].group());
|
||||
cout << formulas[i] << " | " ;
|
||||
ConstraintTree tempCt = (*it)->constr()->projectedCopy (
|
||||
formulas[i].logVars());
|
||||
cout << tempCt.tupleSet();
|
||||
cout << " indicators => " ;
|
||||
vector<LiteralId> indicators =
|
||||
(map_.find (formulas[i].group()))->second;
|
||||
cout << indicators << endl;
|
||||
}
|
||||
}
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedWCNF::printWeights (void) const
|
||||
{
|
||||
unordered_map<LiteralId, std::pair<double,double>>::const_iterator it;
|
||||
it = weights_.begin();
|
||||
while (it != weights_.end()) {
|
||||
cout << "λ" << it->first << " weights: " ;
|
||||
cout << it->second.first << " " << it->second.second;
|
||||
cout << endl;
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
LiftedWCNF::printClauses (void) const
|
||||
{
|
||||
Clause::printClauses (clauses_);
|
||||
}
|
||||
|
@ -1,239 +0,0 @@
|
||||
#ifndef HORUS_LIFTEDWCNF_H
|
||||
#define HORUS_LIFTEDWCNF_H
|
||||
|
||||
#include "ParfactorList.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef long LiteralId;
|
||||
|
||||
class ConstraintTree;
|
||||
|
||||
|
||||
enum LogVarType
|
||||
{
|
||||
FULL_LV,
|
||||
POS_LV,
|
||||
NEG_LV
|
||||
};
|
||||
|
||||
typedef vector<LogVarType> LogVarTypes;
|
||||
|
||||
|
||||
|
||||
class Literal
|
||||
{
|
||||
public:
|
||||
Literal (LiteralId lid, const LogVars& lvs) :
|
||||
lid_(lid), logVars_(lvs), negated_(false) { }
|
||||
|
||||
Literal (const Literal& lit, bool negated) :
|
||||
lid_(lit.lid_), logVars_(lit.logVars_), negated_(negated) { }
|
||||
|
||||
LiteralId lid (void) const { return lid_; }
|
||||
|
||||
LogVars logVars (void) const { return logVars_; }
|
||||
|
||||
size_t nrLogVars (void) const { return logVars_.size(); }
|
||||
|
||||
LogVarSet logVarSet (void) const { return LogVarSet (logVars_); }
|
||||
|
||||
void complement (void) { negated_ = !negated_; }
|
||||
|
||||
bool isPositive (void) const { return negated_ == false; }
|
||||
|
||||
bool isNegative (void) const { return negated_; }
|
||||
|
||||
bool isGround (ConstraintTree constr, LogVarSet ipgLogVars) const;
|
||||
|
||||
size_t indexOfLogVar (LogVar X) const;
|
||||
|
||||
string toString (LogVarSet ipgLogVars = LogVarSet(),
|
||||
LogVarSet posCountedLvs = LogVarSet(),
|
||||
LogVarSet negCountedLvs = LogVarSet()) const;
|
||||
|
||||
friend std::ostream& operator<< (std::ostream &os, const Literal& lit);
|
||||
|
||||
private:
|
||||
LiteralId lid_;
|
||||
LogVars logVars_;
|
||||
bool negated_;
|
||||
};
|
||||
|
||||
typedef vector<Literal> Literals;
|
||||
|
||||
|
||||
|
||||
class Clause
|
||||
{
|
||||
public:
|
||||
Clause (const ConstraintTree& ct = ConstraintTree({})) : constr_(ct) { }
|
||||
|
||||
Clause (vector<vector<string>> names) : constr_(ConstraintTree (names)) { }
|
||||
|
||||
void addLiteral (const Literal& l) { literals_.push_back (l); }
|
||||
|
||||
const Literals& literals (void) const { return literals_; }
|
||||
|
||||
Literals& literals (void) { return literals_; }
|
||||
|
||||
size_t nrLiterals (void) const { return literals_.size(); }
|
||||
|
||||
const ConstraintTree& constr (void) const { return constr_; }
|
||||
|
||||
ConstraintTree constr (void) { return constr_; }
|
||||
|
||||
bool isUnit (void) const { return literals_.size() == 1; }
|
||||
|
||||
LogVarSet ipgLogVars (void) const { return ipgLvs_; }
|
||||
|
||||
void addIpgLogVar (LogVar X) { ipgLvs_.insert (X); }
|
||||
|
||||
void addPosCountedLogVar (LogVar X) { posCountedLvs_.insert (X); }
|
||||
|
||||
void addNegCountedLogVar (LogVar X) { negCountedLvs_.insert (X); }
|
||||
|
||||
LogVarSet posCountedLogVars (void) const { return posCountedLvs_; }
|
||||
|
||||
LogVarSet negCountedLogVars (void) const { return negCountedLvs_; }
|
||||
|
||||
unsigned nrPosCountedLogVars (void) const { return posCountedLvs_.size(); }
|
||||
|
||||
unsigned nrNegCountedLogVars (void) const { return negCountedLvs_.size(); }
|
||||
|
||||
void addLiteralComplemented (const Literal& lit);
|
||||
|
||||
bool containsLiteral (LiteralId lid) const;
|
||||
|
||||
bool containsPositiveLiteral (LiteralId lid, const LogVarTypes&) const;
|
||||
|
||||
bool containsNegativeLiteral (LiteralId lid, const LogVarTypes&) const;
|
||||
|
||||
void removeLiterals (LiteralId lid);
|
||||
|
||||
void removePositiveLiterals (LiteralId lid, const LogVarTypes&);
|
||||
|
||||
void removeNegativeLiterals (LiteralId lid, const LogVarTypes&);
|
||||
|
||||
bool isCountedLogVar (LogVar X) const;
|
||||
|
||||
bool isPositiveCountedLogVar (LogVar X) const;
|
||||
|
||||
bool isNegativeCountedLogVar (LogVar X) const;
|
||||
|
||||
bool isIpgLogVar (LogVar X) const;
|
||||
|
||||
TinySet<LiteralId> lidSet (void) const;
|
||||
|
||||
LogVarSet ipgCandidates (void) const;
|
||||
|
||||
LogVarTypes logVarTypes (size_t litIdx) const;
|
||||
|
||||
void removeLiteral (size_t litIdx);
|
||||
|
||||
static bool independentClauses (Clause& c1, Clause& c2);
|
||||
|
||||
static vector<Clause*> copyClauses (const vector<Clause*>& clauses);
|
||||
|
||||
static void printClauses (const vector<Clause*>& clauses);
|
||||
|
||||
static void deleteClauses (vector<Clause*>& clauses);
|
||||
|
||||
friend std::ostream& operator<< (ostream &os, const Clause& clause);
|
||||
|
||||
private:
|
||||
LogVarSet getLogVarSetExcluding (size_t idx) const;
|
||||
|
||||
Literals literals_;
|
||||
LogVarSet ipgLvs_;
|
||||
LogVarSet posCountedLvs_;
|
||||
LogVarSet negCountedLvs_;
|
||||
ConstraintTree constr_;
|
||||
};
|
||||
|
||||
typedef vector<Clause*> Clauses;
|
||||
|
||||
|
||||
|
||||
class LitLvTypes
|
||||
{
|
||||
public:
|
||||
struct CompareLitLvTypes
|
||||
{
|
||||
bool operator() (
|
||||
const LitLvTypes& types1,
|
||||
const LitLvTypes& types2) const
|
||||
{
|
||||
if (types1.lid_ < types2.lid_) {
|
||||
return true;
|
||||
}
|
||||
if (types1.lid_ == types2.lid_) {
|
||||
return types1.lvTypes_ < types2.lvTypes_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
LitLvTypes (LiteralId lid, const LogVarTypes& lvTypes) :
|
||||
lid_(lid), lvTypes_(lvTypes) { }
|
||||
|
||||
LiteralId lid (void) const { return lid_; }
|
||||
|
||||
const LogVarTypes& logVarTypes (void) const { return lvTypes_; }
|
||||
|
||||
void setAllFullLogVars (void) {
|
||||
std::fill (lvTypes_.begin(), lvTypes_.end(), LogVarType::FULL_LV); }
|
||||
|
||||
friend std::ostream& operator<< (std::ostream &os, const LitLvTypes& lit);
|
||||
|
||||
private:
|
||||
LiteralId lid_;
|
||||
LogVarTypes lvTypes_;
|
||||
};
|
||||
|
||||
typedef TinySet<LitLvTypes,LitLvTypes::CompareLitLvTypes> LitLvTypesSet;
|
||||
|
||||
|
||||
|
||||
class LiftedWCNF
|
||||
{
|
||||
public:
|
||||
LiftedWCNF (const ParfactorList& pfList);
|
||||
|
||||
~LiftedWCNF (void);
|
||||
|
||||
const Clauses& clauses (void) const { return clauses_; }
|
||||
|
||||
void addWeight (LiteralId lid, double posW, double negW);
|
||||
|
||||
double posWeight (LiteralId lid) const;
|
||||
|
||||
double negWeight (LiteralId lid) const;
|
||||
|
||||
vector<LiteralId> prvGroupLiterals (PrvGroup prvGroup);
|
||||
|
||||
Clause* createClause (LiteralId lid) const;
|
||||
|
||||
void printFormulaIndicators (void) const;
|
||||
|
||||
void printWeights (void) const;
|
||||
|
||||
void printClauses (void) const;
|
||||
|
||||
private:
|
||||
|
||||
LiteralId getLiteralId (PrvGroup prvGroup, unsigned range);
|
||||
|
||||
void addIndicatorClauses (const ParfactorList& pfList);
|
||||
|
||||
void addParameterClauses (const ParfactorList& pfList);
|
||||
|
||||
Clauses clauses_;
|
||||
LiteralId freeLiteralId_;
|
||||
const ParfactorList& pfList_;
|
||||
unordered_map<PrvGroup, vector<LiteralId>> map_;
|
||||
unordered_map<LiteralId, std::pair<double,double>> weights_;
|
||||
};
|
||||
|
||||
#endif // HORUS_LIFTEDWCNF_H
|
||||
|
@ -1,942 +0,0 @@
|
||||
|
||||
#include "Parfactor.h"
|
||||
#include "Histogram.h"
|
||||
#include "Indexer.h"
|
||||
#include "Util.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
Parfactor::Parfactor (
|
||||
const ProbFormulas& formulas,
|
||||
const Params& params,
|
||||
const Tuples& tuples,
|
||||
unsigned distId)
|
||||
{
|
||||
args_ = formulas;
|
||||
params_ = params;
|
||||
distId_ = distId;
|
||||
|
||||
LogVars logVars;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
ranges_.push_back (args_[i].range());
|
||||
const LogVars& lvs = args_[i].logVars();
|
||||
for (size_t j = 0; j < lvs.size(); j++) {
|
||||
if (Util::contains (logVars, lvs[j]) == false) {
|
||||
logVars.push_back (lvs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
LogVar newLv = logVars.size();
|
||||
constr_ = new ConstraintTree (logVars, tuples);
|
||||
// Change formulas like f(X,X), X in {(p1),(p2),...}
|
||||
// to be like f(X,Y), (X,Y) in {(p1,p1),(p2,p2),...}.
|
||||
// This will simplify shattering on the constraint tree.
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
LogVarSet lvSet;
|
||||
LogVars& lvs = args_[i].logVars();
|
||||
for (size_t j = 0; j < lvs.size(); j++) {
|
||||
if (lvSet.contains (lvs[j]) == false) {
|
||||
lvSet |= lvs[j];
|
||||
} else {
|
||||
constr_->cloneLogVar (lvs[j], newLv);
|
||||
lvs[j] = newLv;
|
||||
++ newLv;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactor::Parfactor (const Parfactor* g, const Tuple& tuple)
|
||||
{
|
||||
args_ = g->arguments();
|
||||
params_ = g->params();
|
||||
ranges_ = g->ranges();
|
||||
distId_ = g->distId();
|
||||
constr_ = new ConstraintTree (g->logVars(), {tuple});
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactor::Parfactor (const Parfactor* g, ConstraintTree* constr)
|
||||
{
|
||||
args_ = g->arguments();
|
||||
params_ = g->params();
|
||||
ranges_ = g->ranges();
|
||||
distId_ = g->distId();
|
||||
constr_ = constr;
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactor::Parfactor (const Parfactor& g)
|
||||
{
|
||||
args_ = g.arguments();
|
||||
params_ = g.params();
|
||||
ranges_ = g.ranges();
|
||||
distId_ = g.distId();
|
||||
constr_ = new ConstraintTree (*g.constr());
|
||||
assert (params_.size() == Util::sizeExpected (ranges_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactor::~Parfactor (void)
|
||||
{
|
||||
delete constr_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarSet
|
||||
Parfactor::countedLogVars (void) const
|
||||
{
|
||||
LogVarSet set;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].isCounting()) {
|
||||
set.insert (args_[i].countedLogVar());
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarSet
|
||||
Parfactor::uncountedLogVars (void) const
|
||||
{
|
||||
return constr_->logVarSet() - countedLogVars();
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarSet
|
||||
Parfactor::elimLogVars (void) const
|
||||
{
|
||||
LogVarSet requiredToElim = constr_->logVarSet();
|
||||
requiredToElim -= constr_->singletons();
|
||||
requiredToElim -= countedLogVars();
|
||||
return requiredToElim;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVarSet
|
||||
Parfactor::exclusiveLogVars (size_t fIdx) const
|
||||
{
|
||||
assert (fIdx < args_.size());
|
||||
LogVarSet remaining;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (i != fIdx) {
|
||||
remaining |= args_[i].logVarSet();
|
||||
}
|
||||
}
|
||||
return args_[fIdx].logVarSet() - remaining;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::sumOutIndex (size_t fIdx)
|
||||
{
|
||||
assert (fIdx < args_.size());
|
||||
assert (args_[fIdx].contains (elimLogVars()));
|
||||
|
||||
if (args_[fIdx].isCounting()) {
|
||||
unsigned N = constr_->getConditionalCount (
|
||||
args_[fIdx].countedLogVar());
|
||||
unsigned R = args_[fIdx].range();
|
||||
vector<double> numAssigns = HistogramSet::getNumAssigns (N, R);
|
||||
Indexer indexer (ranges_, fIdx);
|
||||
while (indexer.valid()) {
|
||||
if (Globals::logDomain) {
|
||||
params_[indexer] += numAssigns[ indexer[fIdx] ];
|
||||
} else {
|
||||
params_[indexer] *= numAssigns[ indexer[fIdx] ];
|
||||
}
|
||||
++ indexer;
|
||||
}
|
||||
}
|
||||
|
||||
LogVarSet excl = exclusiveLogVars (fIdx);
|
||||
unsigned exp;
|
||||
if (args_[fIdx].isCounting()) {
|
||||
// counting log vars were already raised on counting conversion
|
||||
exp = constr_->getConditionalCount (excl - args_[fIdx].countedLogVar());
|
||||
} else {
|
||||
exp = constr_->getConditionalCount (excl);
|
||||
}
|
||||
constr_->remove (excl);
|
||||
|
||||
TFactor<ProbFormula>::sumOutIndex (fIdx);
|
||||
LogAware::pow (params_, exp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::multiply (Parfactor& g)
|
||||
{
|
||||
alignAndExponentiate (this, &g);
|
||||
TFactor<ProbFormula>::multiply (g);
|
||||
constr_->join (g.constr(), true);
|
||||
simplifyGrounds();
|
||||
assert (constr_->isCartesianProduct (countedLogVars()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Parfactor::canCountConvert (LogVar X)
|
||||
{
|
||||
if (nrFormulas (X) != 1) {
|
||||
return false;
|
||||
}
|
||||
size_t fIdx = indexOfLogVar (X);
|
||||
if (args_[fIdx].isCounting()) {
|
||||
return false;
|
||||
}
|
||||
if (constr_->isCountNormalized (X) == false) {
|
||||
return false;
|
||||
}
|
||||
if (constr_->getConditionalCount (X) == 1) {
|
||||
return false;
|
||||
}
|
||||
if (constr_->isCartesianProduct (countedLogVars() | X) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::countConvert (LogVar X)
|
||||
{
|
||||
size_t fIdx = indexOfLogVar (X);
|
||||
assert (constr_->isCountNormalized (X));
|
||||
assert (constr_->getConditionalCount (X) > 1);
|
||||
assert (canCountConvert (X));
|
||||
|
||||
unsigned N = constr_->getConditionalCount (X);
|
||||
unsigned R = ranges_[fIdx];
|
||||
unsigned H = HistogramSet::nrHistograms (N, R);
|
||||
vector<Histogram> histograms = HistogramSet::getHistograms (N, R);
|
||||
|
||||
Indexer indexer (ranges_);
|
||||
vector<Params> sumout (params_.size() / R);
|
||||
unsigned count = 0;
|
||||
while (indexer.valid()) {
|
||||
sumout[count].reserve (R);
|
||||
for (unsigned r = 0; r < R; r++) {
|
||||
sumout[count].push_back (params_[indexer]);
|
||||
indexer.incrementDimension (fIdx);
|
||||
}
|
||||
count ++;
|
||||
indexer.resetDimension (fIdx);
|
||||
indexer.incrementExceptDimension (fIdx);
|
||||
}
|
||||
|
||||
params_.clear();
|
||||
params_.reserve (sumout.size() * H);
|
||||
|
||||
ranges_[fIdx] = H;
|
||||
MapIndexer mapIndexer (ranges_, fIdx);
|
||||
while (mapIndexer.valid()) {
|
||||
double prod = LogAware::multIdenty();
|
||||
size_t i = mapIndexer;
|
||||
unsigned h = mapIndexer[fIdx];
|
||||
for (unsigned r = 0; r < R; r++) {
|
||||
if (Globals::logDomain) {
|
||||
prod += LogAware::pow (sumout[i][r], histograms[h][r]);
|
||||
} else {
|
||||
prod *= LogAware::pow (sumout[i][r], histograms[h][r]);
|
||||
}
|
||||
}
|
||||
params_.push_back (prod);
|
||||
++ mapIndexer;
|
||||
}
|
||||
args_[fIdx].setCountedLogVar (X);
|
||||
simplifyCountingFormulas (fIdx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::expand (LogVar X, LogVar X_new1, LogVar X_new2)
|
||||
{
|
||||
size_t fIdx = indexOfLogVar (X);
|
||||
assert (fIdx != args_.size());
|
||||
assert (args_[fIdx].isCounting());
|
||||
|
||||
unsigned N1 = constr_->getConditionalCount (X_new1);
|
||||
unsigned N2 = constr_->getConditionalCount (X_new2);
|
||||
unsigned N = N1 + N2;
|
||||
unsigned R = args_[fIdx].range();
|
||||
unsigned H1 = HistogramSet::nrHistograms (N1, R);
|
||||
unsigned H2 = HistogramSet::nrHistograms (N2, R);
|
||||
|
||||
vector<Histogram> histograms = HistogramSet::getHistograms (N, R);
|
||||
vector<Histogram> histograms1 = HistogramSet::getHistograms (N1, R);
|
||||
vector<Histogram> histograms2 = HistogramSet::getHistograms (N2, R);
|
||||
|
||||
vector<unsigned> sumIndexes;
|
||||
sumIndexes.reserve (H1 * H2);
|
||||
for (unsigned i = 0; i < H1; i++) {
|
||||
for (unsigned j = 0; j < H2; j++) {
|
||||
Histogram hist = histograms1[i];
|
||||
hist += histograms2[j];
|
||||
sumIndexes.push_back (HistogramSet::findIndex (hist, histograms));
|
||||
}
|
||||
}
|
||||
|
||||
expandPotential (fIdx, H1 * H2, sumIndexes);
|
||||
|
||||
args_.insert (args_.begin() + fIdx + 1, args_[fIdx]);
|
||||
args_[fIdx].rename (X, X_new1);
|
||||
args_[fIdx + 1].rename (X, X_new2);
|
||||
if (H1 == 2) {
|
||||
args_[fIdx].clearCountedLogVar();
|
||||
}
|
||||
if (H2 == 2) {
|
||||
args_[fIdx + 1].clearCountedLogVar();
|
||||
}
|
||||
ranges_.insert (ranges_.begin() + fIdx + 1, H2);
|
||||
ranges_[fIdx] = H1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::fullExpand (LogVar X)
|
||||
{
|
||||
size_t fIdx = indexOfLogVar (X);
|
||||
assert (fIdx != args_.size());
|
||||
assert (args_[fIdx].isCounting());
|
||||
|
||||
unsigned N = constr_->getConditionalCount (X);
|
||||
unsigned R = args_[fIdx].range();
|
||||
vector<Histogram> originHists = HistogramSet::getHistograms (N, R);
|
||||
vector<Histogram> expandHists = HistogramSet::getHistograms (1, R);
|
||||
assert (ranges_[fIdx] == originHists.size());
|
||||
vector<unsigned> sumIndexes;
|
||||
sumIndexes.reserve (N * R);
|
||||
|
||||
Ranges expandRanges (N, R);
|
||||
Indexer indexer (expandRanges);
|
||||
while (indexer.valid()) {
|
||||
vector<unsigned> hist (R, 0);
|
||||
for (unsigned n = 0; n < N; n++) {
|
||||
hist += expandHists[indexer[n]];
|
||||
}
|
||||
sumIndexes.push_back (HistogramSet::findIndex (hist, originHists));
|
||||
++ indexer;
|
||||
}
|
||||
|
||||
expandPotential (fIdx, std::pow (R, N), sumIndexes);
|
||||
|
||||
ProbFormula f = args_[fIdx];
|
||||
args_.erase (args_.begin() + fIdx);
|
||||
ranges_.erase (ranges_.begin() + fIdx);
|
||||
LogVars newLvs = constr_->expand (X);
|
||||
assert (newLvs.size() == N);
|
||||
for (unsigned i = 0 ; i < N; i++) {
|
||||
ProbFormula newFormula (f.functor(), f.logVars(), f.range());
|
||||
newFormula.rename (X, newLvs[i]);
|
||||
args_.insert (args_.begin() + fIdx + i, newFormula);
|
||||
ranges_.insert (ranges_.begin() + fIdx + i, R);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::reorderAccordingGrounds (const Grounds& grounds)
|
||||
{
|
||||
ProbFormulas newFormulas;
|
||||
for (size_t i = 0; i < grounds.size(); i++) {
|
||||
for (size_t j = 0; j < args_.size(); j++) {
|
||||
if (grounds[i].functor() == args_[j].functor() &&
|
||||
grounds[i].arity() == args_[j].arity()) {
|
||||
constr_->moveToTop (args_[j].logVars());
|
||||
if (constr_->containsTuple (grounds[i].args())) {
|
||||
newFormulas.push_back (args_[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (newFormulas.size() == i + 1);
|
||||
}
|
||||
reorderArguments (newFormulas);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::absorveEvidence (const ProbFormula& formula, unsigned evidence)
|
||||
{
|
||||
size_t fIdx = indexOf (formula);
|
||||
assert (fIdx != args_.size());
|
||||
LogVarSet excl = exclusiveLogVars (fIdx);
|
||||
assert (args_[fIdx].isCounting() == false);
|
||||
assert (constr_->isCountNormalized (excl));
|
||||
LogAware::pow (params_, constr_->getConditionalCount (excl));
|
||||
TFactor<ProbFormula>::absorveEvidence (formula, evidence);
|
||||
constr_->remove (excl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::setNewGroups (void)
|
||||
{
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
args_[i].setGroup (ProbFormula::getNewGroup());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::applySubstitution (const Substitution& theta)
|
||||
{
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
LogVars& lvs = args_[i].logVars();
|
||||
for (size_t j = 0; j < lvs.size(); j++) {
|
||||
lvs[j] = theta.newNameFor (lvs[j]);
|
||||
}
|
||||
if (args_[i].isCounting()) {
|
||||
LogVar clv = args_[i].countedLogVar();
|
||||
args_[i].setCountedLogVar (theta.newNameFor (clv));
|
||||
}
|
||||
}
|
||||
constr_->applySubstitution (theta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t
|
||||
Parfactor::indexOfGround (const Ground& ground) const
|
||||
{
|
||||
size_t idx = args_.size();
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].functor() == ground.functor() &&
|
||||
args_[i].arity() == ground.arity()) {
|
||||
constr_->moveToTop (args_[i].logVars());
|
||||
if (constr_->containsTuple (ground.args())) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PrvGroup
|
||||
Parfactor::findGroup (const Ground& ground) const
|
||||
{
|
||||
size_t idx = indexOfGround (ground);
|
||||
return idx == args_.size()
|
||||
? numeric_limits<PrvGroup>::max()
|
||||
: args_[idx].group();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Parfactor::containsGround (const Ground& ground) const
|
||||
{
|
||||
return findGroup (ground) != numeric_limits<PrvGroup>::max();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Parfactor::containsGrounds (const Grounds& grounds) const
|
||||
{
|
||||
Tuple tuple;
|
||||
LogVars tupleLvs;
|
||||
for (size_t i = 0; i < grounds.size(); i++) {
|
||||
size_t idx = indexOfGround (grounds[i]);
|
||||
if (idx == args_.size()) {
|
||||
return false;
|
||||
}
|
||||
LogVars lvs = args_[idx].logVars();
|
||||
for (size_t j = 0; j < lvs.size(); j++) {
|
||||
if (Util::contains (tupleLvs, lvs[j]) == false) {
|
||||
tuple.push_back (grounds[i].args()[j]);
|
||||
tupleLvs.push_back (lvs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
constr_->moveToTop (tupleLvs);
|
||||
return constr_->containsTuple (tuple);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Parfactor::containsGroup (PrvGroup group) const
|
||||
{
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].group() == group) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Parfactor::containsGroups (vector<PrvGroup> groups) const
|
||||
{
|
||||
for (size_t i = 0; i < groups.size(); i++) {
|
||||
if (containsGroup (groups[i]) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
Parfactor::nrFormulas (LogVar X) const
|
||||
{
|
||||
unsigned count = 0;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].contains (X)) {
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
Parfactor::indexOfLogVar (LogVar X) const
|
||||
{
|
||||
size_t idx = args_.size();
|
||||
assert (nrFormulas (X) == 1);
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].contains (X)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
Parfactor::indexOfGroup (PrvGroup group) const
|
||||
{
|
||||
size_t pos = args_.size();
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].group() == group) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
Parfactor::nrFormulasWithGroup (PrvGroup group) const
|
||||
{
|
||||
unsigned count = 0;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (args_[i].group() == group) {
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<PrvGroup>
|
||||
Parfactor::getAllGroups (void) const
|
||||
{
|
||||
vector<PrvGroup> groups (args_.size());
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
groups[i] = args_[i].group();
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
Parfactor::getLabel (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "phi(" ;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (i != 0) ss << "," ;
|
||||
ss << args_[i];
|
||||
}
|
||||
ss << ")" ;
|
||||
ConstraintTree copy (*constr_);
|
||||
copy.moveToTop (copy.logVarSet().elements());
|
||||
ss << "|" << copy.tupleSet();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::print (bool printParams) const
|
||||
{
|
||||
cout << "Formulas: " ;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (i != 0) cout << ", " ;
|
||||
cout << args_[i];
|
||||
}
|
||||
cout << endl;
|
||||
if (args_[0].group() != Util::maxUnsigned()) {
|
||||
vector<string> groups;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
groups.push_back (string ("g") + Util::toString (args_[i].group()));
|
||||
}
|
||||
cout << "Groups: " << groups << endl;
|
||||
}
|
||||
cout << "LogVars: " << constr_->logVarSet() << endl;
|
||||
cout << "Ranges: " << ranges_ << endl;
|
||||
if (printParams == false) {
|
||||
cout << "Params: " ;
|
||||
if (params_.size() <= 32) {
|
||||
cout.precision(10);
|
||||
cout << params_ << endl;
|
||||
} else {
|
||||
cout << "|" << params_.size() << "|" << endl;
|
||||
}
|
||||
}
|
||||
ConstraintTree copy (*constr_);
|
||||
copy.moveToTop (copy.logVarSet().elements());
|
||||
cout << "Tuples: " << copy.tupleSet() << endl;
|
||||
if (printParams) {
|
||||
printParameters();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::printParameters (void) const
|
||||
{
|
||||
vector<string> jointStrings;
|
||||
Indexer indexer (ranges_);
|
||||
while (indexer.valid()) {
|
||||
stringstream ss;
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (i != 0) ss << ", " ;
|
||||
if (args_[i].isCounting()) {
|
||||
unsigned N = constr_->getConditionalCount (
|
||||
args_[i].countedLogVar());
|
||||
HistogramSet hs (N, args_[i].range());
|
||||
unsigned c = 0;
|
||||
while (c < indexer[i]) {
|
||||
hs.nextHistogram();
|
||||
c ++;
|
||||
}
|
||||
ss << hs;
|
||||
} else {
|
||||
ss << indexer[i];
|
||||
}
|
||||
}
|
||||
jointStrings.push_back (ss.str());
|
||||
++ indexer;
|
||||
}
|
||||
for (size_t i = 0; i < params_.size(); i++) {
|
||||
cout << "f(" << jointStrings[i] << ")" ;
|
||||
cout << " = " << params_[i] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::printProjections (void) const
|
||||
{
|
||||
ConstraintTree copy (*constr_);
|
||||
|
||||
LogVarSet Xs = copy.logVarSet();
|
||||
for (size_t i = 0; i < Xs.size(); i++) {
|
||||
cout << "-> projection of " << Xs[i] << ": " ;
|
||||
cout << copy.tupleSet ({Xs[i]}) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::expandPotential (
|
||||
size_t fIdx,
|
||||
unsigned newRange,
|
||||
const vector<unsigned>& sumIndexes)
|
||||
{
|
||||
ullong newSize = (params_.size() / ranges_[fIdx]) * newRange;
|
||||
if (newSize > params_.max_size()) {
|
||||
cerr << "Error: an overflow occurred when performing expansion." ;
|
||||
cerr << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
Params backup = params_;
|
||||
params_.clear();
|
||||
params_.reserve (newSize);
|
||||
|
||||
size_t prod = 1;
|
||||
vector<size_t> offsets (ranges_.size());
|
||||
for (size_t i = ranges_.size(); i-- > 0; ) {
|
||||
offsets[i] = prod;
|
||||
prod *= ranges_[i];
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
ranges_[fIdx] = newRange;
|
||||
vector<unsigned> indices (ranges_.size(), 0);
|
||||
for (size_t k = 0; k < newSize; k++) {
|
||||
assert (index < backup.size());
|
||||
params_.push_back (backup[index]);
|
||||
for (size_t i = ranges_.size(); i-- > 0; ) {
|
||||
indices[i] ++;
|
||||
if (i == fIdx) {
|
||||
if (indices[i] != ranges_[i]) {
|
||||
int diff = sumIndexes[indices[i]] - sumIndexes[indices[i] - 1];
|
||||
index += diff * offsets[i];
|
||||
break;
|
||||
} else {
|
||||
// last index contains the old range minus 1
|
||||
index -= sumIndexes.back() * offsets[i];
|
||||
indices[i] = 0;
|
||||
}
|
||||
} else {
|
||||
if (indices[i] != ranges_[i]) {
|
||||
index += offsets[i];
|
||||
break;
|
||||
} else {
|
||||
index -= (ranges_[i] - 1) * offsets[i];
|
||||
indices[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::simplifyCountingFormulas (size_t fIdx)
|
||||
{
|
||||
// check if we can simplify the parfactor
|
||||
for (size_t i = 0; i < args_.size(); i++) {
|
||||
if (i != fIdx &&
|
||||
args_[i].isCounting() &&
|
||||
args_[i].group() == args_[fIdx].group()) {
|
||||
// if they only differ in the name of the counting log var
|
||||
if ((args_[i].logVarSet() - args_[i].countedLogVar()) ==
|
||||
(args_[fIdx].logVarSet()) - args_[fIdx].countedLogVar() &&
|
||||
ranges_[i] == ranges_[fIdx]) {
|
||||
simplifyParfactor (fIdx, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::simplifyGrounds (void)
|
||||
{
|
||||
if (args_.size() == 1) {
|
||||
return;
|
||||
}
|
||||
LogVarSet singletons = constr_->singletons();
|
||||
for (long i = 0; i < (long)args_.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < args_.size(); j++) {
|
||||
if (args_[i].group() == args_[j].group() &&
|
||||
singletons.contains (args_[i].logVarSet()) &&
|
||||
singletons.contains (args_[j].logVarSet())) {
|
||||
simplifyParfactor (i, j);
|
||||
i --;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Parfactor::canMultiply (Parfactor* g1, Parfactor* g2)
|
||||
{
|
||||
std::pair<LogVars, LogVars> res = getAlignLogVars (g1, g2);
|
||||
LogVarSet Xs_1 (res.first);
|
||||
LogVarSet Xs_2 (res.second);
|
||||
LogVarSet Y_1 = g1->logVarSet() - Xs_1;
|
||||
LogVarSet Y_2 = g2->logVarSet() - Xs_2;
|
||||
Y_1 -= g1->countedLogVars();
|
||||
Y_2 -= g2->countedLogVars();
|
||||
return g1->constr()->isCountNormalized (Y_1) &&
|
||||
g2->constr()->isCountNormalized (Y_2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::simplifyParfactor (size_t fIdx1, size_t fIdx2)
|
||||
{
|
||||
Params backup = params_;
|
||||
params_.clear();
|
||||
Indexer indexer (ranges_);
|
||||
while (indexer.valid()) {
|
||||
if (indexer[fIdx1] == indexer[fIdx2]) {
|
||||
params_.push_back (backup[indexer]);
|
||||
}
|
||||
++ indexer;
|
||||
}
|
||||
for (size_t i = 0; i < args_[fIdx2].logVars().size(); i++) {
|
||||
if (nrFormulas (args_[fIdx2].logVars()[i]) == 1) {
|
||||
constr_->remove ({ args_[fIdx2].logVars()[i] });
|
||||
}
|
||||
}
|
||||
args_.erase (args_.begin() + fIdx2);
|
||||
ranges_.erase (ranges_.begin() + fIdx2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::pair<LogVars, LogVars>
|
||||
Parfactor::getAlignLogVars (Parfactor* g1, Parfactor* g2)
|
||||
{
|
||||
g1->simplifyGrounds();
|
||||
g2->simplifyGrounds();
|
||||
LogVars Xs_1, Xs_2;
|
||||
TinySet<size_t> matchedI;
|
||||
TinySet<size_t> matchedJ;
|
||||
ProbFormulas& formulas1 = g1->arguments();
|
||||
ProbFormulas& formulas2 = g2->arguments();
|
||||
for (size_t i = 0; i < formulas1.size(); i++) {
|
||||
for (size_t j = 0; j < formulas2.size(); j++) {
|
||||
if (formulas1[i].group() == formulas2[j].group() &&
|
||||
g1->range (i) == g2->range (j) &&
|
||||
matchedI.contains (i) == false &&
|
||||
matchedJ.contains (j) == false) {
|
||||
Util::addToVector (Xs_1, formulas1[i].logVars());
|
||||
Util::addToVector (Xs_2, formulas2[j].logVars());
|
||||
matchedI.insert (i);
|
||||
matchedJ.insert (j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return make_pair (Xs_1, Xs_2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::alignAndExponentiate (Parfactor* g1, Parfactor* g2)
|
||||
{
|
||||
alignLogicalVars (g1, g2);
|
||||
LogVarSet comm = g1->logVarSet() & g2->logVarSet();
|
||||
LogVarSet Y_1 = g1->logVarSet() - comm;
|
||||
LogVarSet Y_2 = g2->logVarSet() - comm;
|
||||
Y_1 -= g1->countedLogVars();
|
||||
Y_2 -= g2->countedLogVars();
|
||||
assert (g1->constr()->isCountNormalized (Y_1));
|
||||
assert (g2->constr()->isCountNormalized (Y_2));
|
||||
unsigned condCount1 = g1->constr()->getConditionalCount (Y_1);
|
||||
unsigned condCount2 = g2->constr()->getConditionalCount (Y_2);
|
||||
LogAware::pow (g1->params(), 1.0 / condCount2);
|
||||
LogAware::pow (g2->params(), 1.0 / condCount1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Parfactor::alignLogicalVars (Parfactor* g1, Parfactor* g2)
|
||||
{
|
||||
std::pair<LogVars, LogVars> res = getAlignLogVars (g1, g2);
|
||||
const LogVars& alignLvs1 = res.first;
|
||||
const LogVars& alignLvs2 = res.second;
|
||||
// cout << "ALIGNING :::::::::::::::::" << endl;
|
||||
// g1->print();
|
||||
// cout << "AND" << endl;
|
||||
// g2->print();
|
||||
// cout << "-> align lvs1 = " << alignLvs1 << endl;
|
||||
// cout << "-> align lvs2 = " << alignLvs2 << endl;
|
||||
LogVar freeLogVar (0);
|
||||
Substitution theta1, theta2;
|
||||
for (size_t i = 0; i < alignLvs1.size(); i++) {
|
||||
bool b1 = theta1.containsReplacementFor (alignLvs1[i]);
|
||||
bool b2 = theta2.containsReplacementFor (alignLvs2[i]);
|
||||
if (b1 == false && b2 == false) {
|
||||
theta1.add (alignLvs1[i], freeLogVar);
|
||||
theta2.add (alignLvs2[i], freeLogVar);
|
||||
++ freeLogVar;
|
||||
} else if (b1 == false && b2) {
|
||||
theta1.add (alignLvs1[i], theta2.newNameFor (alignLvs2[i]));
|
||||
} else if (b1 && b2 == false) {
|
||||
theta2.add (alignLvs2[i], theta1.newNameFor (alignLvs1[i]));
|
||||
}
|
||||
}
|
||||
|
||||
const LogVarSet& allLvs1 = g1->logVarSet();
|
||||
for (size_t i = 0; i < allLvs1.size(); i++) {
|
||||
if (theta1.containsReplacementFor (allLvs1[i]) == false) {
|
||||
theta1.add (allLvs1[i], freeLogVar);
|
||||
++ freeLogVar;
|
||||
}
|
||||
}
|
||||
const LogVarSet& allLvs2 = g2->logVarSet();
|
||||
for (size_t i = 0; i < allLvs2.size(); i++) {
|
||||
if (theta2.containsReplacementFor (allLvs2[i]) == false) {
|
||||
theta2.add (allLvs2[i], freeLogVar);
|
||||
++ freeLogVar;
|
||||
}
|
||||
}
|
||||
|
||||
// handle this type of situation:
|
||||
// g1 = p(X), q(X) ; X in {(p1),(p2)}
|
||||
// g2 = p(X), q(Y) ; (X,Y) in {(p1,p2),(p2,p1)}
|
||||
LogVars discardedLvs1 = theta1.getDiscardedLogVars();
|
||||
for (size_t i = 0; i < discardedLvs1.size(); i++) {
|
||||
if (g1->constr()->isSingleton (discardedLvs1[i]) &&
|
||||
g1->nrFormulas (discardedLvs1[i]) == 1) {
|
||||
g1->constr()->remove (discardedLvs1[i]);
|
||||
} else {
|
||||
LogVar X_new = ++ g1->constr()->logVarSet().back();
|
||||
theta1.rename (discardedLvs1[i], X_new);
|
||||
}
|
||||
}
|
||||
LogVars discardedLvs2 = theta2.getDiscardedLogVars();
|
||||
for (size_t i = 0; i < discardedLvs2.size(); i++) {
|
||||
if (g2->constr()->isSingleton (discardedLvs2[i]) &&
|
||||
g2->nrFormulas (discardedLvs2[i]) == 1) {
|
||||
g2->constr()->remove (discardedLvs2[i]);
|
||||
} else {
|
||||
LogVar X_new = ++ g2->constr()->logVarSet().back();
|
||||
theta2.rename (discardedLvs2[i], X_new);
|
||||
}
|
||||
}
|
||||
|
||||
// cout << "theta1: " << theta1 << endl;
|
||||
// cout << "theta2: " << theta2 << endl;
|
||||
g1->applySubstitution (theta1);
|
||||
g2->applySubstitution (theta2);
|
||||
}
|
||||
|
@ -1,125 +0,0 @@
|
||||
#ifndef HORUS_PARFACTOR_H
|
||||
#define HORUS_PARFACTOR_H
|
||||
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "ProbFormula.h"
|
||||
#include "ConstraintTree.h"
|
||||
#include "LiftedUtils.h"
|
||||
#include "Horus.h"
|
||||
|
||||
#include "Factor.h"
|
||||
|
||||
class Parfactor : public TFactor<ProbFormula>
|
||||
{
|
||||
public:
|
||||
Parfactor (
|
||||
const ProbFormulas&,
|
||||
const Params&,
|
||||
const Tuples&,
|
||||
unsigned distId);
|
||||
|
||||
Parfactor (const Parfactor*, const Tuple&);
|
||||
|
||||
Parfactor (const Parfactor*, ConstraintTree*);
|
||||
|
||||
Parfactor (const Parfactor&);
|
||||
|
||||
~Parfactor (void);
|
||||
|
||||
ConstraintTree* constr (void) { return constr_; }
|
||||
|
||||
const ConstraintTree* constr (void) const { return constr_; }
|
||||
|
||||
const LogVars& logVars (void) const { return constr_->logVars(); }
|
||||
|
||||
const LogVarSet& logVarSet (void) const { return constr_->logVarSet(); }
|
||||
|
||||
LogVarSet countedLogVars (void) const;
|
||||
|
||||
LogVarSet uncountedLogVars (void) const;
|
||||
|
||||
LogVarSet elimLogVars (void) const;
|
||||
|
||||
LogVarSet exclusiveLogVars (size_t fIdx) const;
|
||||
|
||||
void sumOutIndex (size_t fIdx);
|
||||
|
||||
void multiply (Parfactor&);
|
||||
|
||||
bool canCountConvert (LogVar X);
|
||||
|
||||
void countConvert (LogVar);
|
||||
|
||||
void expand (LogVar, LogVar, LogVar);
|
||||
|
||||
void fullExpand (LogVar);
|
||||
|
||||
void reorderAccordingGrounds (const Grounds&);
|
||||
|
||||
void absorveEvidence (const ProbFormula&, unsigned);
|
||||
|
||||
void setNewGroups (void);
|
||||
|
||||
void applySubstitution (const Substitution&);
|
||||
|
||||
size_t indexOfGround (const Ground&) const;
|
||||
|
||||
PrvGroup findGroup (const Ground&) const;
|
||||
|
||||
bool containsGround (const Ground&) const;
|
||||
|
||||
bool containsGrounds (const Grounds&) const;
|
||||
|
||||
bool containsGroup (PrvGroup) const;
|
||||
|
||||
bool containsGroups (vector<PrvGroup>) const;
|
||||
|
||||
unsigned nrFormulas (LogVar) const;
|
||||
|
||||
int indexOfLogVar (LogVar) const;
|
||||
|
||||
int indexOfGroup (PrvGroup) const;
|
||||
|
||||
unsigned nrFormulasWithGroup (PrvGroup) const;
|
||||
|
||||
vector<PrvGroup> getAllGroups (void) const;
|
||||
|
||||
void print (bool = false) const;
|
||||
|
||||
void printParameters (void) const;
|
||||
|
||||
void printProjections (void) const;
|
||||
|
||||
string getLabel (void) const;
|
||||
|
||||
void simplifyGrounds (void);
|
||||
|
||||
static bool canMultiply (Parfactor*, Parfactor*);
|
||||
|
||||
private:
|
||||
|
||||
void simplifyCountingFormulas (size_t fIdx);
|
||||
|
||||
void simplifyParfactor (size_t fIdx1, size_t fIdx2);
|
||||
|
||||
static std::pair<LogVars, LogVars> getAlignLogVars (
|
||||
Parfactor* g1, Parfactor* g2);
|
||||
|
||||
void expandPotential (size_t fIdx, unsigned newRange,
|
||||
const vector<unsigned>& sumIndexes);
|
||||
|
||||
static void alignAndExponentiate (Parfactor*, Parfactor*);
|
||||
|
||||
static void alignLogicalVars (Parfactor*, Parfactor*);
|
||||
|
||||
ConstraintTree* constr_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef vector<Parfactor*> Parfactors;
|
||||
|
||||
#endif // HORUS_PARFACTOR_H
|
||||
|
@ -1,638 +0,0 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "ParfactorList.h"
|
||||
|
||||
|
||||
ParfactorList::ParfactorList (const ParfactorList& pfList)
|
||||
{
|
||||
ParfactorList::const_iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
addShattered (new Parfactor (**it));
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ParfactorList::ParfactorList (const Parfactors& pfs)
|
||||
{
|
||||
add (pfs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ParfactorList::~ParfactorList (void)
|
||||
{
|
||||
ParfactorList::const_iterator it = pfList_.begin();
|
||||
while (it != pfList_.end()) {
|
||||
delete *it;
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParfactorList::add (Parfactor* pf)
|
||||
{
|
||||
pf->setNewGroups();
|
||||
addToShatteredList (pf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParfactorList::add (const Parfactors& pfs)
|
||||
{
|
||||
for (size_t i = 0; i < pfs.size(); i++) {
|
||||
pfs[i]->setNewGroups();
|
||||
addToShatteredList (pfs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParfactorList::addShattered (Parfactor* pf)
|
||||
{
|
||||
assert (isAllShattered());
|
||||
pfList_.push_back (pf);
|
||||
assert (isAllShattered());
|
||||
}
|
||||
|
||||
|
||||
|
||||
list<Parfactor*>::iterator
|
||||
ParfactorList::insertShattered (
|
||||
list<Parfactor*>::iterator it,
|
||||
Parfactor* pf)
|
||||
{
|
||||
return pfList_.insert (it, pf);
|
||||
assert (isAllShattered());
|
||||
}
|
||||
|
||||
|
||||
|
||||
list<Parfactor*>::iterator
|
||||
ParfactorList::remove (list<Parfactor*>::iterator it)
|
||||
{
|
||||
return pfList_.erase (it);
|
||||
}
|
||||
|
||||
|
||||
|
||||
list<Parfactor*>::iterator
|
||||
ParfactorList::removeAndDelete (list<Parfactor*>::iterator it)
|
||||
{
|
||||
delete *it;
|
||||
return pfList_.erase (it);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ParfactorList::isAllShattered (void) const
|
||||
{
|
||||
if (pfList_.size() <= 1) {
|
||||
return true;
|
||||
}
|
||||
vector<Parfactor*> pfs (pfList_.begin(), pfList_.end());
|
||||
for (size_t i = 0; i < pfs.size(); i++) {
|
||||
assert (isShattered (pfs[i]));
|
||||
}
|
||||
for (size_t i = 0; i < pfs.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < pfs.size(); j++) {
|
||||
if (isShattered (pfs[i], pfs[j]) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParfactorList::print (void) const
|
||||
{
|
||||
Parfactors pfVec (pfList_.begin(), pfList_.end());
|
||||
std::sort (pfVec.begin(), pfVec.end(), sortByParams());
|
||||
for (size_t i = 0; i < pfVec.size(); i++) {
|
||||
pfVec[i]->print();
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ParfactorList&
|
||||
ParfactorList::operator= (const ParfactorList& pfList)
|
||||
{
|
||||
if (this != &pfList) {
|
||||
ParfactorList::const_iterator it0 = pfList_.begin();
|
||||
while (it0 != pfList_.end()) {
|
||||
delete *it0;
|
||||
++ it0;
|
||||
}
|
||||
pfList_.clear();
|
||||
ParfactorList::const_iterator it = pfList.begin();
|
||||
while (it != pfList.end()) {
|
||||
addShattered (new Parfactor (**it));
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ParfactorList::isShattered (const Parfactor* g) const
|
||||
{
|
||||
const ProbFormulas& formulas = g->arguments();
|
||||
if (formulas.size() < 2) {
|
||||
return true;
|
||||
}
|
||||
ConstraintTree ct (*g->constr());
|
||||
for (size_t i = 0; i < formulas.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < formulas.size(); j++) {
|
||||
if (formulas[i].group() == formulas[j].group()) {
|
||||
if (identical (
|
||||
formulas[i], *(g->constr()),
|
||||
formulas[j], *(g->constr())) == false) {
|
||||
g->print();
|
||||
cout << "-> not identical on positions " ;
|
||||
cout << i << " and " << j << endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (disjoint (
|
||||
formulas[i], *(g->constr()),
|
||||
formulas[j], *(g->constr())) == false) {
|
||||
g->print();
|
||||
cout << "-> not disjoint on positions " ;
|
||||
cout << i << " and " << j << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ParfactorList::isShattered (
|
||||
const Parfactor* g1,
|
||||
const Parfactor* g2) const
|
||||
{
|
||||
assert (g1 != g2);
|
||||
const ProbFormulas& fms1 = g1->arguments();
|
||||
const ProbFormulas& fms2 = g2->arguments();
|
||||
|
||||
for (size_t i = 0; i < fms1.size(); i++) {
|
||||
for (size_t j = 0; j < fms2.size(); j++) {
|
||||
if (fms1[i].group() == fms2[j].group()) {
|
||||
if (identical (
|
||||
fms1[i], *(g1->constr()),
|
||||
fms2[j], *(g2->constr())) == false) {
|
||||
g1->print();
|
||||
cout << "^" << endl;
|
||||
g2->print();
|
||||
cout << "-> not identical on group " << fms1[i].group() << endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (disjoint (
|
||||
fms1[i], *(g1->constr()),
|
||||
fms2[j], *(g2->constr())) == false) {
|
||||
g1->print();
|
||||
cout << "^" << endl;
|
||||
g2->print();
|
||||
cout << "-> not disjoint on groups " << fms1[i].group();
|
||||
cout << " and " << fms2[j].group() << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParfactorList::addToShatteredList (Parfactor* g)
|
||||
{
|
||||
queue<Parfactor*> residuals;
|
||||
residuals.push (g);
|
||||
while (residuals.empty() == false) {
|
||||
Parfactor* pf = residuals.front();
|
||||
bool pfSplitted = false;
|
||||
list<Parfactor*>::iterator pfIter;
|
||||
pfIter = pfList_.begin();
|
||||
while (pfIter != pfList_.end()) {
|
||||
std::pair<Parfactors, Parfactors> shattRes;
|
||||
shattRes = shatter (*pfIter, pf);
|
||||
if (shattRes.first.empty() == false) {
|
||||
pfIter = removeAndDelete (pfIter);
|
||||
Util::addToQueue (residuals, shattRes.first);
|
||||
} else {
|
||||
++ pfIter;
|
||||
}
|
||||
if (shattRes.second.empty() == false) {
|
||||
delete pf;
|
||||
Util::addToQueue (residuals, shattRes.second);
|
||||
pfSplitted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
residuals.pop();
|
||||
if (pfSplitted == false) {
|
||||
Parfactors res = shatterAgainstMySelf (pf);
|
||||
if (res.empty()) {
|
||||
addShattered (pf);
|
||||
} else {
|
||||
Util::addToQueue (residuals, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (isAllShattered());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactors
|
||||
ParfactorList::shatterAgainstMySelf (Parfactor* g)
|
||||
{
|
||||
Parfactors pfs;
|
||||
queue<Parfactor*> residuals;
|
||||
residuals.push (g);
|
||||
bool shattered = true;
|
||||
while (residuals.empty() == false) {
|
||||
Parfactor* pf = residuals.front();
|
||||
Parfactors res = shatterAgainstMySelf2 (pf);
|
||||
if (res.empty()) {
|
||||
assert (isShattered (pf));
|
||||
if (shattered) {
|
||||
return { };
|
||||
}
|
||||
pfs.push_back (pf);
|
||||
} else {
|
||||
shattered = false;
|
||||
for (size_t i = 0; i < res.size(); i++) {
|
||||
assert (res[i]->constr()->empty() == false);
|
||||
residuals.push (res[i]);
|
||||
}
|
||||
delete pf;
|
||||
}
|
||||
residuals.pop();
|
||||
}
|
||||
return pfs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactors
|
||||
ParfactorList::shatterAgainstMySelf2 (Parfactor* g)
|
||||
{
|
||||
// slip a parfactor with overlapping formulas:
|
||||
// e.g. {s(X),s(Y)}, with (X,Y) in {(p1,p2),(p1,p3),(p4,p1)}
|
||||
const ProbFormulas& formulas = g->arguments();
|
||||
for (size_t i = 0; i < formulas.size() - 1; i++) {
|
||||
for (size_t j = i + 1; j < formulas.size(); j++) {
|
||||
if (formulas[i].sameSkeletonAs (formulas[j])) {
|
||||
Parfactors res = shatterAgainstMySelf (g, i, j);
|
||||
if (res.empty() == false) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Parfactors();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactors
|
||||
ParfactorList::shatterAgainstMySelf (
|
||||
Parfactor* g,
|
||||
size_t fIdx1,
|
||||
size_t fIdx2)
|
||||
{
|
||||
/*
|
||||
Util::printDashedLine();
|
||||
cout << "-> SHATTERING" << endl;
|
||||
g->print();
|
||||
cout << "-> ON: " << g->argument (fIdx1) << "|" ;
|
||||
cout << g->constr()->tupleSet (g->argument (fIdx1).logVars()) << endl;
|
||||
cout << "-> ON: " << g->argument (fIdx2) << "|" ;
|
||||
cout << g->constr()->tupleSet (g->argument (fIdx2).logVars()) << endl;
|
||||
Util::printDashedLine();
|
||||
*/
|
||||
ProbFormula& f1 = g->argument (fIdx1);
|
||||
ProbFormula& f2 = g->argument (fIdx2);
|
||||
if (f1.isAtom()) {
|
||||
cerr << "Error: a ground occurs twice in the same parfactor." << endl;
|
||||
cerr << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
assert (g->constr()->empty() == false);
|
||||
ConstraintTree ctCopy (*g->constr());
|
||||
if (f1.group() == f2.group()) {
|
||||
assert (identical (f1, *(g->constr()), f2, ctCopy));
|
||||
return { };
|
||||
}
|
||||
|
||||
g->constr()->moveToTop (f1.logVars());
|
||||
ctCopy.moveToTop (f2.logVars());
|
||||
|
||||
std::pair<ConstraintTree*,ConstraintTree*> split1 =
|
||||
g->constr()->split (f1.logVars(), &ctCopy, f2.logVars());
|
||||
ConstraintTree* commCt1 = split1.first;
|
||||
ConstraintTree* exclCt1 = split1.second;
|
||||
|
||||
if (commCt1->empty()) {
|
||||
// disjoint
|
||||
delete commCt1;
|
||||
delete exclCt1;
|
||||
return { };
|
||||
}
|
||||
|
||||
PrvGroup newGroup = ProbFormula::getNewGroup();
|
||||
Parfactors res1 = shatter (g, fIdx1, commCt1, exclCt1, newGroup);
|
||||
if (res1.empty()) {
|
||||
res1.push_back (g);
|
||||
}
|
||||
|
||||
Parfactors res;
|
||||
ctCopy.moveToTop (f1.logVars());
|
||||
for (size_t i = 0; i < res1.size(); i++) {
|
||||
res1[i]->constr()->moveToTop (f2.logVars());
|
||||
std::pair<ConstraintTree*, ConstraintTree*> split2;
|
||||
split2 = res1[i]->constr()->split (f2.logVars(), &ctCopy, f1.logVars());
|
||||
ConstraintTree* commCt2 = split2.first;
|
||||
ConstraintTree* exclCt2 = split2.second;
|
||||
if (commCt2->empty()) {
|
||||
if (res1[i] != g) {
|
||||
res.push_back (res1[i]);
|
||||
}
|
||||
delete commCt2;
|
||||
delete exclCt2;
|
||||
continue;
|
||||
}
|
||||
newGroup = ProbFormula::getNewGroup();
|
||||
Parfactors res2 = shatter (res1[i], fIdx2, commCt2, exclCt2, newGroup);
|
||||
if (res2.empty()) {
|
||||
if (res1[i] != g) {
|
||||
res.push_back (res1[i]);
|
||||
}
|
||||
} else {
|
||||
Util::addToVector (res, res2);
|
||||
for (size_t j = 0; j < res2.size(); j++) {
|
||||
}
|
||||
if (res1[i] != g) {
|
||||
delete res1[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res.empty()) {
|
||||
g->argument (fIdx2).setGroup (g->argument (fIdx1).group());
|
||||
updateGroups (f2.group(), f1.group());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::pair<Parfactors, Parfactors>
|
||||
ParfactorList::shatter (Parfactor* g1, Parfactor* g2)
|
||||
{
|
||||
ProbFormulas& formulas1 = g1->arguments();
|
||||
ProbFormulas& formulas2 = g2->arguments();
|
||||
assert (g1 != 0 && g2 != 0 && g1 != g2);
|
||||
for (size_t i = 0; i < formulas1.size(); i++) {
|
||||
for (size_t j = 0; j < formulas2.size(); j++) {
|
||||
if (formulas1[i].sameSkeletonAs (formulas2[j])) {
|
||||
std::pair<Parfactors, Parfactors> res;
|
||||
res = shatter (i, g1, j, g2);
|
||||
if (res.first.empty() == false ||
|
||||
res.second.empty() == false) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return make_pair (Parfactors(), Parfactors());
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::pair<Parfactors, Parfactors>
|
||||
ParfactorList::shatter (
|
||||
size_t fIdx1, Parfactor* g1,
|
||||
size_t fIdx2, Parfactor* g2)
|
||||
{
|
||||
ProbFormula& f1 = g1->argument (fIdx1);
|
||||
ProbFormula& f2 = g2->argument (fIdx2);
|
||||
/*
|
||||
Util::printDashedLine();
|
||||
cout << "-> SHATTERING" << endl;
|
||||
g1->print();
|
||||
cout << "-> WITH" << endl;
|
||||
g2->print();
|
||||
cout << "-> ON: " << f1 << "|" ;
|
||||
cout << g1->constr()->tupleSet (f1.logVars()) << endl;
|
||||
cout << "-> ON: " << f2 << "|" ;
|
||||
cout << g2->constr()->tupleSet (f2.logVars()) << endl;
|
||||
Util::printDashedLine();
|
||||
*/
|
||||
if (f1.isAtom()) {
|
||||
f2.setGroup (f1.group());
|
||||
updateGroups (f2.group(), f1.group());
|
||||
return { };
|
||||
}
|
||||
assert (g1->constr()->empty() == false);
|
||||
assert (g2->constr()->empty() == false);
|
||||
if (f1.group() == f2.group()) {
|
||||
assert (identical (f1, *(g1->constr()), f2, *(g2->constr())));
|
||||
return { };
|
||||
}
|
||||
|
||||
g1->constr()->moveToTop (f1.logVars());
|
||||
g2->constr()->moveToTop (f2.logVars());
|
||||
|
||||
std::pair<ConstraintTree*,ConstraintTree*> split1 =
|
||||
g1->constr()->split (f1.logVars(), g2->constr(), f2.logVars());
|
||||
ConstraintTree* commCt1 = split1.first;
|
||||
ConstraintTree* exclCt1 = split1.second;
|
||||
|
||||
if (commCt1->empty()) {
|
||||
// disjoint
|
||||
delete commCt1;
|
||||
delete exclCt1;
|
||||
return { };
|
||||
}
|
||||
|
||||
std::pair<ConstraintTree*,ConstraintTree*> split2 =
|
||||
g2->constr()->split (f2.logVars(), g1->constr(), f1.logVars());
|
||||
ConstraintTree* commCt2 = split2.first;
|
||||
ConstraintTree* exclCt2 = split2.second;
|
||||
|
||||
assert (commCt1->tupleSet (f1.logVars()) ==
|
||||
commCt2->tupleSet (f2.logVars()));
|
||||
|
||||
// stringstream ss1; ss1 << "" << count << "_A.dot" ;
|
||||
// stringstream ss2; ss2 << "" << count << "_B.dot" ;
|
||||
// stringstream ss3; ss3 << "" << count << "_A_comm.dot" ;
|
||||
// stringstream ss4; ss4 << "" << count << "_A_excl.dot" ;
|
||||
// stringstream ss5; ss5 << "" << count << "_B_comm.dot" ;
|
||||
// stringstream ss6; ss6 << "" << count << "_B_excl.dot" ;
|
||||
// g1->constr()->exportToGraphViz (ss1.str().c_str(), true);
|
||||
// g2->constr()->exportToGraphViz (ss2.str().c_str(), true);
|
||||
// commCt1->exportToGraphViz (ss3.str().c_str(), true);
|
||||
// exclCt1->exportToGraphViz (ss4.str().c_str(), true);
|
||||
// commCt2->exportToGraphViz (ss5.str().c_str(), true);
|
||||
// exclCt2->exportToGraphViz (ss6.str().c_str(), true);
|
||||
|
||||
if (exclCt1->empty() && exclCt2->empty()) {
|
||||
// identical
|
||||
f2.setGroup (f1.group());
|
||||
updateGroups (f2.group(), f1.group());
|
||||
delete commCt1;
|
||||
delete exclCt1;
|
||||
delete commCt2;
|
||||
delete exclCt2;
|
||||
return { };
|
||||
}
|
||||
|
||||
PrvGroup group;
|
||||
if (exclCt1->empty()) {
|
||||
group = f1.group();
|
||||
} else if (exclCt2->empty()) {
|
||||
group = f2.group();
|
||||
} else {
|
||||
group = ProbFormula::getNewGroup();
|
||||
}
|
||||
Parfactors res1 = shatter (g1, fIdx1, commCt1, exclCt1, group);
|
||||
Parfactors res2 = shatter (g2, fIdx2, commCt2, exclCt2, group);
|
||||
return make_pair (res1, res2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Parfactors
|
||||
ParfactorList::shatter (
|
||||
Parfactor* g,
|
||||
size_t fIdx,
|
||||
ConstraintTree* commCt,
|
||||
ConstraintTree* exclCt,
|
||||
PrvGroup commGroup)
|
||||
{
|
||||
ProbFormula& f = g->argument (fIdx);
|
||||
if (exclCt->empty()) {
|
||||
delete commCt;
|
||||
delete exclCt;
|
||||
f.setGroup (commGroup);
|
||||
return { };
|
||||
}
|
||||
|
||||
Parfactors result;
|
||||
if (f.isCounting()) {
|
||||
LogVar X_new1 = g->constr()->logVarSet().back() + 1;
|
||||
LogVar X_new2 = g->constr()->logVarSet().back() + 2;
|
||||
ConstraintTrees cts = g->constr()->jointCountNormalize (
|
||||
commCt, exclCt, f.countedLogVar(), X_new1, X_new2);
|
||||
for (size_t i = 0; i < cts.size(); i++) {
|
||||
Parfactor* newPf = new Parfactor (g, cts[i]);
|
||||
if (cts[i]->nrLogVars() == g->constr()->nrLogVars() + 1) {
|
||||
newPf->expand (f.countedLogVar(), X_new1, X_new2);
|
||||
assert (g->constr()->getConditionalCount (f.countedLogVar()) ==
|
||||
cts[i]->getConditionalCount (X_new1) +
|
||||
cts[i]->getConditionalCount (X_new2));
|
||||
} else {
|
||||
assert (g->constr()->getConditionalCount (f.countedLogVar()) ==
|
||||
cts[i]->getConditionalCount (f.countedLogVar()));
|
||||
}
|
||||
newPf->setNewGroups();
|
||||
result.push_back (newPf);
|
||||
}
|
||||
delete commCt;
|
||||
delete exclCt;
|
||||
} else {
|
||||
Parfactor* newPf = new Parfactor (g, commCt);
|
||||
newPf->setNewGroups();
|
||||
newPf->argument (fIdx).setGroup (commGroup);
|
||||
result.push_back (newPf);
|
||||
newPf = new Parfactor (g, exclCt);
|
||||
newPf->setNewGroups();
|
||||
result.push_back (newPf);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParfactorList::updateGroups (PrvGroup oldGroup, PrvGroup newGroup)
|
||||
{
|
||||
for (ParfactorList::iterator it = pfList_.begin();
|
||||
it != pfList_.end(); ++it) {
|
||||
ProbFormulas& formulas = (*it)->arguments();
|
||||
for (size_t i = 0; i < formulas.size(); i++) {
|
||||
if (formulas[i].group() == oldGroup) {
|
||||
formulas[i].setGroup (newGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ParfactorList::proper (
|
||||
const ProbFormula& f1, ConstraintTree ct1,
|
||||
const ProbFormula& f2, ConstraintTree ct2) const
|
||||
{
|
||||
return disjoint (f1, ct1, f2, ct2)
|
||||
|| identical (f1, ct1, f2, ct2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ParfactorList::identical (
|
||||
const ProbFormula& f1, ConstraintTree ct1,
|
||||
const ProbFormula& f2, ConstraintTree ct2) const
|
||||
{
|
||||
if (f1.sameSkeletonAs (f2) == false) {
|
||||
return false;
|
||||
}
|
||||
if (f1.isAtom()) {
|
||||
return true;
|
||||
}
|
||||
TupleSet ts1 = ct1.tupleSet (f1.logVars());
|
||||
TupleSet ts2 = ct2.tupleSet (f2.logVars());
|
||||
return ts1 == ts2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ParfactorList::disjoint (
|
||||
const ProbFormula& f1, ConstraintTree ct1,
|
||||
const ProbFormula& f2, ConstraintTree ct2) const
|
||||
{
|
||||
if (f1.sameSkeletonAs (f2) == false) {
|
||||
return true;
|
||||
}
|
||||
if (f1.isAtom()) {
|
||||
return false;
|
||||
}
|
||||
TupleSet ts1 = ct1.tupleSet (f1.logVars());
|
||||
TupleSet ts2 = ct2.tupleSet (f2.logVars());
|
||||
return (ts1 & ts2).empty();
|
||||
}
|
||||
|
@ -1,121 +0,0 @@
|
||||
#ifndef HORUS_PARFACTORLIST_H
|
||||
#define HORUS_PARFACTORLIST_H
|
||||
|
||||
#include <list>
|
||||
#include <queue>
|
||||
|
||||
#include "Parfactor.h"
|
||||
#include "ProbFormula.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class ParfactorList
|
||||
{
|
||||
public:
|
||||
ParfactorList (void) { }
|
||||
|
||||
ParfactorList (const ParfactorList&);
|
||||
|
||||
ParfactorList (const Parfactors&);
|
||||
|
||||
~ParfactorList (void);
|
||||
|
||||
const list<Parfactor*>& parfactors (void) const { return pfList_; }
|
||||
|
||||
void clear (void) { pfList_.clear(); }
|
||||
|
||||
size_t size (void) const { return pfList_.size(); }
|
||||
|
||||
typedef std::list<Parfactor*>::iterator iterator;
|
||||
|
||||
iterator begin (void) { return pfList_.begin(); }
|
||||
|
||||
iterator end (void) { return pfList_.end(); }
|
||||
|
||||
typedef std::list<Parfactor*>::const_iterator const_iterator;
|
||||
|
||||
const_iterator begin (void) const { return pfList_.begin(); }
|
||||
|
||||
const_iterator end (void) const { return pfList_.end(); }
|
||||
|
||||
void add (Parfactor* pf);
|
||||
|
||||
void add (const Parfactors& pfs);
|
||||
|
||||
void addShattered (Parfactor* pf);
|
||||
|
||||
list<Parfactor*>::iterator insertShattered (
|
||||
list<Parfactor*>::iterator, Parfactor*);
|
||||
|
||||
list<Parfactor*>::iterator remove (list<Parfactor*>::iterator);
|
||||
|
||||
list<Parfactor*>::iterator removeAndDelete (list<Parfactor*>::iterator);
|
||||
|
||||
bool isAllShattered (void) const;
|
||||
|
||||
void print (void) const;
|
||||
|
||||
ParfactorList& operator= (const ParfactorList& pfList);
|
||||
|
||||
private:
|
||||
bool isShattered (const Parfactor*) const;
|
||||
|
||||
bool isShattered (const Parfactor*, const Parfactor*) const;
|
||||
|
||||
void addToShatteredList (Parfactor*);
|
||||
|
||||
Parfactors shatterAgainstMySelf (Parfactor* g);
|
||||
|
||||
Parfactors shatterAgainstMySelf2 (Parfactor* g);
|
||||
|
||||
Parfactors shatterAgainstMySelf (
|
||||
Parfactor* g, size_t fIdx1, size_t fIdx2);
|
||||
|
||||
std::pair<Parfactors, Parfactors> shatter (
|
||||
Parfactor*, Parfactor*);
|
||||
|
||||
std::pair<Parfactors, Parfactors> shatter (
|
||||
size_t, Parfactor*, size_t, Parfactor*);
|
||||
|
||||
Parfactors shatter (
|
||||
Parfactor*,
|
||||
size_t,
|
||||
ConstraintTree*,
|
||||
ConstraintTree*,
|
||||
PrvGroup);
|
||||
|
||||
void updateGroups (PrvGroup group1, PrvGroup group2);
|
||||
|
||||
bool proper (
|
||||
const ProbFormula&, ConstraintTree,
|
||||
const ProbFormula&, ConstraintTree) const;
|
||||
|
||||
bool identical (
|
||||
const ProbFormula&, ConstraintTree,
|
||||
const ProbFormula&, ConstraintTree) const;
|
||||
|
||||
bool disjoint (
|
||||
const ProbFormula&, ConstraintTree,
|
||||
const ProbFormula&, ConstraintTree) const;
|
||||
|
||||
struct sortByParams
|
||||
{
|
||||
inline bool operator() (const Parfactor* pf1, const Parfactor* pf2)
|
||||
{
|
||||
if (pf1->params().size() < pf2->params().size()) {
|
||||
return true;
|
||||
} else if (pf1->params().size() == pf2->params().size() &&
|
||||
pf1->params() < pf2->params()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
list<Parfactor*> pfList_;
|
||||
};
|
||||
|
||||
#endif // HORUS_PARFACTORLIST_H
|
||||
|
@ -1,140 +0,0 @@
|
||||
#include "ProbFormula.h"
|
||||
|
||||
|
||||
PrvGroup ProbFormula::freeGroup_ = 0;
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ProbFormula::sameSkeletonAs (const ProbFormula& f) const
|
||||
{
|
||||
return functor_ == f.functor() && logVars_.size() == f.arity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ProbFormula::contains (LogVar lv) const
|
||||
{
|
||||
return Util::contains (logVars_, lv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ProbFormula::contains (LogVarSet s) const
|
||||
{
|
||||
return LogVarSet (logVars_).contains (s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t
|
||||
ProbFormula::indexOf (LogVar X) const
|
||||
{
|
||||
return Util::indexOf (logVars_, X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ProbFormula::isAtom (void) const
|
||||
{
|
||||
return logVars_.size() == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ProbFormula::isCounting (void) const
|
||||
{
|
||||
return countedLogVar_.valid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogVar
|
||||
ProbFormula::countedLogVar (void) const
|
||||
{
|
||||
assert (isCounting());
|
||||
return countedLogVar_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProbFormula::setCountedLogVar (LogVar lv)
|
||||
{
|
||||
countedLogVar_ = lv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProbFormula::clearCountedLogVar (void)
|
||||
{
|
||||
countedLogVar_ = LogVar();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProbFormula::rename (LogVar oldName, LogVar newName)
|
||||
{
|
||||
for (size_t i = 0; i < logVars_.size(); i++) {
|
||||
if (logVars_[i] == oldName) {
|
||||
logVars_[i] = newName;
|
||||
}
|
||||
}
|
||||
if (isCounting() && countedLogVar_ == oldName) {
|
||||
countedLogVar_ = newName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool operator== (const ProbFormula& f1, const ProbFormula& f2)
|
||||
{
|
||||
return f1.group_ == f2.group_ &&
|
||||
f1.logVars_ == f2.logVars_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostream& operator<< (ostream &os, const ProbFormula& f)
|
||||
{
|
||||
os << f.functor_;
|
||||
if (f.isAtom() == false) {
|
||||
os << "(" ;
|
||||
for (size_t i = 0; i < f.logVars_.size(); i++) {
|
||||
if (i != 0) os << ",";
|
||||
if (f.isCounting() && f.logVars_[i] == f.countedLogVar_) {
|
||||
os << "#" ;
|
||||
}
|
||||
os << f.logVars_[i];
|
||||
}
|
||||
os << ")" ;
|
||||
}
|
||||
os << "::" << f.range_;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PrvGroup
|
||||
ProbFormula::getNewGroup (void)
|
||||
{
|
||||
freeGroup_ ++;
|
||||
assert (freeGroup_ != numeric_limits<PrvGroup>::max());
|
||||
return freeGroup_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream& operator<< (ostream &os, const ObservedFormula& of)
|
||||
{
|
||||
os << of.functor_ << "/" << of.arity_;
|
||||
os << "|" << of.constr_.tupleSet();
|
||||
os << " [evidence=" << of.evidence_ << "]";
|
||||
return os;
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
#ifndef HORUS_PROBFORMULA_H
|
||||
#define HORUS_PROBFORMULA_H
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "ConstraintTree.h"
|
||||
#include "LiftedUtils.h"
|
||||
#include "Horus.h"
|
||||
|
||||
typedef unsigned long PrvGroup;
|
||||
|
||||
class ProbFormula
|
||||
{
|
||||
public:
|
||||
ProbFormula (Symbol f, const LogVars& lvs, unsigned range)
|
||||
: functor_(f), logVars_(lvs), range_(range),
|
||||
countedLogVar_(), group_(numeric_limits<PrvGroup>::max()) { }
|
||||
|
||||
ProbFormula (Symbol f, unsigned r)
|
||||
: functor_(f), range_(r), group_(numeric_limits<PrvGroup>::max()) { }
|
||||
|
||||
Symbol functor (void) const { return functor_; }
|
||||
|
||||
unsigned arity (void) const { return logVars_.size(); }
|
||||
|
||||
unsigned range (void) const { return range_; }
|
||||
|
||||
LogVars& logVars (void) { return logVars_; }
|
||||
|
||||
const LogVars& logVars (void) const { return logVars_; }
|
||||
|
||||
LogVarSet logVarSet (void) const { return LogVarSet (logVars_); }
|
||||
|
||||
PrvGroup group (void) const { return group_; }
|
||||
|
||||
void setGroup (PrvGroup g) { group_ = g; }
|
||||
|
||||
bool sameSkeletonAs (const ProbFormula&) const;
|
||||
|
||||
bool contains (LogVar) const;
|
||||
|
||||
bool contains (LogVarSet) const;
|
||||
|
||||
size_t indexOf (LogVar) const;
|
||||
|
||||
bool isAtom (void) const;
|
||||
|
||||
bool isCounting (void) const;
|
||||
|
||||
LogVar countedLogVar (void) const;
|
||||
|
||||
void setCountedLogVar (LogVar);
|
||||
|
||||
void clearCountedLogVar (void);
|
||||
|
||||
void rename (LogVar, LogVar);
|
||||
|
||||
static PrvGroup getNewGroup (void);
|
||||
|
||||
friend std::ostream& operator<< (ostream &os, const ProbFormula& f);
|
||||
|
||||
friend bool operator== (const ProbFormula& f1, const ProbFormula& f2);
|
||||
|
||||
private:
|
||||
Symbol functor_;
|
||||
LogVars logVars_;
|
||||
unsigned range_;
|
||||
LogVar countedLogVar_;
|
||||
PrvGroup group_;
|
||||
static PrvGroup freeGroup_;
|
||||
};
|
||||
|
||||
typedef vector<ProbFormula> ProbFormulas;
|
||||
|
||||
|
||||
class ObservedFormula
|
||||
{
|
||||
public:
|
||||
ObservedFormula (Symbol f, unsigned a, unsigned ev)
|
||||
: functor_(f), arity_(a), evidence_(ev), constr_(a) { }
|
||||
|
||||
ObservedFormula (Symbol f, unsigned ev, const Tuple& tuple)
|
||||
: functor_(f), arity_(tuple.size()), evidence_(ev), constr_(arity_)
|
||||
{
|
||||
constr_.addTuple (tuple);
|
||||
}
|
||||
|
||||
Symbol functor (void) const { return functor_; }
|
||||
|
||||
unsigned arity (void) const { return arity_; }
|
||||
|
||||
unsigned evidence (void) const { return evidence_; }
|
||||
|
||||
void setEvidence (unsigned ev) { evidence_ = ev; }
|
||||
|
||||
ConstraintTree& constr (void) { return constr_; }
|
||||
|
||||
bool isAtom (void) const { return arity_ == 0; }
|
||||
|
||||
void addTuple (const Tuple& tuple) { constr_.addTuple (tuple); }
|
||||
|
||||
friend ostream& operator<< (ostream &os, const ObservedFormula& of);
|
||||
|
||||
private:
|
||||
Symbol functor_;
|
||||
unsigned arity_;
|
||||
unsigned evidence_;
|
||||
ConstraintTree constr_;
|
||||
};
|
||||
|
||||
typedef vector<ObservedFormula> ObservedFormulas;
|
||||
|
||||
#endif // HORUS_PROBFORMULA_H
|
||||
|
@ -1,264 +0,0 @@
|
||||
#ifndef HORUS_TINYSET_H
|
||||
#define HORUS_TINYSET_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
template <typename T, typename Compare = std::less<T>>
|
||||
class TinySet
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename vector<T>::iterator iterator;
|
||||
typedef typename vector<T>::const_iterator const_iterator;
|
||||
|
||||
TinySet (const TinySet& s)
|
||||
: vec_(s.vec_), cmp_(s.cmp_) { }
|
||||
|
||||
TinySet (const Compare& cmp = Compare())
|
||||
: vec_(), cmp_(cmp) { }
|
||||
|
||||
TinySet (const T& t, const Compare& cmp = Compare())
|
||||
: vec_(1, t), cmp_(cmp) { }
|
||||
|
||||
TinySet (const vector<T>& elements, const Compare& cmp = Compare())
|
||||
: vec_(elements), cmp_(cmp)
|
||||
{
|
||||
std::sort (begin(), end(), cmp_);
|
||||
iterator it = unique_cmp (begin(), end());
|
||||
vec_.resize (it - begin());
|
||||
}
|
||||
|
||||
iterator insert (const T& t)
|
||||
{
|
||||
iterator it = std::lower_bound (begin(), end(), t, cmp_);
|
||||
if (it == end() || cmp_(t, *it)) {
|
||||
vec_.insert (it, t);
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
void insert_sorted (const T& t)
|
||||
{
|
||||
vec_.push_back (t);
|
||||
assert (consistent());
|
||||
}
|
||||
|
||||
void remove (const T& t)
|
||||
{
|
||||
iterator it = std::lower_bound (begin(), end(), t, cmp_);
|
||||
if (it != end()) {
|
||||
vec_.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
const_iterator find (const T& t) const
|
||||
{
|
||||
const_iterator it = std::lower_bound (begin(), end(), t, cmp_);
|
||||
return it == end() || cmp_(t, *it) ? end() : it;
|
||||
}
|
||||
|
||||
iterator find (const T& t)
|
||||
{
|
||||
iterator it = std::lower_bound (begin(), end(), t, cmp_);
|
||||
return it == end() || cmp_(t, *it) ? end() : it;
|
||||
}
|
||||
|
||||
/* set union */
|
||||
TinySet operator| (const TinySet& s) const
|
||||
{
|
||||
TinySet res;
|
||||
std::set_union (
|
||||
vec_.begin(), vec_.end(),
|
||||
s.vec_.begin(), s.vec_.end(),
|
||||
std::back_inserter (res.vec_),
|
||||
cmp_);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* set intersection */
|
||||
TinySet operator& (const TinySet& s) const
|
||||
{
|
||||
TinySet res;
|
||||
std::set_intersection (
|
||||
vec_.begin(), vec_.end(),
|
||||
s.vec_.begin(), s.vec_.end(),
|
||||
std::back_inserter (res.vec_),
|
||||
cmp_);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* set difference */
|
||||
TinySet operator- (const TinySet& s) const
|
||||
{
|
||||
TinySet res;
|
||||
std::set_difference (
|
||||
vec_.begin(), vec_.end(),
|
||||
s.vec_.begin(), s.vec_.end(),
|
||||
std::back_inserter (res.vec_),
|
||||
cmp_);
|
||||
return res;
|
||||
}
|
||||
|
||||
TinySet& operator|= (const TinySet& s)
|
||||
{
|
||||
return *this = (*this | s);
|
||||
}
|
||||
|
||||
TinySet& operator&= (const TinySet& s)
|
||||
{
|
||||
return *this = (*this & s);
|
||||
}
|
||||
|
||||
TinySet& operator-= (const TinySet& s)
|
||||
{
|
||||
return *this = (*this - s);
|
||||
}
|
||||
|
||||
bool contains (const T& t) const
|
||||
{
|
||||
return std::binary_search (
|
||||
vec_.begin(), vec_.end(), t, cmp_);
|
||||
}
|
||||
|
||||
bool contains (const TinySet& s) const
|
||||
{
|
||||
return std::includes (
|
||||
vec_.begin(),
|
||||
vec_.end(),
|
||||
s.vec_.begin(),
|
||||
s.vec_.end(),
|
||||
cmp_);
|
||||
}
|
||||
|
||||
bool in (const TinySet& s) const
|
||||
{
|
||||
return std::includes (
|
||||
s.vec_.begin(),
|
||||
s.vec_.end(),
|
||||
vec_.begin(),
|
||||
vec_.end(),
|
||||
cmp_);
|
||||
}
|
||||
|
||||
bool intersects (const TinySet& s) const
|
||||
{
|
||||
return (*this & s).size() > 0;
|
||||
}
|
||||
|
||||
const T& operator[] (typename vector<T>::size_type i) const
|
||||
{
|
||||
return vec_[i];
|
||||
}
|
||||
|
||||
T& operator[] (typename vector<T>::size_type i)
|
||||
{
|
||||
return vec_[i];
|
||||
}
|
||||
|
||||
T front (void) const
|
||||
{
|
||||
return vec_.front();
|
||||
}
|
||||
|
||||
T& front (void)
|
||||
{
|
||||
return vec_.front();
|
||||
}
|
||||
|
||||
T back (void) const
|
||||
{
|
||||
return vec_.back();
|
||||
}
|
||||
|
||||
T& back (void)
|
||||
{
|
||||
return vec_.back();
|
||||
}
|
||||
|
||||
const vector<T>& elements (void) const
|
||||
{
|
||||
return vec_;
|
||||
}
|
||||
|
||||
bool empty (void) const
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
typename vector<T>::size_type size (void) const
|
||||
{
|
||||
return vec_.size();
|
||||
}
|
||||
|
||||
void clear (void)
|
||||
{
|
||||
vec_.clear();
|
||||
}
|
||||
|
||||
void reserve (typename vector<T>::size_type size)
|
||||
{
|
||||
vec_.reserve (size);
|
||||
}
|
||||
|
||||
iterator begin (void) { return vec_.begin(); }
|
||||
iterator end (void) { return vec_.end(); }
|
||||
const_iterator begin (void) const { return vec_.begin(); }
|
||||
const_iterator end (void) const { return vec_.end(); }
|
||||
|
||||
friend bool operator== (const TinySet& s1, const TinySet& s2)
|
||||
{
|
||||
return s1.vec_ == s2.vec_;
|
||||
}
|
||||
|
||||
friend bool operator!= (const TinySet& s1, const TinySet& s2)
|
||||
{
|
||||
return ! (s1.vec_ == s2.vec_);
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& out, const TinySet& s)
|
||||
{
|
||||
out << "{" ;
|
||||
typename vector<T>::size_type i;
|
||||
for (i = 0; i < s.size(); i++) {
|
||||
out << ((i != 0) ? "," : "") << s.vec_[i];
|
||||
}
|
||||
out << "}" ;
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
iterator unique_cmp (iterator first, iterator last)
|
||||
{
|
||||
if (first == last) {
|
||||
return last;
|
||||
}
|
||||
iterator result = first;
|
||||
while (++first != last) {
|
||||
if (cmp_(*result, *first)) {
|
||||
*(++result) = *first;
|
||||
}
|
||||
}
|
||||
return ++result;
|
||||
}
|
||||
|
||||
bool consistent (void) const
|
||||
{
|
||||
typename vector<T>::size_type i;
|
||||
for (i = 0; i < vec_.size() - 1; i++) {
|
||||
if ( ! cmp_(vec_[i], vec_[i + 1])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<T> vec_;
|
||||
Compare cmp_;
|
||||
};
|
||||
|
||||
#endif // HORUS_TINYSET_H
|
||||
|
@ -1,429 +0,0 @@
|
||||
#include <limits>
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include "Util.h"
|
||||
#include "Indexer.h"
|
||||
#include "ElimGraph.h"
|
||||
|
||||
|
||||
namespace Globals {
|
||||
bool logDomain = false;
|
||||
|
||||
unsigned verbosity = 0;
|
||||
|
||||
LiftedSolverType liftedSolver = LiftedSolverType::LVE;
|
||||
|
||||
GroundSolverType groundSolver = GroundSolverType::VE;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace BpOptions {
|
||||
Schedule schedule = BpOptions::Schedule::SEQ_FIXED;
|
||||
//Schedule schedule = BpOptions::Schedule::SEQ_RANDOM;
|
||||
//Schedule schedule = BpOptions::Schedule::PARALLEL;
|
||||
//Schedule schedule = BpOptions::Schedule::MAX_RESIDUAL;
|
||||
double accuracy = 0.0001;
|
||||
unsigned maxIter = 1000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace Util {
|
||||
|
||||
|
||||
template <> std::string
|
||||
toString (const bool& b)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::boolalpha << b;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
stringToUnsigned (string str)
|
||||
{
|
||||
int val;
|
||||
stringstream ss;
|
||||
ss << str;
|
||||
ss >> val;
|
||||
if (val < 0) {
|
||||
cerr << "Error: the number readed is negative." << endl;
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return static_cast<unsigned> (val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
stringToDouble (string str)
|
||||
{
|
||||
double val;
|
||||
stringstream ss;
|
||||
ss << str;
|
||||
ss >> val;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
factorial (unsigned num)
|
||||
{
|
||||
double result = 1.0;
|
||||
for (unsigned i = 1; i <= num; i++) {
|
||||
result *= i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
logFactorial (unsigned num)
|
||||
{
|
||||
double result = 0.0;
|
||||
if (num < 150) {
|
||||
result = std::log (factorial (num));
|
||||
} else {
|
||||
for (unsigned i = 1; i <= num; i++) {
|
||||
result += std::log (i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
nrCombinations (unsigned n, unsigned k)
|
||||
{
|
||||
assert (n >= k);
|
||||
int diff = n - k;
|
||||
unsigned result = 0;
|
||||
if (n < 150) {
|
||||
unsigned prod = 1;
|
||||
for (int i = n; i > diff; i--) {
|
||||
prod *= i;
|
||||
}
|
||||
result = prod / factorial (k);
|
||||
} else {
|
||||
double prod = 0.0;
|
||||
for (int i = n; i > diff; i--) {
|
||||
prod += std::log (i);
|
||||
}
|
||||
prod -= logFactorial (k);
|
||||
result = static_cast<unsigned> (std::exp (prod));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t
|
||||
sizeExpected (const Ranges& ranges)
|
||||
{
|
||||
return std::accumulate (ranges.begin(),
|
||||
ranges.end(), 1, multiplies<unsigned>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
nrDigits (int num)
|
||||
{
|
||||
unsigned count = 1;
|
||||
while (num >= 10) {
|
||||
num /= 10;
|
||||
count ++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
isInteger (const string& s)
|
||||
{
|
||||
stringstream ss1 (s);
|
||||
stringstream ss2;
|
||||
int integer;
|
||||
ss1 >> integer;
|
||||
ss2 << integer;
|
||||
return (ss1.str() == ss2.str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
parametersToString (const Params& v, unsigned precision)
|
||||
{
|
||||
stringstream ss;
|
||||
ss.precision (precision);
|
||||
ss << "[" ;
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
if (i != 0) ss << ", " ;
|
||||
ss << v[i];
|
||||
}
|
||||
ss << "]" ;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<string>
|
||||
getStateLines (const Vars& vars)
|
||||
{
|
||||
Ranges ranges;
|
||||
for (size_t i = 0; i < vars.size(); i++) {
|
||||
ranges.push_back (vars[i]->range());
|
||||
}
|
||||
Indexer indexer (ranges);
|
||||
vector<string> jointStrings;
|
||||
while (indexer.valid()) {
|
||||
stringstream ss;
|
||||
for (size_t i = 0; i < vars.size(); i++) {
|
||||
if (i != 0) ss << ", " ;
|
||||
ss << vars[i]->label() << "=" ;
|
||||
ss << vars[i]->states()[(indexer[i])];
|
||||
}
|
||||
jointStrings.push_back (ss.str());
|
||||
++ indexer;
|
||||
}
|
||||
return jointStrings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
setHorusFlag (string key, string value)
|
||||
{
|
||||
bool returnVal = true;
|
||||
if (key == "verbosity") {
|
||||
stringstream ss;
|
||||
ss << value;
|
||||
ss >> Globals::verbosity;
|
||||
} else if (key == "lifted_solver") {
|
||||
if ( value == "lve") {
|
||||
Globals::liftedSolver = LiftedSolverType::LVE;
|
||||
} else if (value == "lbp") {
|
||||
Globals::liftedSolver = LiftedSolverType::LBP;
|
||||
} else if (value == "lkc") {
|
||||
Globals::liftedSolver = LiftedSolverType::LKC;
|
||||
} else {
|
||||
cerr << "warning: invalid value `" << value << "' " ;
|
||||
cerr << "for `" << key << "'" << endl;
|
||||
returnVal = false;
|
||||
}
|
||||
} else if (key == "ground_solver") {
|
||||
if ( value == "ve") {
|
||||
Globals::groundSolver = GroundSolverType::VE;
|
||||
} else if (value == "bp") {
|
||||
Globals::groundSolver = GroundSolverType::BP;
|
||||
} else if (value == "cbp") {
|
||||
Globals::groundSolver = GroundSolverType::CBP;
|
||||
} else {
|
||||
cerr << "warning: invalid value `" << value << "' " ;
|
||||
cerr << "for `" << key << "'" << endl;
|
||||
returnVal = false;
|
||||
}
|
||||
} else if (key == "elim_heuristic") {
|
||||
if ( value == "sequential") {
|
||||
ElimGraph::elimHeuristic = ElimHeuristic::SEQUENTIAL;
|
||||
} else if (value == "min_neighbors") {
|
||||
ElimGraph::elimHeuristic = ElimHeuristic::MIN_NEIGHBORS;
|
||||
} else if (value == "min_weight") {
|
||||
ElimGraph::elimHeuristic = ElimHeuristic::MIN_WEIGHT;
|
||||
} else if (value == "min_fill") {
|
||||
ElimGraph::elimHeuristic = ElimHeuristic::MIN_FILL;
|
||||
} else if (value == "weighted_min_fill") {
|
||||
ElimGraph::elimHeuristic = ElimHeuristic::WEIGHTED_MIN_FILL;
|
||||
} else {
|
||||
cerr << "warning: invalid value `" << value << "' " ;
|
||||
cerr << "for `" << key << "'" << endl;
|
||||
returnVal = false;
|
||||
}
|
||||
} else if (key == "schedule") {
|
||||
if ( value == "seq_fixed") {
|
||||
BpOptions::schedule = BpOptions::Schedule::SEQ_FIXED;
|
||||
} else if (value == "seq_random") {
|
||||
BpOptions::schedule = BpOptions::Schedule::SEQ_RANDOM;
|
||||
} else if (value == "parallel") {
|
||||
BpOptions::schedule = BpOptions::Schedule::PARALLEL;
|
||||
} else if (value == "max_residual") {
|
||||
BpOptions::schedule = BpOptions::Schedule::MAX_RESIDUAL;
|
||||
} else {
|
||||
cerr << "warning: invalid value `" << value << "' " ;
|
||||
cerr << "for `" << key << "'" << endl;
|
||||
returnVal = false;
|
||||
}
|
||||
} else if (key == "accuracy") {
|
||||
stringstream ss;
|
||||
ss << value;
|
||||
ss >> BpOptions::accuracy;
|
||||
} else if (key == "max_iter") {
|
||||
stringstream ss;
|
||||
ss << value;
|
||||
ss >> BpOptions::maxIter;
|
||||
} else if (key == "use_logarithms") {
|
||||
if ( value == "true") {
|
||||
Globals::logDomain = true;
|
||||
} else if (value == "false") {
|
||||
Globals::logDomain = false;
|
||||
} else {
|
||||
cerr << "warning: invalid value `" << value << "' " ;
|
||||
cerr << "for `" << key << "'" << endl;
|
||||
returnVal = false;
|
||||
}
|
||||
} else {
|
||||
cerr << "warning: invalid key `" << key << "'" << endl;
|
||||
returnVal = false;
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
printHeader (string header, std::ostream& os)
|
||||
{
|
||||
printAsteriskLine (os);
|
||||
os << header << endl;
|
||||
printAsteriskLine (os);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
printSubHeader (string header, std::ostream& os)
|
||||
{
|
||||
printDashedLine (os);
|
||||
os << header << endl;
|
||||
printDashedLine (os);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
printAsteriskLine (std::ostream& os)
|
||||
{
|
||||
os << "********************************" ;
|
||||
os << "********************************" ;
|
||||
os << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
printDashedLine (std::ostream& os)
|
||||
{
|
||||
os << "--------------------------------" ;
|
||||
os << "--------------------------------" ;
|
||||
os << endl;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace LogAware {
|
||||
|
||||
void
|
||||
normalize (Params& v)
|
||||
{
|
||||
if (Globals::logDomain) {
|
||||
double sum = std::accumulate (v.begin(), v.end(),
|
||||
LogAware::addIdenty(), Util::logSum);
|
||||
assert (sum != -numeric_limits<double>::infinity());
|
||||
v -= sum;
|
||||
} else {
|
||||
double sum = std::accumulate (v.begin(), v.end(), 0.0);
|
||||
assert (sum != 0.0);
|
||||
v /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
getL1Distance (const Params& v1, const Params& v2)
|
||||
{
|
||||
assert (v1.size() == v2.size());
|
||||
double dist = 0.0;
|
||||
if (Globals::logDomain) {
|
||||
dist = std::inner_product (v1.begin(), v1.end(), v2.begin(), 0.0,
|
||||
std::plus<double>(), FuncObject::abs_diff_exp<double>());
|
||||
} else {
|
||||
dist = std::inner_product (v1.begin(), v1.end(), v2.begin(), 0.0,
|
||||
std::plus<double>(), FuncObject::abs_diff<double>());
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
getMaxNorm (const Params& v1, const Params& v2)
|
||||
{
|
||||
assert (v1.size() == v2.size());
|
||||
double max = 0.0;
|
||||
if (Globals::logDomain) {
|
||||
max = std::inner_product (v1.begin(), v1.end(), v2.begin(), 0.0,
|
||||
FuncObject::max<double>(), FuncObject::abs_diff_exp<double>());
|
||||
} else {
|
||||
max = std::inner_product (v1.begin(), v1.end(), v2.begin(), 0.0,
|
||||
FuncObject::max<double>(), FuncObject::abs_diff<double>());
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
pow (double base, unsigned iexp)
|
||||
{
|
||||
return Globals::logDomain
|
||||
? base * iexp
|
||||
: std::pow (base, iexp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
double
|
||||
pow (double base, double exp)
|
||||
{
|
||||
// `expoent' should not be in log domain
|
||||
return Globals::logDomain
|
||||
? base * exp
|
||||
: std::pow (base, exp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
pow (Params& v, unsigned iexp)
|
||||
{
|
||||
if (iexp == 1) {
|
||||
return;
|
||||
}
|
||||
Globals::logDomain ? v *= iexp : v ^= (int)iexp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
pow (Params& v, double exp)
|
||||
{
|
||||
// `expoent' should not be in log domain
|
||||
Globals::logDomain ? v *= exp : v ^= exp;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,422 +0,0 @@
|
||||
#ifndef HORUS_UTIL_H
|
||||
#define HORUS_UTIL_H
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "Horus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace {
|
||||
const double NEG_INF = -numeric_limits<double>::infinity();
|
||||
};
|
||||
|
||||
|
||||
namespace Util {
|
||||
|
||||
template <typename T> void addToVector (vector<T>&, const vector<T>&);
|
||||
|
||||
template <typename T> void addToSet (set<T>&, const vector<T>&);
|
||||
|
||||
template <typename T> void addToQueue (queue<T>&, const vector<T>&);
|
||||
|
||||
template <typename T> bool contains (const vector<T>&, const T&);
|
||||
|
||||
template <typename T> bool contains (const set<T>&, const T&);
|
||||
|
||||
template <typename K, typename V> bool contains (
|
||||
const unordered_map<K, V>&, const K&);
|
||||
|
||||
template <typename T> size_t indexOf (const vector<T>&, const T&);
|
||||
|
||||
template <class Operation>
|
||||
void apply_n_times (Params& v1, const Params& v2, unsigned repetitions, Operation);
|
||||
|
||||
template <typename T> void log (vector<T>&);
|
||||
|
||||
template <typename T> void exp (vector<T>&);
|
||||
|
||||
template <typename T> string elementsToString (
|
||||
const vector<T>& v, string sep = " ");
|
||||
|
||||
template <typename T> std::string toString (const T&);
|
||||
|
||||
template <> std::string toString (const bool&);
|
||||
|
||||
double logSum (double, double);
|
||||
|
||||
unsigned maxUnsigned (void);
|
||||
|
||||
unsigned stringToUnsigned (string);
|
||||
|
||||
double stringToDouble (string);
|
||||
|
||||
double factorial (unsigned);
|
||||
|
||||
double logFactorial (unsigned);
|
||||
|
||||
unsigned nrCombinations (unsigned, unsigned);
|
||||
|
||||
size_t sizeExpected (const Ranges&);
|
||||
|
||||
unsigned nrDigits (int);
|
||||
|
||||
bool isInteger (const string&);
|
||||
|
||||
string parametersToString (const Params&, unsigned = Constants::PRECISION);
|
||||
|
||||
vector<string> getStateLines (const Vars&);
|
||||
|
||||
bool setHorusFlag (string key, string value);
|
||||
|
||||
void printHeader (string, std::ostream& os = std::cout);
|
||||
|
||||
void printSubHeader (string, std::ostream& os = std::cout);
|
||||
|
||||
void printAsteriskLine (std::ostream& os = std::cout);
|
||||
|
||||
void printDashedLine (std::ostream& os = std::cout);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T> void
|
||||
Util::addToVector (vector<T>& v, const vector<T>& elements)
|
||||
{
|
||||
v.insert (v.end(), elements.begin(), elements.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> void
|
||||
Util::addToSet (set<T>& s, const vector<T>& elements)
|
||||
{
|
||||
s.insert (elements.begin(), elements.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> void
|
||||
Util::addToQueue (queue<T>& q, const vector<T>& elements)
|
||||
{
|
||||
for (size_t i = 0; i < elements.size(); i++) {
|
||||
q.push (elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> bool
|
||||
Util::contains (const vector<T>& v, const T& e)
|
||||
{
|
||||
return std::find (v.begin(), v.end(), e) != v.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> bool
|
||||
Util::contains (const set<T>& s, const T& e)
|
||||
{
|
||||
return s.find (e) != s.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename K, typename V> bool
|
||||
Util::contains (const unordered_map<K, V>& m, const K& k)
|
||||
{
|
||||
return m.find (k) != m.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> size_t
|
||||
Util::indexOf (const vector<T>& v, const T& e)
|
||||
{
|
||||
return std::distance (v.begin(),
|
||||
std::find (v.begin(), v.end(), e));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class Operation> void
|
||||
Util::apply_n_times (Params& v1, const Params& v2, unsigned repetitions,
|
||||
Operation unary_op)
|
||||
{
|
||||
Params::iterator first = v1.begin();
|
||||
Params::const_iterator last = v1.end();
|
||||
Params::const_iterator first2 = v2.begin();
|
||||
Params::const_iterator last2 = v2.end();
|
||||
while (first != last) {
|
||||
for (first2 = v2.begin(); first2 != last2; ++first2) {
|
||||
std::transform (first, first + repetitions, first,
|
||||
std::bind1st (unary_op, *first2));
|
||||
first += repetitions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> void
|
||||
Util::log (vector<T>& v)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(), ::log);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> void
|
||||
Util::exp (vector<T>& v)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(), ::exp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> string
|
||||
Util::elementsToString (const vector<T>& v, string sep)
|
||||
{
|
||||
stringstream ss;
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
ss << ((i != 0) ? sep : "") << v[i];
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> std::string
|
||||
Util::toString (const T& t)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline double
|
||||
Util::logSum (double x, double y)
|
||||
{
|
||||
// std::log (std::exp (x) + std::exp (y)) can overflow!
|
||||
assert (std::isnan (x) == false);
|
||||
assert (std::isnan (y) == false);
|
||||
if (x == NEG_INF) {
|
||||
return y;
|
||||
}
|
||||
if (y == NEG_INF) {
|
||||
return x;
|
||||
}
|
||||
// if one value is much smaller than the other,
|
||||
// keep the larger value
|
||||
const double tol = 460.517; // log (1e200)
|
||||
if (x < y - tol) {
|
||||
return y;
|
||||
}
|
||||
if (y < x - tol) {
|
||||
return x;
|
||||
}
|
||||
assert (std::isnan (x - y) == false);
|
||||
const double exp_diff = std::exp (x - y);
|
||||
if (std::isfinite (exp_diff) == false) {
|
||||
// difference is too large
|
||||
return x > y ? x : y;
|
||||
}
|
||||
// otherwise return the sum
|
||||
return y + std::log (static_cast<double>(1.0) + exp_diff);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline unsigned
|
||||
Util::maxUnsigned (void)
|
||||
{
|
||||
return numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace LogAware {
|
||||
|
||||
inline double one() { return Globals::logDomain ? 0.0 : 1.0; }
|
||||
inline double zero() { return Globals::logDomain ? NEG_INF : 0.0; }
|
||||
inline double addIdenty() { return Globals::logDomain ? NEG_INF : 0.0; }
|
||||
inline double multIdenty() { return Globals::logDomain ? 0.0 : 1.0; }
|
||||
inline double withEvidence() { return Globals::logDomain ? 0.0 : 1.0; }
|
||||
inline double noEvidence() { return Globals::logDomain ? NEG_INF : 0.0; }
|
||||
inline double log (double v) { return Globals::logDomain ? ::log (v) : v; }
|
||||
inline double exp (double v) { return Globals::logDomain ? ::exp (v) : v; }
|
||||
|
||||
void normalize (Params&);
|
||||
|
||||
double getL1Distance (const Params&, const Params&);
|
||||
|
||||
double getMaxNorm (const Params&, const Params&);
|
||||
|
||||
double pow (double, unsigned);
|
||||
|
||||
double pow (double, double);
|
||||
|
||||
void pow (Params&, unsigned);
|
||||
|
||||
void pow (Params&, double);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator+=(std::vector<T>& v, double val)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(),
|
||||
std::bind2nd (plus<double>(), val));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator-=(std::vector<T>& v, double val)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(),
|
||||
std::bind2nd (minus<double>(), val));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator*=(std::vector<T>& v, double val)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(),
|
||||
std::bind2nd (multiplies<double>(), val));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator/=(std::vector<T>& v, double val)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(),
|
||||
std::bind2nd (divides<double>(), val));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator+=(std::vector<T>& a, const std::vector<T>& b)
|
||||
{
|
||||
assert (a.size() == b.size());
|
||||
std::transform (a.begin(), a.end(), b.begin(), a.begin(),
|
||||
plus<double>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator-=(std::vector<T>& a, const std::vector<T>& b)
|
||||
{
|
||||
assert (a.size() == b.size());
|
||||
std::transform (a.begin(), a.end(), b.begin(), a.begin(),
|
||||
minus<double>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator*=(std::vector<T>& a, const std::vector<T>& b)
|
||||
{
|
||||
assert (a.size() == b.size());
|
||||
std::transform (a.begin(), a.end(), b.begin(), a.begin(),
|
||||
multiplies<double>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator/=(std::vector<T>& a, const std::vector<T>& b)
|
||||
{
|
||||
assert (a.size() == b.size());
|
||||
std::transform (a.begin(), a.end(), b.begin(), a.begin(),
|
||||
divides<double>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator^=(std::vector<T>& v, double exp)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(),
|
||||
std::bind2nd (ptr_fun<double, double, double> (std::pow), exp));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator^=(std::vector<T>& v, int iexp)
|
||||
{
|
||||
std::transform (v.begin(), v.end(), v.begin(),
|
||||
std::bind2nd (ptr_fun<double, int, double> (std::pow), iexp));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator << (std::ostream& os, const vector<T>& v)
|
||||
{
|
||||
os << "[" ;
|
||||
os << Util::elementsToString (v, ", ");
|
||||
os << "]" ;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
namespace FuncObject {
|
||||
|
||||
template<typename T>
|
||||
struct max : public std::binary_function<T, T, T>
|
||||
{
|
||||
T operator() (const T& x, const T& y) const
|
||||
{
|
||||
return x < y ? y : x;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct abs_diff : public std::binary_function<T, T, T>
|
||||
{
|
||||
T operator() (const T& x, const T& y) const
|
||||
{
|
||||
return std::abs (x - y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct abs_diff_exp : public std::binary_function<T, T, T>
|
||||
{
|
||||
T operator() (const T& x, const T& y) const
|
||||
{
|
||||
return std::abs (std::exp (x) - std::exp (y));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HORUS_UTIL_H
|
||||
|
@ -1,102 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "Var.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
unordered_map<VarId, VarInfo> Var::varsInfo_;
|
||||
|
||||
|
||||
Var::Var (const Var* v)
|
||||
{
|
||||
varId_ = v->varId();
|
||||
range_ = v->range();
|
||||
evidence_ = v->getEvidence();
|
||||
index_ = std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Var::Var (VarId varId, unsigned range, int evidence)
|
||||
{
|
||||
assert (range != 0);
|
||||
assert (evidence < (int) range);
|
||||
varId_ = varId;
|
||||
range_ = range;
|
||||
evidence_ = evidence;
|
||||
index_ = std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Var::isValidState (int stateIndex)
|
||||
{
|
||||
return stateIndex >= 0 && stateIndex < (int) range_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Var::isValidState (const string& stateName)
|
||||
{
|
||||
States states = Var::getVarInfo (varId_).states;
|
||||
return Util::contains (states, stateName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Var::setEvidence (int ev)
|
||||
{
|
||||
assert (ev < (int) range_);
|
||||
evidence_ = ev;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Var::setEvidence (const string& ev)
|
||||
{
|
||||
States states = Var::getVarInfo (varId_).states;
|
||||
for (size_t i = 0; i < states.size(); i++) {
|
||||
if (states[i] == ev) {
|
||||
evidence_ = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert (false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
Var::label (void) const
|
||||
{
|
||||
if (Var::varsHaveInfo()) {
|
||||
return Var::getVarInfo (varId_).label;
|
||||
}
|
||||
stringstream ss;
|
||||
ss << "x" << varId_;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
States
|
||||
Var::states (void) const
|
||||
{
|
||||
if (Var::varsHaveInfo()) {
|
||||
return Var::getVarInfo (varId_).states;
|
||||
}
|
||||
States states;
|
||||
for (unsigned i = 0; i < range_; i++) {
|
||||
stringstream ss;
|
||||
ss << i ;
|
||||
states.push_back (ss.str());
|
||||
}
|
||||
return states;
|
||||
}
|
||||
|
@ -1,108 +0,0 @@
|
||||
#ifndef HORUS_VAR_H
|
||||
#define HORUS_VAR_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Util.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct VarInfo
|
||||
{
|
||||
VarInfo (string l, const States& sts) : label(l), states(sts) { }
|
||||
string label;
|
||||
States states;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Var
|
||||
{
|
||||
public:
|
||||
Var (const Var*);
|
||||
|
||||
Var (VarId, unsigned, int = Constants::NO_EVIDENCE);
|
||||
|
||||
virtual ~Var (void) { };
|
||||
|
||||
VarId varId (void) const { return varId_; }
|
||||
|
||||
unsigned range (void) const { return range_; }
|
||||
|
||||
int getEvidence (void) const { return evidence_; }
|
||||
|
||||
size_t getIndex (void) const { return index_; }
|
||||
|
||||
void setIndex (size_t idx) { index_ = idx; }
|
||||
|
||||
bool hasEvidence (void) const
|
||||
{
|
||||
return evidence_ != Constants::NO_EVIDENCE;
|
||||
}
|
||||
|
||||
operator size_t (void) const { return index_; }
|
||||
|
||||
bool operator== (const Var& var) const
|
||||
{
|
||||
assert (!(varId_ == var.varId() && range_ != var.range()));
|
||||
return varId_ == var.varId();
|
||||
}
|
||||
|
||||
bool operator!= (const Var& var) const
|
||||
{
|
||||
assert (!(varId_ == var.varId() && range_ != var.range()));
|
||||
return varId_ != var.varId();
|
||||
}
|
||||
|
||||
bool isValidState (int);
|
||||
|
||||
bool isValidState (const string&);
|
||||
|
||||
void setEvidence (int);
|
||||
|
||||
void setEvidence (const string&);
|
||||
|
||||
string label (void) const;
|
||||
|
||||
States states (void) const;
|
||||
|
||||
static void addVarInfo (
|
||||
VarId vid, string label, const States& states)
|
||||
{
|
||||
assert (Util::contains (varsInfo_, vid) == false);
|
||||
varsInfo_.insert (make_pair (vid, VarInfo (label, states)));
|
||||
}
|
||||
|
||||
static VarInfo getVarInfo (VarId vid)
|
||||
{
|
||||
assert (Util::contains (varsInfo_, vid));
|
||||
return varsInfo_.find (vid)->second;
|
||||
}
|
||||
|
||||
static bool varsHaveInfo (void)
|
||||
{
|
||||
return varsInfo_.size() != 0;
|
||||
}
|
||||
|
||||
static void clearVarsInfo (void)
|
||||
{
|
||||
varsInfo_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
VarId varId_;
|
||||
unsigned range_;
|
||||
int evidence_;
|
||||
size_t index_;
|
||||
|
||||
static unordered_map<VarId, VarInfo> varsInfo_;
|
||||
|
||||
};
|
||||
|
||||
#endif // HORUS_VAR_H
|
||||
|
@ -1,217 +0,0 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "VarElim.h"
|
||||
#include "ElimGraph.h"
|
||||
#include "Factor.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
VarElim::~VarElim (void)
|
||||
{
|
||||
delete factorList_.back();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
VarElim::solveQuery (VarIds queryVids)
|
||||
{
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "Solving query on " ;
|
||||
for (size_t i = 0; i < queryVids.size(); i++) {
|
||||
if (i != 0) cout << ", " ;
|
||||
cout << fg.getVarNode (queryVids[i])->label();
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
factorList_.clear();
|
||||
varFactors_.clear();
|
||||
elimOrder_.clear();
|
||||
createFactorList();
|
||||
absorveEvidence();
|
||||
findEliminationOrder (queryVids);
|
||||
processFactorList (queryVids);
|
||||
Params params = factorList_.back()->params();
|
||||
if (Globals::logDomain) {
|
||||
Util::exp (params);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::printSolverFlags (void) const
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "variable elimination [" ;
|
||||
ss << "elim_heuristic=" ;
|
||||
ElimHeuristic eh = ElimGraph::elimHeuristic;
|
||||
switch (eh) {
|
||||
case SEQUENTIAL: ss << "sequential"; break;
|
||||
case MIN_NEIGHBORS: ss << "min_neighbors"; break;
|
||||
case MIN_WEIGHT: ss << "min_weight"; break;
|
||||
case MIN_FILL: ss << "min_fill"; break;
|
||||
case WEIGHTED_MIN_FILL: ss << "weighted_min_fill"; break;
|
||||
}
|
||||
ss << ",log_domain=" << Util::toString (Globals::logDomain);
|
||||
ss << "]" ;
|
||||
cout << ss.str() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::createFactorList (void)
|
||||
{
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
factorList_.reserve (facNodes.size() * 2);
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
factorList_.push_back (new Factor (facNodes[i]->factor()));
|
||||
const VarNodes& neighs = facNodes[i]->neighbors();
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
unordered_map<VarId, vector<size_t>>::iterator it
|
||||
= varFactors_.find (neighs[j]->varId());
|
||||
if (it == varFactors_.end()) {
|
||||
it = varFactors_.insert (make_pair (
|
||||
neighs[j]->varId(), vector<size_t>())).first;
|
||||
}
|
||||
it->second.push_back (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::absorveEvidence (void)
|
||||
{
|
||||
if (Globals::verbosity > 2) {
|
||||
Util::printDashedLine();
|
||||
cout << "(initial factor list)" << endl;
|
||||
printActiveFactors();
|
||||
}
|
||||
const VarNodes& varNodes = fg.varNodes();
|
||||
for (size_t i = 0; i < varNodes.size(); i++) {
|
||||
if (varNodes[i]->hasEvidence()) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "-> aborving evidence on ";
|
||||
cout << varNodes[i]->label() << " = " ;
|
||||
cout << varNodes[i]->getEvidence() << endl;
|
||||
}
|
||||
const vector<size_t>& idxs =
|
||||
varFactors_.find (varNodes[i]->varId())->second;
|
||||
for (size_t j = 0; j < idxs.size(); j++) {
|
||||
Factor* factor = factorList_[idxs[j]];
|
||||
if (factor->nrArguments() == 1) {
|
||||
factorList_[idxs[j]] = 0;
|
||||
} else {
|
||||
factorList_[idxs[j]]->absorveEvidence (
|
||||
varNodes[i]->varId(), varNodes[i]->getEvidence());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::findEliminationOrder (const VarIds& vids)
|
||||
{
|
||||
elimOrder_ = ElimGraph::getEliminationOrder (factorList_, vids);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::processFactorList (const VarIds& vids)
|
||||
{
|
||||
totalFactorSize_ = 0;
|
||||
largestFactorSize_ = 0;
|
||||
for (size_t i = 0; i < elimOrder_.size(); i++) {
|
||||
if (Globals::verbosity >= 2) {
|
||||
if (Globals::verbosity >= 3) {
|
||||
Util::printDashedLine();
|
||||
printActiveFactors();
|
||||
}
|
||||
cout << "-> summing out " ;
|
||||
cout << fg.getVarNode (elimOrder_[i])->label() << endl;
|
||||
}
|
||||
eliminate (elimOrder_[i]);
|
||||
}
|
||||
|
||||
Factor* finalFactor = new Factor();
|
||||
for (size_t i = 0; i < factorList_.size(); i++) {
|
||||
if (factorList_[i]) {
|
||||
finalFactor->multiply (*factorList_[i]);
|
||||
delete factorList_[i];
|
||||
factorList_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VarIds unobservedVids;
|
||||
for (size_t i = 0; i < vids.size(); i++) {
|
||||
if (fg.getVarNode (vids[i])->hasEvidence() == false) {
|
||||
unobservedVids.push_back (vids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
finalFactor->reorderArguments (unobservedVids);
|
||||
finalFactor->normalize();
|
||||
factorList_.push_back (finalFactor);
|
||||
if (Globals::verbosity > 0) {
|
||||
cout << "total factor size: " << totalFactorSize_ << endl;
|
||||
cout << "largest factor size: " << largestFactorSize_ << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::eliminate (VarId elimVar)
|
||||
{
|
||||
Factor* result = 0;
|
||||
vector<size_t>& idxs = varFactors_.find (elimVar)->second;
|
||||
for (size_t i = 0; i < idxs.size(); i++) {
|
||||
size_t idx = idxs[i];
|
||||
if (factorList_[idx]) {
|
||||
if (result == 0) {
|
||||
result = new Factor (*factorList_[idx]);
|
||||
} else {
|
||||
result->multiply (*factorList_[idx]);
|
||||
}
|
||||
delete factorList_[idx];
|
||||
factorList_[idx] = 0;
|
||||
}
|
||||
}
|
||||
totalFactorSize_ += result->size();
|
||||
if (result->size() > largestFactorSize_) {
|
||||
largestFactorSize_ = result->size();
|
||||
}
|
||||
if (result != 0 && result->nrArguments() != 1) {
|
||||
result->sumOut (elimVar);
|
||||
factorList_.push_back (result);
|
||||
const VarIds& resultVarIds = result->arguments();
|
||||
for (size_t i = 0; i < resultVarIds.size(); i++) {
|
||||
vector<size_t>& idxs =
|
||||
varFactors_.find (resultVarIds[i])->second;
|
||||
idxs.push_back (factorList_.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
VarElim::printActiveFactors (void)
|
||||
{
|
||||
for (size_t i = 0; i < factorList_.size(); i++) {
|
||||
if (factorList_[i] != 0) {
|
||||
cout << factorList_[i]->getLabel() << " " ;
|
||||
cout << factorList_[i]->params() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
#ifndef HORUS_VARELIM_H
|
||||
#define HORUS_VARELIM_H
|
||||
|
||||
#include "unordered_map"
|
||||
|
||||
#include "GroundSolver.h"
|
||||
#include "FactorGraph.h"
|
||||
#include "Horus.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class VarElim : public GroundSolver
|
||||
{
|
||||
public:
|
||||
VarElim (const FactorGraph& fg) : GroundSolver (fg) { }
|
||||
|
||||
~VarElim (void);
|
||||
|
||||
Params solveQuery (VarIds);
|
||||
|
||||
void printSolverFlags (void) const;
|
||||
|
||||
private:
|
||||
void createFactorList (void);
|
||||
|
||||
void absorveEvidence (void);
|
||||
|
||||
void findEliminationOrder (const VarIds&);
|
||||
|
||||
void processFactorList (const VarIds&);
|
||||
|
||||
void eliminate (VarId);
|
||||
|
||||
void printActiveFactors (void);
|
||||
|
||||
Factors factorList_;
|
||||
VarIds elimOrder_;
|
||||
unsigned largestFactorSize_;
|
||||
unsigned totalFactorSize_;
|
||||
unordered_map<VarId, vector<size_t>> varFactors_;
|
||||
};
|
||||
|
||||
#endif // HORUS_VARELIM_H
|
||||
|
@ -1,288 +0,0 @@
|
||||
#include "WeightedBp.h"
|
||||
|
||||
|
||||
WeightedBp::~WeightedBp (void)
|
||||
{
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
delete links_[i];
|
||||
}
|
||||
links_.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
WeightedBp::getPosterioriOf (VarId vid)
|
||||
{
|
||||
if (runned_ == false) {
|
||||
runSolver();
|
||||
}
|
||||
VarNode* var = fg.getVarNode (vid);
|
||||
assert (var != 0);
|
||||
Params probs;
|
||||
if (var->hasEvidence()) {
|
||||
probs.resize (var->range(), LogAware::noEvidence());
|
||||
probs[var->getEvidence()] = LogAware::withEvidence();
|
||||
} else {
|
||||
probs.resize (var->range(), LogAware::multIdenty());
|
||||
const BpLinks& links = ninf(var)->getLinks();
|
||||
if (Globals::logDomain) {
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
WeightedLink* l = static_cast<WeightedLink*> (links[i]);
|
||||
probs += l->powMessage();
|
||||
}
|
||||
LogAware::normalize (probs);
|
||||
Util::exp (probs);
|
||||
} else {
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
WeightedLink* l = static_cast<WeightedLink*> (links[i]);
|
||||
probs *= l->powMessage();
|
||||
}
|
||||
LogAware::normalize (probs);
|
||||
}
|
||||
}
|
||||
return probs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
WeightedBp::createLinks (void)
|
||||
{
|
||||
if (Globals::verbosity > 0) {
|
||||
cout << "compressed factor graph contains " ;
|
||||
cout << fg.nrVarNodes() << " variables and " ;
|
||||
cout << fg.nrFacNodes() << " factors " << endl;
|
||||
cout << endl;
|
||||
}
|
||||
const FacNodes& facNodes = fg.facNodes();
|
||||
for (size_t i = 0; i < facNodes.size(); i++) {
|
||||
const VarNodes& neighs = facNodes[i]->neighbors();
|
||||
for (size_t j = 0; j < neighs.size(); j++) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << "creating link " ;
|
||||
cout << facNodes[i]->getLabel();
|
||||
cout << " -- " ;
|
||||
cout << neighs[j]->label();
|
||||
cout << " idx=" << j << ", weight=" << weights_[i][j] << endl;
|
||||
}
|
||||
links_.push_back (new WeightedLink (
|
||||
facNodes[i], neighs[j], j, weights_[i][j]));
|
||||
}
|
||||
}
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
WeightedBp::maxResidualSchedule (void)
|
||||
{
|
||||
if (nIters_ == 1) {
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
calculateMessage (links_[i]);
|
||||
SortedOrder::iterator it = sortedOrder_.insert (links_[i]);
|
||||
linkMap_.insert (make_pair (links_[i], it));
|
||||
if (Globals::verbosity >= 1) {
|
||||
cout << "calculating " << links_[i]->toString() << endl;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < links_.size(); c++) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << endl << "current residuals:" << endl;
|
||||
for (SortedOrder::iterator it = sortedOrder_.begin();
|
||||
it != sortedOrder_.end(); ++it) {
|
||||
cout << " " << setw (30) << left << (*it)->toString();
|
||||
cout << "residual = " << (*it)->residual() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
SortedOrder::iterator it = sortedOrder_.begin();
|
||||
BpLink* link = *it;
|
||||
if (Globals::verbosity >= 1) {
|
||||
cout << "updating " << (*sortedOrder_.begin())->toString() << endl;
|
||||
}
|
||||
if (link->residual() < BpOptions::accuracy) {
|
||||
return;
|
||||
}
|
||||
link->updateMessage();
|
||||
link->clearResidual();
|
||||
sortedOrder_.erase (it);
|
||||
linkMap_.find (link)->second = sortedOrder_.insert (link);
|
||||
|
||||
// update the messages that depend on message source --> destin
|
||||
const FacNodes& factorNeighbors = link->varNode()->neighbors();
|
||||
for (size_t i = 0; i < factorNeighbors.size(); i++) {
|
||||
const BpLinks& links = ninf(factorNeighbors[i])->getLinks();
|
||||
for (size_t j = 0; j < links.size(); j++) {
|
||||
if (links[j]->varNode() != link->varNode()) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << " calculating " << links[j]->toString() << endl;
|
||||
}
|
||||
calculateMessage (links[j]);
|
||||
BpLinkMap::iterator iter = linkMap_.find (links[j]);
|
||||
sortedOrder_.erase (iter->second);
|
||||
iter->second = sortedOrder_.insert (links[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// in counting bp, the message that a variable X sends to
|
||||
// to a factor F depends on the message that F sent to the X
|
||||
const BpLinks& links = ninf(link->facNode())->getLinks();
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
if (links[i]->varNode() != link->varNode()) {
|
||||
if (Globals::verbosity > 1) {
|
||||
cout << " calculating " << links[i]->toString() << endl;
|
||||
}
|
||||
calculateMessage (links[i]);
|
||||
BpLinkMap::iterator iter = linkMap_.find (links[i]);
|
||||
sortedOrder_.erase (iter->second);
|
||||
iter->second = sortedOrder_.insert (links[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
WeightedBp::calcFactorToVarMsg (BpLink* _link)
|
||||
{
|
||||
WeightedLink* link = static_cast<WeightedLink*> (_link);
|
||||
FacNode* src = link->facNode();
|
||||
const VarNode* dst = link->varNode();
|
||||
const BpLinks& links = ninf(src)->getLinks();
|
||||
// calculate the product of messages that were sent
|
||||
// to factor `src', except from var `dst'
|
||||
unsigned reps = 1;
|
||||
unsigned msgSize = Util::sizeExpected (src->factor().ranges());
|
||||
Params msgProduct (msgSize, LogAware::multIdenty());
|
||||
if (Globals::logDomain) {
|
||||
for (size_t i = links.size(); i-- > 0; ) {
|
||||
const WeightedLink* l = static_cast<const WeightedLink*> (links[i]);
|
||||
if ( ! (l->varNode() == dst && l->index() == link->index())) {
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " message from " << links[i]->varNode()->label();
|
||||
cout << ": " ;
|
||||
}
|
||||
Util::apply_n_times (msgProduct, getVarToFactorMsg (links[i]),
|
||||
reps, std::plus<double>());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
reps *= links[i]->varNode()->range();
|
||||
}
|
||||
} else {
|
||||
for (size_t i = links.size(); i-- > 0; ) {
|
||||
const WeightedLink* l = static_cast<const WeightedLink*> (links[i]);
|
||||
if ( ! (l->varNode() == dst && l->index() == link->index())) {
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " message from " << links[i]->varNode()->label();
|
||||
cout << ": " ;
|
||||
}
|
||||
Util::apply_n_times (msgProduct, getVarToFactorMsg (links[i]),
|
||||
reps, std::multiplies<double>());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
reps *= links[i]->varNode()->range();
|
||||
}
|
||||
}
|
||||
Factor result (src->factor().arguments(),
|
||||
src->factor().ranges(), msgProduct);
|
||||
assert (msgProduct.size() == src->factor().size());
|
||||
if (Globals::logDomain) {
|
||||
result.params() += src->factor().params();
|
||||
} else {
|
||||
result.params() *= src->factor().params();
|
||||
}
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " message product: " << msgProduct << endl;
|
||||
cout << " original factor: " << src->factor().params() << endl;
|
||||
cout << " factor product: " << result.params() << endl;
|
||||
}
|
||||
result.sumOutAllExceptIndex (link->index());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " marginalized: " << result.params() << endl;
|
||||
}
|
||||
link->nextMessage() = result.params();
|
||||
LogAware::normalize (link->nextMessage());
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " curr msg: " << link->message() << endl;
|
||||
cout << " next msg: " << link->nextMessage() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Params
|
||||
WeightedBp::getVarToFactorMsg (const BpLink* _link) const
|
||||
{
|
||||
const WeightedLink* link = static_cast<const WeightedLink*> (_link);
|
||||
const VarNode* src = link->varNode();
|
||||
const FacNode* dst = link->facNode();
|
||||
Params msg;
|
||||
if (src->hasEvidence()) {
|
||||
msg.resize (src->range(), LogAware::noEvidence());
|
||||
double value = link->message()[src->getEvidence()];
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
msg[src->getEvidence()] = value;
|
||||
cout << msg << "^" << link->weight() << "-1" ;
|
||||
}
|
||||
msg[src->getEvidence()] = LogAware::pow (value, link->weight() - 1);
|
||||
} else {
|
||||
msg = link->message();
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << msg << "^" << link->weight() << "-1" ;
|
||||
}
|
||||
LogAware::pow (msg, link->weight() - 1);
|
||||
}
|
||||
const BpLinks& links = ninf(src)->getLinks();
|
||||
if (Globals::logDomain) {
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
WeightedLink* l = static_cast<WeightedLink*> (links[i]);
|
||||
if ( ! (l->facNode() == dst && l->index() == link->index())) {
|
||||
msg += l->powMessage();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < links.size(); i++) {
|
||||
WeightedLink* l = static_cast<WeightedLink*> (links[i]);
|
||||
if ( ! (l->facNode() == dst && l->index() == link->index())) {
|
||||
msg *= l->powMessage();
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " x " << l->nextMessage() << "^" << link->weight();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Constants::SHOW_BP_CALCS) {
|
||||
cout << " = " << msg;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
WeightedBp::printLinkInformation (void) const
|
||||
{
|
||||
for (size_t i = 0; i < links_.size(); i++) {
|
||||
WeightedLink* l = static_cast<WeightedLink*> (links_[i]);
|
||||
cout << l->toString() << ":" << endl;
|
||||
cout << " curr msg = " << l->message() << endl;
|
||||
cout << " next msg = " << l->nextMessage() << endl;
|
||||
cout << " pow msg = " << l->powMessage() << endl;
|
||||
cout << " index = " << l->index() << endl;
|
||||
cout << " weight = " << l->weight() << endl;
|
||||
cout << " residual = " << l->residual() << endl;
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
#ifndef HORUS_WEIGHTEDBP_H
|
||||
#define HORUS_WEIGHTEDBP_H
|
||||
|
||||
#include "BeliefProp.h"
|
||||
|
||||
class WeightedLink : public BpLink
|
||||
{
|
||||
public:
|
||||
WeightedLink (FacNode* fn, VarNode* vn, size_t idx, unsigned weight)
|
||||
: BpLink (fn, vn), index_(idx), weight_(weight),
|
||||
pwdMsg_(vn->range(), LogAware::one()) { }
|
||||
|
||||
size_t index (void) const { return index_; }
|
||||
|
||||
unsigned weight (void) const { return weight_; }
|
||||
|
||||
const Params& powMessage (void) const { return pwdMsg_; }
|
||||
|
||||
void updateMessage (void)
|
||||
{
|
||||
pwdMsg_ = *nextMsg_;
|
||||
swap (currMsg_, nextMsg_);
|
||||
LogAware::pow (pwdMsg_, weight_);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t index_;
|
||||
unsigned weight_;
|
||||
Params pwdMsg_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WeightedBp : public BeliefProp
|
||||
{
|
||||
public:
|
||||
WeightedBp (const FactorGraph& fg,
|
||||
const vector<vector<unsigned>>& weights)
|
||||
: BeliefProp (fg), weights_(weights) { }
|
||||
|
||||
~WeightedBp (void);
|
||||
|
||||
Params getPosterioriOf (VarId);
|
||||
|
||||
private:
|
||||
|
||||
void createLinks (void);
|
||||
|
||||
void maxResidualSchedule (void);
|
||||
|
||||
void calcFactorToVarMsg (BpLink*);
|
||||
|
||||
Params getVarToFactorMsg (const BpLink*) const;
|
||||
|
||||
void printLinkInformation (void) const;
|
||||
|
||||
vector<vector<unsigned>> weights_;
|
||||
};
|
||||
|
||||
#endif // HORUS_WEIGHTEDBP_H
|
||||
|
Reference in New Issue
Block a user