ok, second try

This commit is contained in:
Tiago Gomes 2012-05-23 14:56:01 +01:00
parent 3388917aa5
commit 6c77afb3ae
96 changed files with 17840 additions and 0 deletions

View File

@ -0,0 +1,86 @@
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <fstream>
#include <sstream>
#include "BayesBall.h"
#include "Util.h"
FactorGraph*
BayesBall::getMinimalFactorGraph (const VarIds& queryIds)
{
assert (fg_.isFromBayesNetwork());
Scheduling scheduling;
for (unsigned i = 0; i < queryIds.size(); i++) {
assert (dag_.getNode (queryIds[i]));
DAGraphNode* n = dag_.getNode (queryIds[i]);
scheduling.push (ScheduleInfo (n, false, true));
}
while (!scheduling.empty()) {
ScheduleInfo& sch = scheduling.front();
DAGraphNode* 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 (unsigned i = 0; i < facNodes.size(); i++) {
const DAGraphNode* 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 (unsigned i = 0; i < varNodes.size(); i++) {
if (varNodes[i]->hasEvidence()) {
VarNode* vn = fg->getVarNode (varNodes[i]->varId());
if (vn) {
vn->setEvidence (varNodes[i]->getEvidence());
}
}
}
}

View File

@ -0,0 +1,85 @@
#ifndef HORUS_BAYESBALL_H
#define HORUS_BAYESBALL_H
#include <vector>
#include <queue>
#include <list>
#include <map>
#include "FactorGraph.h"
#include "BayesNet.h"
#include "Horus.h"
using namespace std;
struct ScheduleInfo
{
ScheduleInfo (DAGraphNode* n, bool vfp, bool vfc) :
node(n), visitedFromParent(vfp), visitedFromChild(vfc) { }
DAGraphNode* 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 DAGraphNode* n, Scheduling& sch) const;
void scheduleChilds (const DAGraphNode* n, Scheduling& sch) const;
FactorGraph& fg_;
DAGraph& dag_;
};
inline void
BayesBall::scheduleParents (const DAGraphNode* n, Scheduling& sch) const
{
const vector<DAGraphNode*>& ps = n->parents();
for (vector<DAGraphNode*>::const_iterator it = ps.begin();
it != ps.end(); it++) {
sch.push (ScheduleInfo (*it, false, true));
}
}
inline void
BayesBall::scheduleChilds (const DAGraphNode* n, Scheduling& sch) const
{
const vector<DAGraphNode*>& cs = n->childs();
for (vector<DAGraphNode*>::const_iterator it = cs.begin();
it != cs.end(); it++) {
sch.push (ScheduleInfo (*it, true, false));
}
}
#endif // HORUS_BAYESBALL_H

View File

@ -0,0 +1,107 @@
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <fstream>
#include <sstream>
#include "BayesNet.h"
#include "Util.h"
void
DAGraph::addNode (DAGraphNode* n)
{
assert (Util::contains (varMap_, n->varId()) == false);
nodes_.push_back (n);
varMap_[n->varId()] = n;
}
void
DAGraph::addEdge (VarId vid1, VarId vid2)
{
unordered_map<VarId, DAGraphNode*>::iterator it1;
unordered_map<VarId, DAGraphNode*>::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 DAGraphNode*
DAGraph::getNode (VarId vid) const
{
unordered_map<VarId, DAGraphNode*>::const_iterator it;
it = varMap_.find (vid);
return it != varMap_.end() ? it->second : 0;
}
DAGraphNode*
DAGraph::getNode (VarId vid)
{
unordered_map<VarId, DAGraphNode*>::const_iterator it;
it = varMap_.find (vid);
return it != varMap_.end() ? it->second : 0;
}
void
DAGraph::setIndexes (void)
{
for (unsigned i = 0; i < nodes_.size(); i++) {
nodes_[i]->setIndex (i);
}
}
void
DAGraph::clear (void)
{
for (unsigned i = 0; i < nodes_.size(); i++) {
nodes_[i]->clear();
}
}
void
DAGraph::exportToGraphViz (const char* fileName)
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "DAGraph::exportToDotFile()" << endl;
abort();
}
out << "digraph {" << endl;
out << "ranksep=1" << endl;
for (unsigned 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 (unsigned i = 0; i < nodes_.size(); i++) {
const vector<DAGraphNode*>& childs = nodes_[i]->childs();
for (unsigned j = 0; j < childs.size(); j++) {
out << nodes_[i]->varId() << " -> " << childs[j]->varId();
out << " [style=bold]" << endl ;
}
}
out << "}" << endl;
out.close();
}

View File

@ -0,0 +1,88 @@
#ifndef HORUS_BAYESNET_H
#define HORUS_BAYESNET_H
#include <vector>
#include <queue>
#include <list>
#include <map>
#include "Var.h"
#include "Horus.h"
using namespace std;
class Var;
class DAGraphNode : public Var
{
public:
DAGraphNode (Var* v) : Var (v) , visited_(false),
markedOnTop_(false), markedOnBottom_(false) { }
const vector<DAGraphNode*>& childs (void) const { return childs_; }
vector<DAGraphNode*>& childs (void) { return childs_; }
const vector<DAGraphNode*>& parents (void) const { return parents_; }
vector<DAGraphNode*>& parents (void) { return parents_; }
void addParent (DAGraphNode* p) { parents_.push_back (p); }
void addChild (DAGraphNode* 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<DAGraphNode*> childs_;
vector<DAGraphNode*> parents_;
};
class DAGraph
{
public:
DAGraph (void) { }
void addNode (DAGraphNode* n);
void addEdge (VarId vid1, VarId vid2);
const DAGraphNode* getNode (VarId vid) const;
DAGraphNode* getNode (VarId vid);
bool empty (void) const { return nodes_.empty(); }
void setIndexes (void);
void clear (void);
void exportToGraphViz (const char*);
private:
vector<DAGraphNode*> nodes_;
unordered_map<VarId, DAGraphNode*> varMap_;
};
#endif // HORUS_BAYESNET_H

View File

@ -0,0 +1,526 @@
#include <cassert>
#include <limits>
#include <algorithm>
#include <iostream>
#include "BpSolver.h"
#include "FactorGraph.h"
#include "Factor.h"
#include "Indexer.h"
#include "Horus.h"
BpSolver::BpSolver (const FactorGraph& fg) : Solver (fg)
{
fg_ = &fg;
runned_ = false;
}
BpSolver::~BpSolver (void)
{
for (unsigned i = 0; i < varsI_.size(); i++) {
delete varsI_[i];
}
for (unsigned i = 0; i < facsI_.size(); i++) {
delete facsI_[i];
}
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
}
Params
BpSolver::solveQuery (VarIds queryVids)
{
assert (queryVids.empty() == false);
if (queryVids.size() == 1) {
return getPosterioriOf (queryVids[0]);
} else {
return getJointDistributionOf (queryVids);
}
}
void
BpSolver::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
BpSolver::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 SpLinkSet& links = ninf(var)->getLinks();
if (Globals::logDomain) {
for (unsigned i = 0; i < links.size(); i++) {
Util::add (probs, links[i]->getMessage());
}
LogAware::normalize (probs);
Util::fromLog (probs);
} else {
for (unsigned i = 0; i < links.size(); i++) {
Util::multiply (probs, links[i]->getMessage());
}
LogAware::normalize (probs);
}
}
return probs;
}
Params
BpSolver::getJointDistributionOf (const VarIds& jointVarIds)
{
if (runned_ == false) {
runSolver();
}
int idx = -1;
VarNode* vn = fg_->getVarNode (jointVarIds[0]);
const FacNodes& facNodes = vn->neighbors();
for (unsigned i = 0; i < facNodes.size(); i++) {
if (facNodes[i]->factor().contains (jointVarIds)) {
idx = i;
break;
}
}
if (idx == -1) {
return getJointByConditioning (jointVarIds);
} else {
Factor res (facNodes[idx]->factor());
const SpLinkSet& links = ninf(facNodes[idx])->getLinks();
for (unsigned i = 0; i < links.size(); i++) {
Factor msg ({links[i]->getVariable()->varId()},
{links[i]->getVariable()->range()},
getVar2FactorMsg (links[i]));
res.multiply (msg);
}
res.sumOutAllExcept (jointVarIds);
res.reorderArguments (jointVarIds);
res.normalize();
Params jointDist = res.params();
if (Globals::logDomain) {
Util::fromLog (jointDist);
}
return jointDist;
}
}
void
BpSolver::runSolver (void)
{
clock_t start;
if (Constants::COLLECT_STATS) {
start = clock();
}
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:
random_shuffle (links_.begin(), links_.end());
// no break
case BpOptions::Schedule::SEQ_FIXED:
for (unsigned i = 0; i < links_.size(); i++) {
calculateAndUpdateMessage (links_[i]);
}
break;
case BpOptions::Schedule::PARALLEL:
for (unsigned i = 0; i < links_.size(); i++) {
calculateMessage (links_[i]);
}
for (unsigned 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 << "Sum-Product converged in " ;
cout << nIters_ << " iterations" << endl;
} else {
cout << "The maximum number of iterations was hit, terminating..." ;
cout << endl;
}
cout << endl;
}
unsigned size = fg_->varNodes().size();
if (Constants::COLLECT_STATS) {
unsigned nIters = 0;
bool loopy = fg_->isTree() == false;
if (loopy) nIters = nIters_;
double time = (double (clock() - start)) / CLOCKS_PER_SEC;
Statistics::updateStatistics (size, loopy, nIters, time);
}
runned_ = true;
}
void
BpSolver::createLinks (void)
{
const FacNodes& facNodes = fg_->facNodes();
for (unsigned i = 0; i < facNodes.size(); i++) {
const VarNodes& neighbors = facNodes[i]->neighbors();
for (unsigned j = 0; j < neighbors.size(); j++) {
links_.push_back (new SpLink (facNodes[i], neighbors[j]));
}
}
}
void
BpSolver::maxResidualSchedule (void)
{
if (nIters_ == 1) {
for (unsigned 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 (unsigned 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)->getResidual() << endl;
}
}
SortedOrder::iterator it = sortedOrder_.begin();
SpLink* link = *it;
if (link->getResidual() < 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->getVariable()->neighbors();
for (unsigned i = 0; i < factorNeighbors.size(); i++) {
if (factorNeighbors[i] != link->getFactor()) {
const SpLinkSet& links = ninf(factorNeighbors[i])->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (links[j]->getVariable() != link->getVariable()) {
calculateMessage (links[j]);
SpLinkMap::iterator iter = linkMap_.find (links[j]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (links[j]);
}
}
}
}
if (Globals::verbosity > 1) {
Util::printDashedLine();
}
}
}
void
BpSolver::calculateFactor2VariableMsg (SpLink* link)
{
FacNode* src = link->getFactor();
const VarNode* dst = link->getVariable();
const SpLinkSet& links = ninf(src)->getLinks();
// calculate the product of messages that were sent
// to factor `src', except from var `dst'
unsigned msgSize = 1;
for (unsigned i = 0; i < links.size(); i++) {
msgSize *= links[i]->getVariable()->range();
}
unsigned repetitions = 1;
Params msgProduct (msgSize, LogAware::multIdenty());
if (Globals::logDomain) {
for (int i = links.size() - 1; i >= 0; i--) {
if (links[i]->getVariable() != dst) {
if (Constants::SHOW_BP_CALCS) {
cout << " message from " << links[i]->getVariable()->label();
cout << ": " ;
}
Util::add (msgProduct, getVar2FactorMsg (links[i]), repetitions);
repetitions *= links[i]->getVariable()->range();
if (Constants::SHOW_BP_CALCS) {
cout << endl;
}
} else {
unsigned range = links[i]->getVariable()->range();
Util::add (msgProduct, Params (range, 0.0), repetitions);
repetitions *= range;
}
}
} else {
for (int i = links.size() - 1; i >= 0; i--) {
if (links[i]->getVariable() != dst) {
if (Constants::SHOW_BP_CALCS) {
cout << " message from " << links[i]->getVariable()->label();
cout << ": " ;
}
Util::multiply (msgProduct, getVar2FactorMsg (links[i]), repetitions);
repetitions *= links[i]->getVariable()->range();
if (Constants::SHOW_BP_CALCS) {
cout << endl;
}
} else {
unsigned range = links[i]->getVariable()->range();
Util::multiply (msgProduct, Params (range, 1.0), repetitions);
repetitions *= 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->getNextMessage() = result.params();
LogAware::normalize (link->getNextMessage());
if (Constants::SHOW_BP_CALCS) {
cout << " curr msg: " << link->getMessage() << endl;
cout << " next msg: " << link->getNextMessage() << endl;
}
}
Params
BpSolver::getVar2FactorMsg (const SpLink* link) const
{
const VarNode* src = link->getVariable();
const FacNode* dst = link->getFactor();
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;
}
const SpLinkSet& links = ninf (src)->getLinks();
if (Globals::logDomain) {
SpLinkSet::const_iterator it;
for (it = links.begin(); it != links.end(); ++ it) {
Util::add (msg, (*it)->getMessage());
if (Constants::SHOW_BP_CALCS) {
cout << " x " << (*it)->getMessage();
}
}
Util::subtract (msg, link->getMessage());
} else {
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dst) {
Util::multiply (msg, links[i]->getMessage());
if (Constants::SHOW_BP_CALCS) {
cout << " x " << links[i]->getMessage();
}
}
}
}
if (Constants::SHOW_BP_CALCS) {
cout << " = " << msg;
}
return msg;
}
Params
BpSolver::getJointByConditioning (const VarIds& jointVarIds) const
{
VarNodes jointVars;
for (unsigned i = 0; i < jointVarIds.size(); i++) {
assert (fg_->getVarNode (jointVarIds[i]));
jointVars.push_back (fg_->getVarNode (jointVarIds[i]));
}
FactorGraph* fg = new FactorGraph (*fg_);
BpSolver solver (*fg);
solver.runSolver();
Params prevBeliefs = solver.getPosterioriOf (jointVarIds[0]);
VarIds observedVids = {jointVars[0]->varId()};
for (unsigned i = 1; i < jointVarIds.size(); i++) {
assert (jointVars[i]->hasEvidence() == false);
Params newBeliefs;
Vars observedVars;
for (unsigned j = 0; j < observedVids.size(); j++) {
observedVars.push_back (fg->getVarNode (observedVids[j]));
}
StatesIndexer idx (observedVars, false);
while (idx.valid()) {
for (unsigned j = 0; j < observedVars.size(); j++) {
observedVars[j]->setEvidence (idx[j]);
}
++ idx;
BpSolver solver (*fg);
solver.runSolver();
Params beliefs = solver.getPosterioriOf (jointVarIds[i]);
for (unsigned k = 0; k < beliefs.size(); k++) {
newBeliefs.push_back (beliefs[k]);
}
}
int count = -1;
for (unsigned 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());
}
return prevBeliefs;
}
void
BpSolver::initializeSolver (void)
{
const VarNodes& varNodes = fg_->varNodes();
varsI_.reserve (varNodes.size());
for (unsigned i = 0; i < varNodes.size(); i++) {
varsI_.push_back (new SPNodeInfo());
}
const FacNodes& facNodes = fg_->facNodes();
facsI_.reserve (facNodes.size());
for (unsigned i = 0; i < facNodes.size(); i++) {
facsI_.push_back (new SPNodeInfo());
}
createLinks();
for (unsigned i = 0; i < links_.size(); i++) {
FacNode* src = links_[i]->getFactor();
VarNode* dst = links_[i]->getVariable();
ninf (dst)->addSpLink (links_[i]);
ninf (src)->addSpLink (links_[i]);
}
}
bool
BpSolver::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()))->getResidual();
if (maxResidual > BpOptions::accuracy) {
converged = false;
} else {
converged = true;
}
} else {
for (unsigned i = 0; i < links_.size(); i++) {
double residual = links_[i]->getResidual();
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
BpSolver::printLinkInformation (void) const
{
for (unsigned i = 0; i < links_.size(); i++) {
SpLink* l = links_[i];
cout << l->toString() << ":" << endl;
cout << " curr msg = " ;
cout << l->getMessage() << endl;
cout << " next msg = " ;
cout << l->getNextMessage() << endl;
cout << " residual = " << l->getResidual() << endl;
}
}

View File

@ -0,0 +1,190 @@
#ifndef HORUS_BPSOLVER_H
#define HORUS_BPSOLVER_H
#include <set>
#include <vector>
#include <sstream>
#include "Solver.h"
#include "Factor.h"
#include "FactorGraph.h"
#include "Util.h"
using namespace std;
class SpLink
{
public:
SpLink (FacNode* fn, VarNode* vn)
{
fac_ = fn;
var_ = vn;
v1_.resize (vn->range(), LogAware::tl (1.0 / vn->range()));
v2_.resize (vn->range(), LogAware::tl (1.0 / vn->range()));
currMsg_ = &v1_;
nextMsg_ = &v2_;
msgSended_ = false;
residual_ = 0.0;
}
virtual ~SpLink (void) { };
FacNode* getFactor (void) const { return fac_; }
VarNode* getVariable (void) const { return var_; }
const Params& getMessage (void) const { return *currMsg_; }
Params& getNextMessage (void) { return *nextMsg_; }
bool messageWasSended (void) const { return msgSended_; }
double getResidual (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_);
msgSended_ = true;
}
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_;
bool msgSended_;
double residual_;
};
typedef vector<SpLink*> SpLinkSet;
class SPNodeInfo
{
public:
void addSpLink (SpLink* link) { links_.push_back (link); }
const SpLinkSet& getLinks (void) { return links_; }
private:
SpLinkSet links_;
};
class BpSolver : public Solver
{
public:
BpSolver (const FactorGraph&);
virtual ~BpSolver (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 calculateFactor2VariableMsg (SpLink*);
virtual Params getVar2FactorMsg (const SpLink*) const;
virtual Params getJointByConditioning (const VarIds&) const;
SPNodeInfo* ninf (const VarNode* var) const
{
return varsI_[var->getIndex()];
}
SPNodeInfo* ninf (const FacNode* fac) const
{
return facsI_[fac->getIndex()];
}
void calculateAndUpdateMessage (SpLink* link, bool calcResidual = true)
{
if (Globals::verbosity > 2) {
cout << "calculating & updating " << link->toString() << endl;
}
calculateFactor2VariableMsg (link);
if (calcResidual) {
link->updateResidual();
}
link->updateMessage();
}
void calculateMessage (SpLink* link, bool calcResidual = true)
{
if (Globals::verbosity > 2) {
cout << "calculating " << link->toString() << endl;
}
calculateFactor2VariableMsg (link);
if (calcResidual) {
link->updateResidual();
}
}
void updateMessage (SpLink* link)
{
link->updateMessage();
if (Globals::verbosity > 2) {
cout << "updating " << link->toString() << endl;
}
}
struct CompareResidual
{
inline bool operator() (const SpLink* link1, const SpLink* link2)
{
return link1->getResidual() > link2->getResidual();
}
};
SpLinkSet links_;
unsigned nIters_;
vector<SPNodeInfo*> varsI_;
vector<SPNodeInfo*> facsI_;
bool runned_;
const FactorGraph* fg_;
typedef multiset<SpLink*, CompareResidual> SortedOrder;
SortedOrder sortedOrder_;
typedef unordered_map<SpLink*, SortedOrder::iterator> SpLinkMap;
SpLinkMap linkMap_;
private:
void initializeSolver (void);
bool converged (void);
virtual void printLinkInformation (void) const;
};
#endif // HORUS_BPSOLVER_H

View File

@ -0,0 +1,320 @@
#include "CFactorGraph.h"
#include "Factor.h"
bool CFactorGraph::checkForIdenticalFactors = true;
CFactorGraph::CFactorGraph (const FactorGraph& fg)
: freeColor_(0), groundFg_(&fg)
{
findIdenticalFactors();
setInitialColors();
createGroups();
}
CFactorGraph::~CFactorGraph (void)
{
for (unsigned i = 0; i < varClusters_.size(); i++) {
delete varClusters_[i];
}
for (unsigned i = 0; i < facClusters_.size(); i++) {
delete facClusters_[i];
}
}
void
CFactorGraph::findIdenticalFactors()
{
if (checkForIdenticalFactors == false) {
return;
}
const FacNodes& facNodes = groundFg_->facNodes();
for (unsigned i = 0; i < facNodes.size(); i++) {
facNodes[i]->factor().setDistId (Util::maxUnsigned());
}
unsigned groupCount = 1;
for (unsigned i = 0; i < facNodes.size(); i++) {
Factor& f1 = facNodes[i]->factor();
if (f1.distId() != Util::maxUnsigned()) {
continue;
}
f1.setDistId (groupCount);
for (unsigned 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
CFactorGraph::setInitialColors (void)
{
varColors_.resize (groundFg_->nrVarNodes());
facColors_.resize (groundFg_->nrFacNodes());
// create the initial variable colors
VarColorMap colorMap;
const VarNodes& varNodes = groundFg_->varNodes();
for (unsigned i = 0; i < varNodes.size(); i++) {
unsigned dsize = varNodes[i]->range();
VarColorMap::iterator it = colorMap.find (dsize);
if (it == colorMap.end()) {
it = colorMap.insert (make_pair (
dsize, Colors (dsize+1,-1))).first;
}
unsigned idx;
if (varNodes[i]->hasEvidence()) {
idx = varNodes[i]->getEvidence();
} else {
idx = dsize;
}
Colors& stateColors = it->second;
if (stateColors[idx] == -1) {
stateColors[idx] = getFreeColor();
}
setColor (varNodes[i], stateColors[idx]);
}
const FacNodes& facNodes = groundFg_->facNodes();
// create the initial factor colors
DistColorMap distColors;
for (unsigned 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, getFreeColor())).first;
}
setColor (facNodes[i], it->second);
}
}
void
CFactorGraph::createGroups (void)
{
VarSignMap varGroups;
FacSignMap facGroups;
unsigned nIters = 0;
bool groupsHaveChanged = true;
const VarNodes& varNodes = groundFg_->varNodes();
const FacNodes& facNodes = groundFg_->facNodes();
while (groupsHaveChanged || nIters == 1) {
nIters ++;
// set a new color to the variables with the same signature
unsigned prevVarGroupsSize = varGroups.size();
varGroups.clear();
for (unsigned 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 = getFreeColor();
VarNodes& groupMembers = it->second;
for (unsigned i = 0; i < groupMembers.size(); i++) {
setColor (groupMembers[i], newColor);
}
}
unsigned prevFactorGroupsSize = facGroups.size();
facGroups.clear();
// set a new color to the factors with the same signature
for (unsigned 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 = getFreeColor();
FacNodes& groupMembers = it->second;
for (unsigned i = 0; i < groupMembers.size(); i++) {
setColor (groupMembers[i], newColor);
}
}
groupsHaveChanged = prevVarGroupsSize != varGroups.size()
|| prevFactorGroupsSize != facGroups.size();
}
// printGroups (varGroups, facGroups);
createClusters (varGroups, facGroups);
}
void
CFactorGraph::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 (unsigned i = 0; i < groupVars.size(); i++) {
vid2VarCluster_.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 (unsigned i = 0; i < neighs.size(); i++) {
VarId vid = neighs[i]->varId();
varClusters.push_back (vid2VarCluster_.find (vid)->second);
}
facClusters_.push_back (new FacCluster (it->second, varClusters));
}
}
VarSignature
CFactorGraph::getSignature (const VarNode* varNode)
{
const FacNodes& neighs = varNode->neighbors();
VarSignature sign;
sign.reserve (neighs.size() + 1);
for (unsigned 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
CFactorGraph::getSignature (const FacNode* facNode)
{
const VarNodes& neighs = facNode->neighbors();
FacSignature sign;
sign.reserve (neighs.size() + 1);
for (unsigned i = 0; i < neighs.size(); i++) {
sign.push_back (getColor (neighs[i]));
}
sign.push_back (getColor (facNode));
return sign;
}
FactorGraph*
CFactorGraph::getGroundFactorGraph (void)
{
FactorGraph* fg = new FactorGraph();
for (unsigned i = 0; i < varClusters_.size(); i++) {
VarNode* newVar = new VarNode (varClusters_[i]->first());
varClusters_[i]->setRepresentative (newVar);
fg->addVarNode (newVar);
}
for (unsigned i = 0; i < facClusters_.size(); i++) {
Vars vars;
const VarClusters& clusters = facClusters_[i]->varClusters();
for (unsigned 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 (unsigned j = 0; j < vars.size(); j++) {
fg->addEdge (static_cast<VarNode*> (vars[j]), fn);
}
}
return fg;
}
unsigned
CFactorGraph::getEdgeCount (
const FacCluster* fc,
const VarCluster* vc,
unsigned index) const
{
unsigned count = 0;
VarId reprVid = vc->representative()->varId();
VarNode* groundVar = groundFg_->getVarNode (reprVid);
const FacNodes& neighs = groundVar->neighbors();
for (unsigned 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) == (int)index) {
count ++;
}
}
return count;
}
void
CFactorGraph::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 (unsigned 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 (unsigned i = 0; i < groupMembers.size(); i++) {
cout << groupMembers[i]->getLabel() << " " ;
}
count ++;
cout << endl;
}
}
}

View File

@ -0,0 +1,176 @@
#ifndef HORUS_CFACTORGRAPH_H
#define HORUS_CFACTORGRAPH_H
#include <unordered_map>
#include "FactorGraph.h"
#include "Factor.h"
#include "Util.h"
#include "Horus.h"
class VarCluster;
class FacCluster;
class VarSignatureHash;
class FacSignatureHash;
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, VarSignatureHash> VarSignMap;
typedef unordered_map<FacSignature, FacNodes, FacSignatureHash> FacSignMap;
typedef vector<VarCluster*> VarClusters;
typedef vector<FacCluster*> FacClusters;
typedef unordered_map<VarId, VarCluster*> VarId2VarCluster;
struct VarSignatureHash
{
size_t operator() (const VarSignature &sig) const
{
size_t val = hash<size_t>()(sig.size());
for (unsigned i = 0; i < sig.size(); i++) {
val ^= hash<size_t>()(sig[i].first);
val ^= hash<size_t>()(sig[i].second);
}
return val;
}
};
struct FacSignatureHash
{
size_t operator() (const FacSignature &sig) const
{
size_t val = hash<size_t>()(sig.size());
for (unsigned i = 0; i < sig.size(); i++) {
val ^= hash<size_t>()(sig[i]);
}
return val;
}
};
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_; }
VarClusters& varClusters (void) { return varClusters_; }
FacNode* representative (void) const { return repr_; }
void setRepresentative (FacNode* fn) { repr_ = fn; }
private:
FacNodes members_;
VarClusters varClusters_;
FacNode* repr_;
};
class CFactorGraph
{
public:
CFactorGraph (const FactorGraph&);
~CFactorGraph (void);
const VarClusters& varClusters (void) { return varClusters_; }
const FacClusters& facClusters (void) { return facClusters_; }
VarNode* getEquivalent (VarId vid)
{
VarCluster* vc = vid2VarCluster_.find (vid)->second;
return vc->representative();
}
FactorGraph* getGroundFactorGraph (void);
unsigned getEdgeCount (const FacCluster*,
const VarCluster*, unsigned index) const;
static bool checkForIdenticalFactors;
private:
Color getFreeColor (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;
Color freeColor_;
Colors varColors_;
Colors facColors_;
VarClusters varClusters_;
FacClusters facClusters_;
VarId2VarCluster vid2VarCluster_;
const FactorGraph* groundFg_;
};
#endif // HORUS_CFACTORGRAPH_H

View File

@ -0,0 +1,369 @@
#include "CbpSolver.h"
CbpSolver::CbpSolver (const FactorGraph& fg) : BpSolver (fg)
{
unsigned nrGroundVars, nrGroundFacs, nrNeighborless;
if (Constants::COLLECT_STATS) {
nrGroundVars = fg_->varNodes().size();
nrGroundFacs = fg_->facNodes().size();
const VarNodes& vars = fg_->varNodes();
nrNeighborless = 0;
for (unsigned i = 0; i < vars.size(); i++) {
const FacNodes& factors = vars[i]->neighbors();
if (factors.size() == 1 && factors[0]->neighbors().size() == 1) {
nrNeighborless ++;
}
}
}
cfg_ = new CFactorGraph (fg);
fg_ = cfg_->getGroundFactorGraph();
if (Constants::COLLECT_STATS) {
unsigned nrClusterVars = fg_->varNodes().size();
unsigned nrClusterFacs = fg_->facNodes().size();
Statistics::updateCompressingStatistics (nrGroundVars,
nrGroundFacs, nrClusterVars, nrClusterFacs, nrNeighborless);
}
}
CbpSolver::~CbpSolver (void)
{
delete cfg_;
delete fg_;
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
links_.clear();
}
void
CbpSolver::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 (CFactorGraph::checkForIdenticalFactors);
ss << "]" ;
cout << ss.str() << endl;
}
Params
CbpSolver::getPosterioriOf (VarId vid)
{
if (runned_ == false) {
runSolver();
}
assert (cfg_->getEquivalent (vid));
VarNode* var = cfg_->getEquivalent (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 SpLinkSet& links = ninf(var)->getLinks();
if (Globals::logDomain) {
for (unsigned i = 0; i < links.size(); i++) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links[i]);
Util::add (probs, l->poweredMessage());
}
LogAware::normalize (probs);
Util::fromLog (probs);
} else {
for (unsigned i = 0; i < links.size(); i++) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links[i]);
Util::multiply (probs, l->poweredMessage());
}
LogAware::normalize (probs);
}
}
return probs;
}
Params
CbpSolver::getJointDistributionOf (const VarIds& jointVids)
{
VarIds eqVarIds;
for (unsigned i = 0; i < jointVids.size(); i++) {
VarNode* vn = cfg_->getEquivalent (jointVids[i]);
eqVarIds.push_back (vn->varId());
}
return BpSolver::getJointDistributionOf (eqVarIds);
}
void
CbpSolver::createLinks (void)
{
if (Globals::verbosity > 0) {
cout << "compressed factor graph contains " ;
cout << fg_->nrVarNodes() << " variables and " ;
cout << fg_->nrFacNodes() << " factors " << endl;
cout << endl;
}
const FacClusters& fcs = cfg_->facClusters();
for (unsigned i = 0; i < fcs.size(); i++) {
const VarClusters& vcs = fcs[i]->varClusters();
for (unsigned j = 0; j < vcs.size(); j++) {
unsigned count = cfg_->getEdgeCount (fcs[i], vcs[j], j);
if (Globals::verbosity > 1) {
cout << "creating link " ;
cout << fcs[i]->representative()->getLabel();
cout << " -- " ;
cout << vcs[j]->representative()->label();
cout << " idx=" << j << ", count=" << count << endl;
}
links_.push_back (new CbpSolverLink (
fcs[i]->representative(), vcs[j]->representative(), j, count));
}
}
if (Globals::verbosity > 1) {
cout << endl;
}
}
void
CbpSolver::maxResidualSchedule (void)
{
if (nIters_ == 1) {
for (unsigned 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 (unsigned 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)->getResidual() << endl;
}
}
SortedOrder::iterator it = sortedOrder_.begin();
SpLink* link = *it;
if (Globals::verbosity >= 1) {
cout << "updating " << (*sortedOrder_.begin())->toString() << endl;
}
if (link->getResidual() < 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->getVariable()->neighbors();
for (unsigned i = 0; i < factorNeighbors.size(); i++) {
const SpLinkSet& links = ninf(factorNeighbors[i])->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (links[j]->getVariable() != link->getVariable()) {
if (Globals::verbosity > 1) {
cout << " calculating " << links[j]->toString() << endl;
}
calculateMessage (links[j]);
SpLinkMap::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 SpLinkSet& links = ninf(link->getFactor())->getLinks();
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getVariable() != link->getVariable()) {
if (Globals::verbosity > 1) {
cout << " calculating " << links[i]->toString() << endl;
}
calculateMessage (links[i]);
SpLinkMap::iterator iter = linkMap_.find (links[i]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (links[i]);
}
}
}
}
void
CbpSolver::calculateFactor2VariableMsg (SpLink* _link)
{
CbpSolverLink* link = static_cast<CbpSolverLink*> (_link);
FacNode* src = link->getFactor();
const VarNode* dst = link->getVariable();
const SpLinkSet& links = ninf(src)->getLinks();
// calculate the product of messages that were sent
// to factor `src', except from var `dst'
unsigned msgSize = 1;
for (unsigned i = 0; i < links.size(); i++) {
msgSize *= links[i]->getVariable()->range();
}
unsigned repetitions = 1;
Params msgProduct (msgSize, LogAware::multIdenty());
if (Globals::logDomain) {
for (int i = links.size() - 1; i >= 0; i--) {
const CbpSolverLink* cl = static_cast<const CbpSolverLink*> (links[i]);
if ( ! (cl->getVariable() == dst && cl->index() == link->index())) {
if (Constants::SHOW_BP_CALCS) {
cout << " message from " << links[i]->getVariable()->label();
cout << ": " ;
}
Util::add (msgProduct, getVar2FactorMsg (links[i]), repetitions);
repetitions *= links[i]->getVariable()->range();
if (Constants::SHOW_BP_CALCS) {
cout << endl;
}
} else {
unsigned range = links[i]->getVariable()->range();
Util::add (msgProduct, Params (range, 0.0), repetitions);
repetitions *= range;
}
}
} else {
for (int i = links.size() - 1; i >= 0; i--) {
const CbpSolverLink* cl = static_cast<const CbpSolverLink*> (links[i]);
if ( ! (cl->getVariable() == dst && cl->index() == link->index())) {
if (Constants::SHOW_BP_CALCS) {
cout << " message from " << links[i]->getVariable()->label();
cout << ": " ;
}
Util::multiply (msgProduct, getVar2FactorMsg (links[i]), repetitions);
repetitions *= links[i]->getVariable()->range();
if (Constants::SHOW_BP_CALCS) {
cout << endl;
}
} else {
unsigned range = links[i]->getVariable()->range();
Util::multiply (msgProduct, Params (range, 1.0), repetitions);
repetitions *= range;
}
}
}
Factor result (src->factor().arguments(),
src->factor().ranges(), msgProduct);
assert (msgProduct.size() == src->factor().size());
if (Globals::logDomain) {
for (unsigned i = 0; i < result.size(); i++) {
result[i] += src->factor()[i];
}
} else {
for (unsigned i = 0; i < result.size(); i++) {
result[i] *= src->factor()[i];
}
}
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->getNextMessage() = result.params();
LogAware::normalize (link->getNextMessage());
if (Constants::SHOW_BP_CALCS) {
cout << " curr msg: " << link->getMessage() << endl;
cout << " next msg: " << link->getNextMessage() << endl;
}
}
Params
CbpSolver::getVar2FactorMsg (const SpLink* _link) const
{
const CbpSolverLink* link = static_cast<const CbpSolverLink*> (_link);
const VarNode* src = link->getVariable();
const FacNode* dst = link->getFactor();
Params msg;
if (src->hasEvidence()) {
msg.resize (src->range(), LogAware::noEvidence());
double value = link->getMessage()[src->getEvidence()];
if (Constants::SHOW_BP_CALCS) {
msg[src->getEvidence()] = value;
cout << msg << "^" << link->nrEdges() << "-1" ;
}
msg[src->getEvidence()] = LogAware::pow (value, link->nrEdges() - 1);
} else {
msg = link->getMessage();
if (Constants::SHOW_BP_CALCS) {
cout << msg << "^" << link->nrEdges() << "-1" ;
}
LogAware::pow (msg, link->nrEdges() - 1);
}
const SpLinkSet& links = ninf(src)->getLinks();
if (Globals::logDomain) {
for (unsigned i = 0; i < links.size(); i++) {
CbpSolverLink* cl = static_cast<CbpSolverLink*> (links[i]);
if ( ! (cl->getFactor() == dst && cl->index() == link->index())) {
CbpSolverLink* cl = static_cast<CbpSolverLink*> (links[i]);
Util::add (msg, cl->poweredMessage());
}
}
} else {
for (unsigned i = 0; i < links.size(); i++) {
CbpSolverLink* cl = static_cast<CbpSolverLink*> (links[i]);
if ( ! (cl->getFactor() == dst && cl->index() == link->index())) {
Util::multiply (msg, cl->poweredMessage());
if (Constants::SHOW_BP_CALCS) {
cout << " x " << cl->getNextMessage() << "^" << link->nrEdges();
}
}
}
}
if (Constants::SHOW_BP_CALCS) {
cout << " = " << msg;
}
return msg;
}
void
CbpSolver::printLinkInformation (void) const
{
for (unsigned i = 0; i < links_.size(); i++) {
CbpSolverLink* cl = static_cast<CbpSolverLink*> (links_[i]);
cout << cl->toString() << ":" << endl;
cout << " curr msg = " << cl->getMessage() << endl;
cout << " next msg = " << cl->getNextMessage() << endl;
cout << " index = " << cl->index() << endl;
cout << " nr edges = " << cl->nrEdges() << endl;
cout << " powered = " << cl->poweredMessage() << endl;
cout << " residual = " << cl->getResidual() << endl;
}
}

View File

@ -0,0 +1,67 @@
#ifndef HORUS_CBP_H
#define HORUS_CBP_H
#include "BpSolver.h"
#include "CFactorGraph.h"
class Factor;
class CbpSolverLink : public SpLink
{
public:
CbpSolverLink (FacNode* fn, VarNode* vn, unsigned idx, unsigned count)
: SpLink (fn, vn), index_(idx), nrEdges_(count),
pwdMsg_(vn->range(), LogAware::one()) { }
unsigned index (void) const { return index_; }
unsigned nrEdges (void) const { return nrEdges_; }
const Params& poweredMessage (void) const { return pwdMsg_; }
void updateMessage (void)
{
pwdMsg_ = *nextMsg_;
swap (currMsg_, nextMsg_);
msgSended_ = true;
LogAware::pow (pwdMsg_, nrEdges_);
}
private:
unsigned index_;
unsigned nrEdges_;
Params pwdMsg_;
};
class CbpSolver : public BpSolver
{
public:
CbpSolver (const FactorGraph& fg);
~CbpSolver (void);
void printSolverFlags (void) const;
Params getPosterioriOf (VarId);
Params getJointDistributionOf (const VarIds&);
private:
void createLinks (void);
void maxResidualSchedule (void);
void calculateFactor2VariableMsg (SpLink*);
Params getVar2FactorMsg (const SpLink*) const;
void printLinkInformation (void) const;
CFactorGraph* cfg_;
};
#endif // HORUS_CBP_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,231 @@
#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_; }
unsigned 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 (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_;
}
unsigned 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&);
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 copyLogVar (LogVar,LogVar);
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&, unsigned, 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

View File

@ -0,0 +1,222 @@
#include <limits>
#include <fstream>
#include "ElimGraph.h"
ElimHeuristic ElimGraph::elimHeuristic = MIN_NEIGHBORS;
ElimGraph::ElimGraph (const vector<Factor*>& factors)
{
for (unsigned 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 (unsigned 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 (unsigned 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 (unsigned i = 0; i < nodes_.size(); i++) {
delete nodes_[i];
}
}
VarIds
ElimGraph::getEliminatingOrder (const VarIds& exclude)
{
VarIds elimOrder;
unmarked_.reserve (nodes_.size());
for (unsigned i = 0; i < nodes_.size(); i++) {
if (Util::contains (exclude, nodes_[i]->varId()) == false) {
unmarked_.insert (nodes_[i]);
}
}
unsigned nVarsToEliminate = nodes_.size() - exclude.size();
for (unsigned i = 0; i < nVarsToEliminate; i++) {
EgNode* node = getLowestCostNode();
unmarked_.remove (node);
const EGNeighs& neighs = node->neighbors();
for (unsigned 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 (unsigned i = 0; i < nodes_.size(); i++) {
cout << "node " << nodes_[i]->label() << " neighs:" ;
EGNeighs neighs = nodes_[i]->neighbors();
for (unsigned 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: cannot open file to write at " ;
cerr << "Markov::exportToDotFile()" << endl;
abort();
}
out << "strict graph {" << endl;
for (unsigned i = 0; i < nodes_.size(); i++) {
if (showNeighborless || nodes_[i]->neighbors().size() != 0) {
out << '"' << nodes_[i]->label() << '"' << endl;
}
}
for (unsigned i = 0; i < highlightVarIds.size(); i++) {
EgNode* node =getEgNode (highlightVarIds[i]);
if (node) {
out << '"' << node->label() << '"' ;
out << " [shape=box3d]" << endl;
} else {
cout << "error: invalid variable id: " << highlightVarIds[i] << endl;
abort();
}
}
for (unsigned i = 0; i < nodes_.size(); i++) {
EGNeighs neighs = nodes_[i]->neighbors();
for (unsigned j = 0; j < neighs.size(); j++) {
out << '"' << nodes_[i]->label() << '"' << " -- " ;
out << '"' << neighs[j]->label() << '"' << endl;
}
}
out << "}" << endl;
out.close();
}
VarIds
ElimGraph::getEliminationOrder (
const vector<Factor*> factors,
VarIds excludedVids)
{
ElimGraph graph (factors);
// graph.print();
// graph.exportToGraphViz ("_egg.dot");
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();
unsigned cost = 0;
EGNeighs::const_iterator it;
switch (elimHeuristic) {
case MIN_NEIGHBORS: {
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
cost = getNeighborsCost (*it);
if (cost < minCost) {
bestNode = *it;
minCost = cost;
}
}}
break;
case MIN_WEIGHT:
//cost = getWeightCost (unmarked_[i]);
break;
case MIN_FILL:
//cost = getFillCost (unmarked_[i]);
break;
case WEIGHTED_MIN_FILL:
//cost = getWeightedFillCost (unmarked_[i]);
break;
default:
assert (false);
}
assert (bestNode);
return bestNode;
}
void
ElimGraph::connectAllNeighbors (const EgNode* n)
{
const EGNeighs& neighs = n->neighbors();
if (neighs.size() > 0) {
for (unsigned i = 0; i < neighs.size() - 1; i++) {
for (unsigned j = i+1; j < neighs.size(); j++) {
if ( ! neighbors (neighs[i], neighs[j])) {
addEdge (neighs[i], neighs[j]);
}
}
}
}
}

View File

@ -0,0 +1,138 @@
#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
{
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 vector<Factor*>&); // TODO
~ElimGraph (void);
VarIds getEliminatingOrder (const VarIds&);
void print (void) const;
void exportToGraphViz (const char*, bool = true,
const VarIds& = VarIds()) const;
static VarIds getEliminationOrder (const vector<Factor*>, 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 (unsigned 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 (unsigned i = 0; i < neighs.size() - 1; i++) {
for (unsigned 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 (unsigned i = 0; i < neighs.size() - 1; i++) {
for (unsigned 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

View File

@ -0,0 +1,288 @@
#include <cstdlib>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <sstream>
#include "Factor.h"
#include "Indexer.h"
Factor::Factor (const Factor& g)
{
copyFromFactor (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::expectedSize (ranges_));
}
Factor::Factor (
const Vars& vars,
const Params& params,
unsigned distId)
{
for (unsigned 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::expectedSize (ranges_));
}
void
Factor::sumOut (VarId vid)
{
int idx = indexOf (vid);
assert (idx != -1);
if (vid == args_.back()) {
sumOutLastVariable(); // optimization
return;
}
if (vid == args_.front()) {
sumOutFirstVariable(); // optimization
return;
}
sumOutIndex (idx);
}
void
Factor::sumOutAllExcept (VarId vid)
{
assert (indexOf (vid) != -1);
while (args_.back() != vid) {
sumOutLastVariable();
}
while (args_.front() != vid) {
sumOutFirstVariable();
}
}
void
Factor::sumOutAllExcept (const VarIds& vids)
{
for (int i = 0; i < (int)args_.size(); i++) {
if (Util::contains (vids, args_[i]) == false) {
sumOut (args_[i]);
i --;
}
}
}
void
Factor::sumOutIndex (unsigned idx)
{
assert (idx < args_.size());
// number of parameters separating a different state of `var',
// with the states of the remaining variables fixed
unsigned varOffset = 1;
// number of parameters separating a different state of the variable
// on the left of `var', with the states of the remaining vars fixed
unsigned leftVarOffset = 1;
for (int i = args_.size() - 1; i > (int)idx; i--) {
varOffset *= ranges_[i];
leftVarOffset *= ranges_[i];
}
leftVarOffset *= ranges_[idx];
unsigned offset = 0;
unsigned count1 = 0;
unsigned count2 = 0;
unsigned newpsSize = params_.size() / ranges_[idx];
Params newps;
newps.reserve (newpsSize);
while (newps.size() < newpsSize) {
double sum = LogAware::addIdenty();
for (unsigned i = 0; i < ranges_[idx]; i++) {
if (Globals::logDomain) {
sum = Util::logSum (sum, params_[offset]);
} else {
sum += params_[offset];
}
offset += varOffset;
}
newps.push_back (sum);
count1 ++;
if (idx == args_.size() - 1) {
offset = count1 * ranges_[idx];
} else {
if (((offset - varOffset + 1) % leftVarOffset) == 0) {
count1 = 0;
count2 ++;
}
offset = (leftVarOffset * count2) + count1;
}
}
args_.erase (args_.begin() + idx);
ranges_.erase (ranges_.begin() + idx);
params_ = newps;
}
void
Factor::sumOutAllExceptIndex (unsigned idx)
{
assert (idx < args_.size());
while (args_.size() > idx + 1) {
sumOutLastVariable();
}
for (unsigned i = 0; i < idx; i++) {
sumOutFirstVariable();
}
}
void
Factor::sumOutFirstVariable (void)
{
assert (args_.size() > 1);
unsigned range = ranges_.front();
unsigned sep = params_.size() / range;
if (Globals::logDomain) {
for (unsigned i = sep; i < params_.size(); i++) {
params_[i % sep] = Util::logSum (params_[i % sep], params_[i]);
}
} else {
for (unsigned i = sep; i < params_.size(); i++) {
params_[i % sep] += params_[i];
}
}
params_.resize (sep);
args_.erase (args_.begin());
ranges_.erase (ranges_.begin());
}
void
Factor::sumOutLastVariable (void)
{
assert (args_.size() > 1);
unsigned range = ranges_.back();
unsigned idx1 = 0;
unsigned idx2 = 0;
if (Globals::logDomain) {
while (idx1 < params_.size()) {
params_[idx2] = params_[idx1];
idx1 ++;
for (unsigned j = 1; j < range; j++) {
params_[idx2] = Util::logSum (params_[idx2], params_[idx1]);
idx1 ++;
}
idx2 ++;
}
} else {
while (idx1 < params_.size()) {
params_[idx2] = params_[idx1];
idx1 ++;
for (unsigned j = 1; j < range; j++) {
params_[idx2] += params_[idx1];
idx1 ++;
}
idx2 ++;
}
}
params_.resize (idx2);
args_.pop_back();
ranges_.pop_back();
}
void
Factor::multiply (Factor& g)
{
if (args_.size() == 0) {
copyFromFactor (g);
return;
}
TFactor<VarId>::multiply (g);
}
void
Factor::reorderAccordingVarIds (void)
{
VarIds sortedVarIds = args_;
sort (sortedVarIds.begin(), sortedVarIds.end());
reorderArguments (sortedVarIds);
}
string
Factor::getLabel (void) const
{
stringstream ss;
ss << "f(" ;
for (unsigned 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 (unsigned i = 0; i < args_.size(); i++) {
vars.push_back (new Var (args_[i], ranges_[i]));
}
vector<string> jointStrings = Util::getStateLines (vars);
for (unsigned i = 0; i < params_.size(); i++) {
// cout << "[" << distId_ << "] " ;
cout << "f(" << jointStrings[i] << ")" ;
cout << " = " << params_[i] << endl;
}
cout << endl;
for (unsigned i = 0; i < vars.size(); i++) {
delete vars[i];
}
}
void
Factor::copyFromFactor (const Factor& g)
{
args_ = g.arguments();
ranges_ = g.ranges();
params_ = g.params();
distId_ = g.distId();
}

View File

@ -0,0 +1,305 @@
#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_; }
unsigned nrArguments (void) const { return args_.size(); }
unsigned 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 setParams (const Params& newParams)
{
params_ = newParams;
assert (params_.size() == Util::expectedSize (ranges_));
}
int indexOf (const T& t) const
{
int idx = -1;
for (unsigned i = 0; i < args_.size(); i++) {
if (args_[i] == t) {
idx = i;
break;
}
}
return idx;
}
const T& argument (unsigned idx) const
{
assert (idx < args_.size());
return args_[idx];
}
T& argument (unsigned idx)
{
assert (idx < args_.size());
return args_[idx];
}
unsigned range (unsigned idx) const
{
assert (idx < ranges_.size());
return ranges_[idx];
}
void multiply (TFactor<T>& g)
{
const vector<T>& g_args = g.arguments();
const Ranges& g_ranges = g.ranges();
const Params& g_params = g.params();
if (args_ == g_args) {
// optimization: if the factors contain the same set of args,
// we can do a 1 to 1 operation on the parameters
if (Globals::logDomain) {
Util::add (params_, g_params);
} else {
Util::multiply (params_, g_params);
}
} else {
bool sharedArgs = false;
vector<unsigned> gvarpos;
for (unsigned i = 0; i < g_args.size(); i++) {
int idx = indexOf (g_args[i]);
if (idx == -1) {
ullong newSize = params_.size() * g_ranges[i];
if (newSize > params_.max_size()) {
cerr << "error: an overflow occurred on factor multiplication" ;
cerr << endl;
abort();
}
insertArgument (g_args[i], g_ranges[i]);
gvarpos.push_back (args_.size() - 1);
} else {
sharedArgs = true;
gvarpos.push_back (idx);
}
}
if (sharedArgs == false) {
// optimization: if the original factors doesn't have common args,
// we don't need to marry the states of the common args
unsigned count = 0;
for (unsigned i = 0; i < params_.size(); i++) {
if (Globals::logDomain) {
params_[i] += g_params[count];
} else {
params_[i] *= g_params[count];
}
count ++;
if (count >= g_params.size()) {
count = 0;
}
}
} else {
StatesIndexer indexer (ranges_, false);
while (indexer.valid()) {
unsigned g_li = 0;
unsigned prod = 1;
for (int j = gvarpos.size() - 1; j >= 0; j--) {
g_li += indexer[gvarpos[j]] * prod;
prod *= g_ranges[j];
}
if (Globals::logDomain) {
params_[indexer] += g_params[g_li];
} else {
params_[indexer] *= g_params[g_li];
}
++ indexer;
}
}
}
}
void absorveEvidence (const T& arg, unsigned evidence)
{
int idx = indexOf (arg);
assert (idx != -1);
assert (evidence < ranges_[idx]);
Params copy = params_;
params_.clear();
params_.reserve (copy.size() / ranges_[idx]);
StatesIndexer indexer (ranges_);
for (unsigned i = 0; i < evidence; i++) {
indexer.increment (idx);
}
while (indexer.valid()) {
params_.push_back (copy[indexer]);
indexer.incrementExcluding (idx);
}
args_.erase (args_.begin() + idx);
ranges_.erase (ranges_.begin() + idx);
}
void reorderArguments (const vector<T> newArgs)
{
assert (newArgs.size() == args_.size());
if (newArgs == args_) {
return; // already in the wanted order
}
Ranges newRanges;
vector<unsigned> positions;
for (unsigned i = 0; i < newArgs.size(); i++) {
unsigned idx = indexOf (newArgs[i]);
newRanges.push_back (ranges_[idx]);
positions.push_back (idx);
}
unsigned N = ranges_.size();
Params newParams (params_.size());
for (unsigned i = 0; i < params_.size(); i++) {
unsigned li = i;
// calculate vector index corresponding to linear index
vector<unsigned> vi (N);
for (int k = N-1; k >= 0; k--) {
vi[k] = li % ranges_[k];
li /= ranges_[k];
}
// convert permuted vector index to corresponding linear index
unsigned prod = 1;
unsigned new_li = 0;
for (int k = N - 1; k >= 0; k--) {
new_li += vi[positions[k]] * prod;
prod *= ranges_[positions[k]];
}
newParams[new_li] = params_[i];
}
args_ = newArgs;
ranges_ = newRanges;
params_ = newParams;
}
bool contains (const T& arg) const
{
return Util::contains (args_, arg);
}
bool contains (const vector<T>& args) const
{
for (unsigned i = 0; i < args_.size(); i++) {
if (contains (args[i]) == false) {
return false;
}
}
return true;
}
double& operator[] (psize_t idx)
{
assert (idx < params_.size());
return params_[idx];
}
protected:
vector<T> args_;
Ranges ranges_;
Params params_;
unsigned distId_;
private:
void insertArgument (const T& arg, unsigned range)
{
assert (indexOf (arg) == -1);
Params copy = params_;
params_.clear();
params_.reserve (copy.size() * range);
for (unsigned i = 0; i < copy.size(); i++) {
for (unsigned reps = 0; reps < range; reps++) {
params_.push_back (copy[i]);
}
}
args_.push_back (arg);
ranges_.push_back (range);
}
void insertArguments (const vector<T>& args, const Ranges& ranges)
{
Params copy = params_;
unsigned nrStates = 1;
for (unsigned i = 0; i < args.size(); i++) {
assert (indexOf (args[i]) == -1);
args_.push_back (args[i]);
ranges_.push_back (ranges[i]);
nrStates *= ranges[i];
}
params_.clear();
params_.reserve (copy.size() * nrStates);
for (unsigned i = 0; i < copy.size(); i++) {
for (unsigned reps = 0; reps < nrStates; reps++) {
params_.push_back (copy[i]);
}
}
}
};
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 sumOutIndex (unsigned idx);
void sumOutAllExceptIndex (unsigned idx);
void sumOutFirstVariable (void);
void sumOutLastVariable (void);
void multiply (Factor&);
void reorderAccordingVarIds (void);
string getLabel (void) const;
void print (void) const;
private:
void copyFromFactor (const Factor& f);
};
#endif // HORUS_FACTOR_H

View File

@ -0,0 +1,465 @@
#include <set>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include "FactorGraph.h"
#include "Factor.h"
#include "BayesNet.h"
#include "BayesBall.h"
#include "Util.h"
FactorGraph::FactorGraph (const FactorGraph& fg)
{
const VarNodes& varNodes = fg.varNodes();
for (unsigned i = 0; i < varNodes.size(); i++) {
addVarNode (new VarNode (varNodes[i]));
}
const FacNodes& facNodes = fg.facNodes();
for (unsigned i = 0; i < facNodes.size(); i++) {
FacNode* facNode = new FacNode (facNodes[i]->factor());
addFacNode (facNode);
const VarNodes& neighs = facNodes[i]->neighbors();
for (unsigned j = 0; j < neighs.size(); j++) {
addEdge (varNodes_[neighs[j]->getIndex()], facNode);
}
}
fromBayesNet_ = fg.isFromBayesNetwork();
}
void
FactorGraph::readFromUaiFormat (const char* fileName)
{
std::ifstream is (fileName);
if (!is.is_open()) {
cerr << "error: cannot read from file " << fileName << endl;
abort();
}
ignoreLines (is);
string line;
getline (is, line);
if (line != "MARKOV") {
cerr << "error: the network must be a MARKOV network " << endl;
abort();
}
// 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 << "'" << endl;
cerr << "identifiers must be between 0 and " << ranges.size() - 1 ;
cerr << endl;
abort();
}
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::expectedSize (factorRanges[i])) {
cerr << "error: invalid number of parameters for factor nº " << i ;
cerr << ", expected: " << Util::expectedSize (factorRanges[i]);
cerr << ", given: " << nrParams << endl;
abort();
}
Params params (nrParams);
for (unsigned j = 0; j < nrParams; j++) {
is >> params[j];
}
if (Globals::logDomain) {
Util::toLog (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: cannot read from file " << fileName << endl;
abort();
}
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::expectedSize (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::toLog (params);
}
reverse (vids.begin(), vids.end());
Factor f (vids, ranges, params);
reverse (vids.begin(), vids.end());
f.reorderArguments (vids);
addFactor (f);
}
is.close();
}
FactorGraph::~FactorGraph (void)
{
for (unsigned i = 0; i < varNodes_.size(); i++) {
delete varNodes_[i];
}
for (unsigned 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 (unsigned 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();
}
DAGraph&
FactorGraph::getStructure (void)
{
assert (fromBayesNet_);
if (structure_.empty()) {
for (unsigned i = 0; i < varNodes_.size(); i++) {
structure_.addNode (new DAGraphNode (varNodes_[i]));
}
for (unsigned i = 0; i < facNodes_.size(); i++) {
const VarIds& vids = facNodes_[i]->factor().arguments();
for (unsigned j = 1; j < vids.size(); j++) {
structure_.addEdge (vids[j], vids[0]);
}
}
}
return structure_;
}
void
FactorGraph::print (void) const
{
for (unsigned 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 (unsigned j = 0; j < varNodes_[i]->neighbors().size(); j++) {
cout << varNodes_[i]->neighbors()[j]->getLabel() << " " ;
}
cout << endl << endl;
}
for (unsigned 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: cannot open file to write at " ;
cerr << "FactorGraph::exportToDotFile()" << endl;
abort();
}
out << "graph \"" << fileName << "\" {" << endl;
for (unsigned i = 0; i < varNodes_.size(); i++) {
if (varNodes_[i]->hasEvidence()) {
out << '"' << varNodes_[i]->label() << '"' ;
out << " [style=filled, fillcolor=yellow]" << endl;
}
}
for (unsigned i = 0; i < facNodes_.size(); i++) {
out << '"' << facNodes_[i]->getLabel() << '"' ;
out << " [label=\"" << facNodes_[i]->getLabel();
out << "\"" << ", shape=box]" << endl;
}
for (unsigned i = 0; i < facNodes_.size(); i++) {
const VarNodes& myVars = facNodes_[i]->neighbors();
for (unsigned 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: cannot open file " << fileName << endl;
abort();
}
out << "MARKOV" << endl;
out << varNodes_.size() << endl;
for (unsigned i = 0; i < varNodes_.size(); i++) {
out << varNodes_[i]->range() << " " ;
}
out << endl;
out << facNodes_.size() << endl;
for (unsigned i = 0; i < facNodes_.size(); i++) {
const VarNodes& factorVars = facNodes_[i]->neighbors();
out << factorVars.size();
for (unsigned j = 0; j < factorVars.size(); j++) {
out << " " << factorVars[j]->getIndex();
}
out << endl;
}
for (unsigned i = 0; i < facNodes_.size(); i++) {
Params params = facNodes_[i]->factor().params();
if (Globals::logDomain) {
Util::fromLog (params);
}
out << endl << params.size() << endl << " " ;
for (unsigned j = 0; j < params.size(); j++) {
out << params[j] << " " ;
}
out << endl;
}
out.close();
}
void
FactorGraph::exportToLibDaiFormat (const char* fileName) const
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file " << fileName << endl;
abort();
}
out << facNodes_.size() << endl << endl;
for (unsigned i = 0; i < facNodes_.size(); i++) {
const VarNodes& factorVars = facNodes_[i]->neighbors();
out << factorVars.size() << endl;
for (int j = factorVars.size() - 1; j >= 0; j--) {
out << factorVars[j]->varId() << " " ;
}
out << endl;
for (unsigned j = 0; j < factorVars.size(); j++) {
out << factorVars[j]->range() << " " ;
}
out << endl;
Params params = facNodes_[i]->factor().params();
if (Globals::logDomain) {
Util::fromLog (params);
}
out << params.size() << endl;
for (unsigned j = 0; j < params.size(); j++) {
out << j << " " << params[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 (unsigned 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 (unsigned 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 (unsigned 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
}

View File

@ -0,0 +1,145 @@
#ifndef HORUS_FACTORGRAPH_H
#define HORUS_FACTORGRAPH_H
#include <vector>
#include "Factor.h"
#include "BayesNet.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_; }
int getIndex (void) const { return index_; }
void setIndex (int index) { index_ = index; }
string getLabel (void) { return factor_.getLabel(); }
private:
DISALLOW_COPY_AND_ASSIGN (FacNode);
VarNodes neighs_;
Factor factor_;
int index_;
};
struct CompVarId
{
bool operator() (const Var* v1, const Var* v2) const
{
return v1->varId() < v2->varId();
}
};
class FactorGraph
{
public:
FactorGraph (bool fbn = false) : fromBayesNet_(fbn) { }
FactorGraph (const FactorGraph&);
~FactorGraph (void);
const VarNodes& varNodes (void) const { return varNodes_; }
const FacNodes& facNodes (void) const { return facNodes_; }
bool isFromBayesNetwork (void) const { return fromBayesNet_ ; }
unsigned nrVarNodes (void) const { return varNodes_.size(); }
unsigned 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;
DAGraph& 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_;
DAGraph structure_;
bool fromBayesNet_;
typedef unordered_map<unsigned, VarNode*> VarMap;
VarMap varMap_;
};
#endif // HORUS_FACTORGRAPH_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
#ifndef HORUS_FOVESOLVER_H
#define HORUS_FOVESOLVER_H
#include "ParfactorList.h"
class LiftedOperator
{
public:
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&, unsigned 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 (unsigned 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 (unsigned, ParfactorList&, const Grounds&);
static bool isToEliminate (Parfactor*, unsigned, const Grounds&);
unsigned 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 (
unsigned 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<unsigned, unsigned>> getAffectedFormulas (void);
unsigned group_;
unsigned lvIndex_;
ParfactorList& pfList_;
};
class FoveSolver
{
public:
FoveSolver (const ParfactorList& pfList) : pfList_(pfList) { }
Params getPosterioriOf (const Ground&);
Params getJointDistributionOf (const Grounds&);
void printSolverFlags (void) const;
static void absorveEvidence (
ParfactorList& pfList, ObservedFormulas& obsFormulas);
static Parfactors countNormalize (Parfactor*, const LogVarSet&);
static Parfactor calcGroundMultiplication (Parfactor pf);
private:
void runSolver (const Grounds&);
LiftedOperator* getBestOperation (const Grounds&);
void runWeakBayesBall (const Grounds&);
void shatterAgainstQuery (const Grounds&);
static Parfactors absorve (ObservedFormula&, Parfactor*);
ParfactorList pfList_;
double largestCost_;
};
#endif // HORUS_FOVESOLVER_H

View File

@ -0,0 +1,145 @@
#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 (int i = hist_.size() - 2; i >= 0; i--) {
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[] (unsigned 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);
}
unsigned
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 (unsigned idx) const
{
unsigned sum = 0;
for (unsigned i = 0; i < idx; i++) {
sum += hist_[i];
}
return size_ - sum;
}
void
HistogramSet::clearAfter (unsigned idx)
{
std::fill (hist_.begin() + idx + 1, hist_.end(), 0);
}

View File

@ -0,0 +1,45 @@
#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[] (unsigned idx) const;
unsigned nrHistograms (void) const;
void reset (void);
static vector<Histogram> getHistograms (unsigned ,unsigned);
static unsigned nrHistograms (unsigned, unsigned);
static unsigned findIndex (
const Histogram&, const vector<Histogram>&);
static vector<double> getNumAssigns (unsigned, unsigned);
friend std::ostream& operator<< (ostream &os, const HistogramSet& hs);
private:
unsigned maxCount (unsigned) const;
void clearAfter (unsigned);
unsigned size_;
Histogram hist_;
};
#endif // HORUS_HISTOGRAM_H

View File

@ -0,0 +1,81 @@
#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 Params::size_type psize_t;
typedef unsigned long long ullong;
enum InfAlgorithms
{
VE, // variable elimination
BP, // belief propagation
CBP // counting belief propagation
};
namespace Globals {
extern bool logDomain;
// level of debug information
extern unsigned verbosity;
extern InfAlgorithms infAlgorithm;
};
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;
const bool COLLECT_STATS = false;
};
namespace BpOptions
{
enum Schedule {
SEQ_FIXED,
SEQ_RANDOM,
PARALLEL,
MAX_RESIDUAL
};
extern Schedule schedule;
extern double accuracy;
extern unsigned maxIter;
}
#endif // HORUS_HORUS_H

View File

@ -0,0 +1,188 @@
#include <cstdlib>
#include <iostream>
#include <sstream>
#include "FactorGraph.h"
#include "VarElimSolver.h"
#include "BpSolver.h"
#include "CbpSolver.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] \
NETWORK_FILE [VARIABLE | OBSERVED_VARIABLE=EVIDENCE] ..." ;
int
main (int argc, const char* argv[])
{
if (argc <= 1) {
cerr << "error: no graphical model specified" << endl;
cerr << USAGE << endl;
exit (0);
}
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 (0);
}
if (rightArg.empty()) {
cerr << "error: missing right argument" << endl;
cerr << USAGE << endl;
exit (0);
}
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 graphical model must be defined either " ;
cerr << "in a UAI or libDAI file" << endl;
exit (0);
}
}
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 (0);
}
VarId vid = Util::stringToUnsigned (arg);
VarNode* queryVar = fg.getVarNode (vid);
if (queryVar == false) {
cerr << "error: unknow variable with id " ;
cerr << "`" << vid << "'" << endl;
exit (0);
}
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 (0);
}
if (Util::isInteger (leftArg) == false) {
cerr << "error: `" << leftArg << "' " ;
cerr << "is not a variable id" << endl ;
exit (0);
continue;
}
VarId vid = Util::stringToUnsigned (leftArg);
VarNode* observedVar = fg.getVarNode (vid);
if (observedVar == false) {
cerr << "error: unknow variable with id " ;
cerr << "`" << vid << "'" << endl;
exit (0);
}
if (rightArg.empty()) {
cerr << "error: missing right argument" << endl;
cerr << USAGE << endl;
exit (0);
}
if (Util::isInteger (rightArg) == false) {
cerr << "error: `" << rightArg << "' " ;
cerr << "is not a state index" << endl ;
exit (0);
}
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 (0);
}
observedVar->setEvidence (stateIdx);
}
}
return queryIds;
}
void
runSolver (const FactorGraph& fg, const VarIds& queryIds)
{
Solver* solver = 0;
switch (Globals::infAlgorithm) {
case InfAlgorithms::VE:
solver = new VarElimSolver (fg);
break;
case InfAlgorithms::BP:
solver = new BpSolver (fg);
break;
case InfAlgorithms::CBP:
solver = new CbpSolver (fg);
break;
default:
assert (false);
}
if (Globals::verbosity > 0) {
solver->printSolverFlags();
cout << endl;
}
if (queryIds.size() == 0) {
solver->printAllPosterioris();
} else {
solver->printAnswer (queryIds);
}
delete solver;
}

View File

@ -0,0 +1,586 @@
#include <cstdlib>
#include <vector>
#include <iostream>
#include <sstream>
#include <YapInterface.h>
#include "ParfactorList.h"
#include "FactorGraph.h"
#include "FoveSolver.h"
#include "VarElimSolver.h"
#include "BpSolver.h"
#include "CbpSolver.h"
#include "ElimGraph.h"
#include "BayesBall.h"
using namespace std;
typedef std::pair<ParfactorList*, ObservedFormulas*> LiftedNetwork;
Params readParameters (YAP_Term);
vector<unsigned> readUnsignedList (YAP_Term);
void readLiftedEvidence (YAP_Term, ObservedFormulas&);
Parfactor* readParfactor (YAP_Term);
void runVeSolver (FactorGraph* fg, const vector<VarIds>& tasks,
vector<Params>& results);
void runBpSolver (FactorGraph* fg, const vector<VarIds>& tasks,
vector<Params>& results);
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;
}
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 (unsigned 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);
}
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: constraint has free variables" << endl;
abort();
}
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;
cout << "has evidence()" << endl;
for (unsigned 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);
}
}
int
createGroundNetwork (void)
{
string factorsType ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG1)));
bool fromBayesNet = factorsType == "bayes";
FactorGraph* fg = new FactorGraph (fromBayesNet);
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);
}
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::toLog (params);
}
return params;
}
int
runLiftedSolver (void)
{
LiftedNetwork* network = (LiftedNetwork*) YAP_IntOfTerm (YAP_ARG1);
YAP_Term taskList = YAP_ARG2;
vector<Params> results;
ParfactorList pfListCopy (*network->first);
FoveSolver::absorveEvidence (pfListCopy, *network->second);
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);
}
FoveSolver solver (pfListCopy);
if (Globals::verbosity > 0 && taskList == YAP_ARG2) {
solver.printSolverFlags();
cout << endl;
}
if (queryVars.size() == 1) {
results.push_back (solver.getPosterioriOf (queryVars[0]));
} else {
results.push_back (solver.getJointDistributionOf (queryVars));
}
taskList = YAP_TailOfTerm (taskList);
}
YAP_Term list = YAP_TermNil();
for (int i = results.size() - 1; i >= 0; i--) {
const Params& beliefs = results[i];
YAP_Term queryBeliefsL = YAP_TermNil();
for (int j = beliefs.size() - 1; j >= 0; j--) {
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 YAP_Unify (list, 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);
}
vector<Params> results;
if (Globals::infAlgorithm == InfAlgorithms::VE) {
runVeSolver (fg, tasks, results);
} else {
runBpSolver (fg, tasks, results);
}
YAP_Term list = YAP_TermNil();
for (int i = results.size() - 1; i >= 0; i--) {
const Params& beliefs = results[i];
YAP_Term queryBeliefsL = YAP_TermNil();
for (int j = beliefs.size() - 1; j >= 0; j--) {
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 YAP_Unify (list, YAP_ARG3);
}
void runVeSolver (
FactorGraph* fg,
const vector<VarIds>& tasks,
vector<Params>& results)
{
results.reserve (tasks.size());
for (unsigned i = 0; i < tasks.size(); i++) {
FactorGraph* mfg = fg;
if (fg->isFromBayesNetwork()) {
// mfg = BayesBall::getMinimalFactorGraph (*fg, tasks[i]);
}
// VarElimSolver solver (*mfg);
VarElimSolver solver (*fg); //FIXME
if (Globals::verbosity > 0 && i == 0) {
solver.printSolverFlags();
cout << endl;
}
results.push_back (solver.solveQuery (tasks[i]));
if (fg->isFromBayesNetwork()) {
// delete mfg;
}
}
}
void runBpSolver (
FactorGraph* fg,
const vector<VarIds>& tasks,
vector<Params>& results)
{
std::set<VarId> vids;
for (unsigned i = 0; i < tasks.size(); i++) {
Util::addToSet (vids, tasks[i]);
}
Solver* solver = 0;
FactorGraph* mfg = fg;
if (fg->isFromBayesNetwork()) {
//mfg = BayesBall::getMinimalFactorGraph (
// *fg, VarIds (vids.begin(),vids.end()));
}
if (Globals::infAlgorithm == InfAlgorithms::BP) {
solver = new BpSolver (*fg); // FIXME
} else if (Globals::infAlgorithm == InfAlgorithms::CBP) {
CFactorGraph::checkForIdenticalFactors = false;
solver = new CbpSolver (*fg); // FIXME
} else {
cerr << "error: unknow solver" << endl;
abort();
}
if (Globals::verbosity > 0) {
solver->printSolverFlags();
cout << endl;
}
results.reserve (tasks.size());
for (unsigned i = 0; i < tasks.size(); i++) {
results.push_back (solver->solveQuery (tasks[i]));
}
if (fg->isFromBayesNetwork()) {
//delete mfg;
}
delete solver;
}
int
setParfactorsParams (void)
{
LiftedNetwork* network = (LiftedNetwork*) YAP_IntOfTerm (YAP_ARG1);
ParfactorList* pfList = network->first;
YAP_Term distList = YAP_ARG2;
unordered_map<unsigned, Params> paramsMap;
while (distList != YAP_TermNil()) {
YAP_Term dist = YAP_HeadOfTerm (distList);
unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (1, dist));
assert (Util::contains (paramsMap, distId) == false);
paramsMap[distId] = readParameters (YAP_ArgOfTerm (2, dist));
distList = YAP_TailOfTerm (distList);
}
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)
{
return TRUE; // TODO
FactorGraph* fg = (FactorGraph*) YAP_IntOfTerm (YAP_ARG1);
YAP_Term distList = YAP_ARG2;
unordered_map<unsigned, Params> paramsMap;
while (distList != YAP_TermNil()) {
YAP_Term dist = YAP_HeadOfTerm (distList);
unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (1, dist));
assert (Util::contains (paramsMap, distId) == false);
paramsMap[distId] = readParameters (YAP_ArgOfTerm (2, dist));
distList = YAP_TailOfTerm (distList);
}
const FacNodes& facNodes = fg->facNodes();
for (unsigned 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
freeParfactors (void)
{
LiftedNetwork* network = (LiftedNetwork*) YAP_IntOfTerm (YAP_ARG1);
delete network->first;
delete network->second;
delete network;
return TRUE;
}
extern "C" void
init_predicates (void)
{
YAP_UserCPredicate ("create_lifted_network", createLiftedNetwork, 3);
YAP_UserCPredicate ("create_ground_network", createGroundNetwork, 4);
YAP_UserCPredicate ("run_lifted_solver", runLiftedSolver, 3);
YAP_UserCPredicate ("run_ground_solver", runGroundSolver, 3);
YAP_UserCPredicate ("set_parfactors_params", setParfactorsParams, 2);
YAP_UserCPredicate ("set_factors_params", setFactorsParams, 2);
YAP_UserCPredicate ("set_vars_information", setVarsInformation, 2);
YAP_UserCPredicate ("set_horus_flag", setHorusFlag, 2);
YAP_UserCPredicate ("free_parfactors", freeParfactors, 1);
YAP_UserCPredicate ("free_ground_network", freeGroundNetwork, 1);
}

View File

@ -0,0 +1,296 @@
#ifndef HORUS_STATESINDEXER_H
#define HORUS_STATESINDEXER_H
#include <algorithm>
#include <numeric>
#include <functional>
#include <sstream>
#include <iomanip>
#include "Var.h"
#include "Util.h"
class StatesIndexer
{
public:
StatesIndexer (const Ranges& ranges, bool calcOffsets = true)
{
size_ = 1;
indices_.resize (ranges.size(), 0);
ranges_ = ranges;
for (unsigned i = 0; i < ranges.size(); i++) {
size_ *= ranges[i];
}
li_ = 0;
if (calcOffsets) {
calculateOffsets();
}
}
StatesIndexer (const Vars& vars, bool calcOffsets = true)
{
size_ = 1;
indices_.resize (vars.size(), 0);
ranges_.reserve (vars.size());
for (unsigned i = 0; i < vars.size(); i++) {
ranges_.push_back (vars[i]->range());
size_ *= vars[i]->range();
}
li_ = 0;
if (calcOffsets) {
calculateOffsets();
}
}
void increment (void)
{
for (int i = ranges_.size() - 1; i >= 0; i--) {
indices_[i] ++;
if (indices_[i] != ranges_[i]) {
break;
} else {
indices_[i] = 0;
}
}
li_ ++;
}
void increment (unsigned dim)
{
assert (dim < ranges_.size());
assert (ranges_.size() == offsets_.size());
assert (indices_[dim] < ranges_[dim]);
indices_[dim] ++;
li_ += offsets_[dim];
}
void incrementExcluding (unsigned skipDim)
{
assert (ranges_.size() == offsets_.size());
for (int i = ranges_.size() - 1; i >= 0; i--) {
if (i != (int)skipDim) {
indices_[i] ++;
li_ += offsets_[i];
if (indices_[i] != ranges_[i]) {
return;
} else {
indices_[i] = 0;
li_ -= offsets_[i] * ranges_[i];
}
}
}
li_ = size_;
}
unsigned linearIndex (void) const
{
return li_;
}
const vector<unsigned>& indices (void) const
{
return indices_;
}
StatesIndexer& operator ++ (void)
{
increment();
return *this;
}
operator unsigned (void) const
{
return li_;
}
unsigned operator[] (unsigned dim) const
{
assert (valid());
assert (dim < ranges_.size());
return indices_[dim];
}
bool valid (void) const
{
return li_ < size_;
}
void reset (void)
{
std::fill (indices_.begin(), indices_.end(), 0);
li_ = 0;
}
void reset (unsigned dim)
{
indices_[dim] = 0;
li_ -= offsets_[dim] * ranges_[dim];
}
unsigned size (void) const
{
return size_ ;
}
friend ostream& operator<< (ostream &os, const StatesIndexer& idx)
{
os << "(" << std::setw (2) << std::setfill('0') << idx.li_ << ") " ;
os << idx.indices_;
return os;
}
private:
void calculateOffsets (void)
{
unsigned prod = 1;
offsets_.resize (ranges_.size());
for (int i = ranges_.size() - 1; i >= 0; i--) {
offsets_[i] = prod;
prod *= ranges_[i];
}
}
unsigned li_;
unsigned size_;
vector<unsigned> indices_;
vector<unsigned> ranges_;
vector<unsigned> offsets_;
};
class MapIndexer
{
public:
MapIndexer (const Ranges& ranges, const vector<bool>& mapDims)
{
assert (ranges.size() == mapDims.size());
unsigned prod = 1;
offsets_.resize (ranges.size());
for (int i = ranges.size() - 1; i >= 0; i--) {
if (mapDims[i]) {
offsets_[i] = prod;
prod *= ranges[i];
}
}
indices_.resize (ranges.size(), 0);
ranges_ = ranges;
index_ = 0;
valid_ = true;
}
MapIndexer (const Ranges& ranges, unsigned ignoreDim)
{
unsigned prod = 1;
offsets_.resize (ranges.size());
for (int i = ranges.size() - 1; i >= 0; i--) {
if (i != (int)ignoreDim) {
offsets_[i] = prod;
prod *= ranges[i];
}
}
indices_.resize (ranges.size(), 0);
ranges_ = ranges;
index_ = 0;
valid_ = true;
}
/*
MapIndexer (
const VarIds& loopVids,
const Ranges& loopRanges,
const VarIds& mapVids,
const Ranges& mapRanges)
{
unsigned prod = 1;
vector<unsigned> offsets (mapRanges.size());
for (int i = mapRanges.size() - 1; i >= 0; i--) {
offsets[i] = prod;
prod *= mapRanges[i];
}
offsets_.reserve (loopVids.size());
for (unsigned i = 0; i < loopVids.size(); i++) {
VarIds::const_iterator it =
std::find (mapVids.begin(), mapVids.end(), loopVids[i]);
if (it != mapVids.end()) {
offsets_.push_back (offsets[it - mapVids.begin()]);
} else {
offsets_.push_back (0);
}
}
indices_.resize (loopVids.size(), 0);
ranges_ = loopRanges;
index_ = 0;
size_ = prod;
}
*/
MapIndexer& operator ++ (void)
{
assert (valid_);
for (int i = ranges_.size() - 1; i >= 0; i--) {
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;
}
unsigned mappedIndex (void) const
{
return index_;
}
operator unsigned (void) const
{
return index_;
}
unsigned operator[] (unsigned 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 ostream& operator<< (ostream &os, const MapIndexer& idx)
{
os << "(" << std::setw (2) << std::setfill('0') << idx.index_ << ") " ;
os << idx.indices_;
return os;
}
private:
unsigned index_;
bool valid_;
vector<unsigned> ranges_;
vector<unsigned> indices_;
vector<unsigned> offsets_;
};
#endif // HORUS_STATESINDEXER_H

View File

@ -0,0 +1,131 @@
#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 (unsigned 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 (unsigned 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;
}

View File

@ -0,0 +1,166 @@
#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_; }
unsigned 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);
}
unsigned 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

View File

@ -0,0 +1,177 @@
#
# default base directory for YAP installation
# (EROOT for architecture-dependent files)
#
GCC = @GCC@
prefix = @prefix@
exec_prefix = @exec_prefix@
ROOTDIR = $(prefix)
EROOTDIR = @exec_prefix@
abs_top_builddir = @abs_top_builddir@
#
# where the binary should be
#
BINDIR = $(EROOTDIR)/bin
#
# where YAP should look for libraries
#
LIBDIR=@libdir@
YAPLIBDIR=@libdir@/Yap
#
#
CC=@CC@
CXX=@CXX@
# normal
#CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -DNDEBUG
# debug
CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -g -O0 -Wextra
#
#
# You shouldn't need to change what follows.
#
INSTALL=@INSTALL@
INSTALL_DATA=@INSTALL_DATA@
INSTALL_PROGRAM=@INSTALL_PROGRAM@
SHELL=/bin/sh
RANLIB=@RANLIB@
srcdir=@srcdir@
SO=@SO@
#4.1VPATH=@srcdir@:@srcdir@/OPTYap
CWD=$(PWD)
HEADERS = \
$(srcdir)/BayesNet.h \
$(srcdir)/BayesBall.h \
$(srcdir)/ElimGraph.h \
$(srcdir)/FactorGraph.h \
$(srcdir)/Factor.h \
$(srcdir)/CFactorGraph.h \
$(srcdir)/ConstraintTree.h \
$(srcdir)/Solver.h \
$(srcdir)/VarElimSolver.h \
$(srcdir)/BpSolver.h \
$(srcdir)/CbpSolver.h \
$(srcdir)/FoveSolver.h \
$(srcdir)/Var.h \
$(srcdir)/Indexer.h \
$(srcdir)/Parfactor.h \
$(srcdir)/ProbFormula.h \
$(srcdir)/Histogram.h \
$(srcdir)/ParfactorList.h \
$(srcdir)/LiftedUtils.h \
$(srcdir)/TinySet.h \
$(srcdir)/Util.h \
$(srcdir)/Horus.h
CPP_SOURCES = \
$(srcdir)/BayesNet.cpp \
$(srcdir)/BayesBall.cpp \
$(srcdir)/ElimGraph.cpp \
$(srcdir)/FactorGraph.cpp \
$(srcdir)/Factor.cpp \
$(srcdir)/CFactorGraph.cpp \
$(srcdir)/ConstraintTree.cpp \
$(srcdir)/Var.cpp \
$(srcdir)/Solver.cpp \
$(srcdir)/VarElimSolver.cpp \
$(srcdir)/BpSolver.cpp \
$(srcdir)/CbpSolver.cpp \
$(srcdir)/FoveSolver.cpp \
$(srcdir)/Parfactor.cpp \
$(srcdir)/ProbFormula.cpp \
$(srcdir)/Histogram.cpp \
$(srcdir)/ParfactorList.cpp \
$(srcdir)/LiftedUtils.cpp \
$(srcdir)/Util.cpp \
$(srcdir)/HorusYap.cpp \
$(srcdir)/HorusCli.cpp
OBJS = \
BayesNet.o \
BayesBall.o \
ElimGraph.o \
FactorGraph.o \
Factor.o \
CFactorGraph.o \
ConstraintTree.o \
Var.o \
Solver.o \
VarElimSolver.o \
BpSolver.o \
CbpSolver.o \
FoveSolver.o \
Parfactor.o \
ProbFormula.o \
Histogram.o \
ParfactorList.o \
LiftedUtils.o \
Util.o \
HorusYap.o
HCLI_OBJS = \
BayesNet.o \
BayesBall.o \
ElimGraph.o \
FactorGraph.o \
Factor.o \
CFactorGraph.o \
ConstraintTree.o \
Var.o \
Solver.o \
VarElimSolver.o \
BpSolver.o \
CbpSolver.o \
FoveSolver.o \
Parfactor.o \
ProbFormula.o \
Histogram.o \
ParfactorList.o \
LiftedUtils.o \
Util.o \
HorusCli.o
SOBJS=horus.@SO@
all: $(SOBJS) hcli
# default rule
%.o : $(srcdir)/%.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
@DO_SECOND_LD@horus.@SO@: $(OBJS)
@DO_SECOND_LD@ @SHLIB_CXX_LD@ -o horus.@SO@ $(OBJS) @EXTRA_LIBS_FOR_SWIDLLS@
hcli: $(HCLI_OBJS)
$(CXX) -o hcli $(HCLI_OBJS)
install: all
$(INSTALL_PROGRAM) $(SOBJS) $(DESTDIR) $(YAPLIBDIR)
clean:
rm -f *.o *~ $(OBJS) $(SOBJS) *.BAK hcli
erase_dots:
rm -f *.dot *.png
depend: $(HEADERS) $(CPP_SOURCES)
-@if test "$(GCC)" = yes; then\
$(CC) -std=c++0x -MM -MG $(CFLAGS) -I$(srcdir) -I$(srcdir)/../../../../include -I$(srcdir)/../../../../H $(CPP_SOURCES) >> Makefile;\
else\
makedepend -f - -- $(CFLAGS) -I$(srcdir)/../../../../H -I$(srcdir)/../../../../include -- $(CPP_SOURCES) |\
sed 's|.*/\([^:]*\):|\1:|' >> Makefile ;\
fi
# DO NOT DELETE THIS LINE -- make depend depends on it.

View File

@ -0,0 +1,911 @@
#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 (unsigned i = 0; i < args_.size(); i++) {
ranges_.push_back (args_[i].range());
const LogVars& lvs = args_[i].logVars();
for (unsigned j = 0; j < lvs.size(); j++) {
if (Util::contains (logVars, lvs[j]) == false) {
logVars.push_back (lvs[j]);
}
}
}
constr_ = new ConstraintTree (logVars, tuples);
assert (params_.size() == Util::expectedSize (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::expectedSize (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::expectedSize (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::expectedSize (ranges_));
}
Parfactor::~Parfactor (void)
{
delete constr_;
}
LogVarSet
Parfactor::countedLogVars (void) const
{
LogVarSet set;
for (unsigned 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 (unsigned fIdx) const
{
assert (fIdx < args_.size());
LogVarSet remaining;
for (unsigned i = 0; i < args_.size(); i++) {
if (i != fIdx) {
remaining |= args_[i].logVarSet();
}
}
return args_[fIdx].logVarSet() - remaining;
}
void
Parfactor::setConstraintTree (ConstraintTree* newTree)
{
delete constr_;
constr_ = newTree;
}
void
Parfactor::sumOut (unsigned 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);
StatesIndexer sindexer (ranges_, fIdx);
while (sindexer.valid()) {
unsigned h = sindexer[fIdx];
if (Globals::logDomain) {
params_[sindexer] += numAssigns[h];
} else {
params_[sindexer] *= numAssigns[h];
}
++ sindexer;
}
}
Params copy = params_;
params_.clear();
params_.resize (copy.size() / ranges_[fIdx], LogAware::addIdenty());
MapIndexer indexer (ranges_, fIdx);
if (Globals::logDomain) {
for (unsigned i = 0; i < copy.size(); i++) {
params_[indexer] = Util::logSum (params_[indexer], copy[i]);
++ indexer;
}
} else {
for (unsigned i = 0; i < copy.size(); i++) {
params_[indexer] += copy[i];
++ indexer;
}
}
LogVarSet excl = exclusiveLogVars (fIdx);
if (args_[fIdx].isCounting()) {
// counting log vars were already raised on counting conversion
LogAware::pow (params_, constr_->getConditionalCount (
excl - args_[fIdx].countedLogVar()));
} else {
LogAware::pow (params_, constr_->getConditionalCount (excl));
}
constr_->remove (excl);
args_.erase (args_.begin() + fIdx);
ranges_.erase (ranges_.begin() + fIdx);
}
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;
}
int 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)
{
int 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);
StatesIndexer 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.increment (fIdx);
}
count ++;
indexer.reset (fIdx);
indexer.incrementExcluding (fIdx);
}
params_.clear();
params_.reserve (sumout.size() * H);
ranges_[fIdx] = H;
MapIndexer mapIndexer (ranges_, fIdx);
while (mapIndexer.valid()) {
double prod = LogAware::multIdenty();
unsigned i = mapIndexer.mappedIndex();
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)
{
int fIdx = indexOfLogVar (X);
assert (fIdx != -1);
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];
std::transform (
hist.begin(), hist.end(),
histograms2[j].begin(),
hist.begin(),
plus<int>());
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)
{
int fIdx = indexOfLogVar (X);
assert (fIdx != -1);
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);
StatesIndexer indexer (expandRanges);
while (indexer.valid()) {
vector<unsigned> hist (R, 0);
for (unsigned n = 0; n < N; n++) {
std::transform (
hist.begin(), hist.end(),
expandHists[indexer[n]].begin(),
hist.begin(),
plus<int>());
}
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 (unsigned i = 0; i < grounds.size(); i++) {
for (unsigned 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)
{
int fIdx = indexOf (formula);
assert (fIdx != -1);
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 (unsigned i = 0; i < args_.size(); i++) {
args_[i].setGroup (ProbFormula::getNewGroup());
}
}
void
Parfactor::applySubstitution (const Substitution& theta)
{
for (unsigned i = 0; i < args_.size(); i++) {
LogVars& lvs = args_[i].logVars();
for (unsigned 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);
}
int
Parfactor::findGroup (const Ground& ground) const
{
int group = -1;
for (unsigned 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())) {
group = args_[i].group();
break;
}
}
}
return group;
}
bool
Parfactor::containsGround (const Ground& ground) const
{
return findGroup (ground) != -1;
}
bool
Parfactor::containsGroup (unsigned group) const
{
for (unsigned i = 0; i < args_.size(); i++) {
if (args_[i].group() == group) {
return true;
}
}
return false;
}
unsigned
Parfactor::nrFormulas (LogVar X) const
{
unsigned count = 0;
for (unsigned i = 0; i < args_.size(); i++) {
if (args_[i].contains (X)) {
count ++;
}
}
return count;
}
int
Parfactor::indexOfLogVar (LogVar X) const
{
int idx = -1;
assert (nrFormulas (X) == 1);
for (unsigned i = 0; i < args_.size(); i++) {
if (args_[i].contains (X)) {
idx = i;
break;
}
}
return idx;
}
int
Parfactor::indexOfGroup (unsigned group) const
{
int pos = -1;
for (unsigned i = 0; i < args_.size(); i++) {
if (args_[i].group() == group) {
pos = i;
break;
}
}
return pos;
}
unsigned
Parfactor::nrFormulasWithGroup (unsigned group) const
{
unsigned count = 0;
for (unsigned i = 0; i < args_.size(); i++) {
if (args_[i].group() == group) {
count ++;
}
}
return count;
}
vector<unsigned>
Parfactor::getAllGroups (void) const
{
vector<unsigned> groups (args_.size());
for (unsigned i = 0; i < args_.size(); i++) {
groups[i] = args_[i].group();
}
return groups;
}
string
Parfactor::getLabel (void) const
{
stringstream ss;
ss << "phi(" ;
for (unsigned 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 (unsigned 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 (unsigned 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;
StatesIndexer indexer (ranges_);
while (indexer.valid()) {
stringstream ss;
for (unsigned 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 (unsigned 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 (unsigned i = 0; i < Xs.size(); i++) {
cout << "-> projection of " << Xs[i] << ": " ;
cout << copy.tupleSet ({Xs[i]}) << endl;
}
}
void
Parfactor::expandPotential (
int 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;
abort();
}
Params copy = params_;
params_.clear();
params_.reserve (newSize);
unsigned prod = 1;
vector<unsigned> offsets_ (ranges_.size());
for (int i = ranges_.size() - 1; i >= 0; i--) {
offsets_[i] = prod;
prod *= ranges_[i];
}
unsigned index = 0;
ranges_[fIdx] = newRange;
vector<unsigned> indices (ranges_.size(), 0);
for (unsigned k = 0; k < newSize; k++) {
if (index >= copy.size()) {
abort();
}
assert (index < copy.size());
params_.push_back (copy[index]);
for (int i = ranges_.size() - 1; i >= 0; i--) {
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 (int fIdx)
{
// check if we can simplify the parfactor
for (unsigned i = 0; i < args_.size(); i++) {
if ((int)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)
{
LogVarSet singletons = constr_->singletons();
for (int i = 0; i < (int)args_.size() - 1; i++) {
for (unsigned 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 (unsigned fIdx1, unsigned fIdx2)
{
Params copy = params_;
params_.clear();
StatesIndexer indexer (ranges_);
while (indexer.valid()) {
if (indexer[fIdx1] == indexer[fIdx2]) {
params_.push_back (copy[indexer]);
}
++ indexer;
}
for (unsigned 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<unsigned> matchedI;
TinySet<unsigned> matchedJ;
ProbFormulas& formulas1 = g1->arguments();
ProbFormulas& formulas2 = g2->arguments();
for (unsigned i = 0; i < formulas1.size(); i++) {
for (unsigned 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 (unsigned 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 (unsigned i = 0; i < allLvs1.size(); i++) {
if (theta1.containsReplacementFor (allLvs1[i]) == false) {
theta1.add (allLvs1[i], freeLogVar);
++ freeLogVar;
}
}
const LogVarSet& allLvs2 = g2->logVarSet();
for (unsigned 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 (unsigned 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 (unsigned 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);
}

View File

@ -0,0 +1,121 @@
#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);
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 (unsigned) const;
void setConstraintTree (ConstraintTree*);
void sumOut (unsigned 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&);
int findGroup (const Ground&) const;
bool containsGround (const Ground&) const;
bool containsGroup (unsigned) const;
unsigned nrFormulas (LogVar) const;
int indexOfLogVar (LogVar) const;
int indexOfGroup (unsigned) const;
unsigned nrFormulasWithGroup (unsigned) const;
vector<unsigned> 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 (int fIdx);
void simplifyParfactor (unsigned fIdx1, unsigned fIdx2);
static std::pair<LogVars, LogVars> getAlignLogVars (
Parfactor* g1, Parfactor* g2);
void expandPotential (int 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

View File

@ -0,0 +1,619 @@
#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 (unsigned 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 (unsigned i = 0; i < pfs.size(); i++) {
assert (isShattered (pfs[i]));
}
for (unsigned i = 0; i < pfs.size() - 1; i++) {
for (unsigned 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 (unsigned i = 0; i < pfVec.size(); i++) {
pfVec[i]->print();
cout << endl;
}
}
bool
ParfactorList::isShattered (const Parfactor* g) const
{
const ProbFormulas& formulas = g->arguments();
if (formulas.size() < 2) {
return true;
}
ConstraintTree ct (*g->constr());
for (unsigned i = 0; i < formulas.size() - 1; i++) {
for (unsigned 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 (unsigned i = 0; i < fms1.size(); i++) {
for (unsigned 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 (unsigned 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 (unsigned i = 0; i < formulas.size() - 1; i++) {
for (unsigned 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,
unsigned fIdx1,
unsigned 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 a parfactor" << endl;
cerr << endl;
abort();
}
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 { };
}
unsigned 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 (unsigned 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 (unsigned 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 (unsigned i = 0; i < formulas1.size(); i++) {
for (unsigned 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 (
unsigned fIdx1, Parfactor* g1,
unsigned 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()));
// unsigned static count = 0; count ++;
// 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 { };
}
unsigned 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,
unsigned fIdx,
ConstraintTree* commCt,
ConstraintTree* exclCt,
unsigned 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 (unsigned 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 (unsigned oldGroup, unsigned newGroup)
{
for (ParfactorList::iterator it = pfList_.begin();
it != pfList_.end(); it++) {
ProbFormulas& formulas = (*it)->arguments();
for (unsigned 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();
}

View File

@ -0,0 +1,120 @@
#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(); }
unsigned 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;
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, unsigned fIdx1, unsigned fIdx2);
std::pair<Parfactors, Parfactors> shatter (
Parfactor*, Parfactor*);
std::pair<Parfactors, Parfactors> shatter (
unsigned, Parfactor*, unsigned, Parfactor*);
Parfactors shatter (
Parfactor*,
unsigned,
ConstraintTree*,
ConstraintTree*,
unsigned);
void updateGroups (unsigned group1, unsigned 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

View File

@ -0,0 +1,139 @@
#include "ProbFormula.h"
int 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);
}
int
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 (unsigned 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 (unsigned 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;
}
unsigned
ProbFormula::getNewGroup (void)
{
freeGroup_ ++;
return freeGroup_;
}
ostream& operator<< (ostream &os, const ObservedFormula& of)
{
os << of.functor_ << "/" << of.arity_;
os << "|" << of.constr_.tupleSet();
os << " [evidence=" << of.evidence_ << "]";
return os;
}

View File

@ -0,0 +1,112 @@
#ifndef HORUS_PROBFORMULA_H
#define HORUS_PROBFORMULA_H
#include <limits>
#include "ConstraintTree.h"
#include "LiftedUtils.h"
#include "Horus.h"
typedef unsigned PrvGroup;
class ProbFormula
{
public:
ProbFormula (Symbol f, const LogVars& lvs, unsigned range)
: functor_(f), logVars_(lvs), range_(range),
countedLogVar_(), group_(Util::maxUnsigned()) { }
ProbFormula (Symbol f, unsigned r)
: functor_(f), range_(r), group_(Util::maxUnsigned()) { }
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_); }
unsigned group (void) const { return group_; }
void setGroup (unsigned g) { group_ = g; }
bool sameSkeletonAs (const ProbFormula&) const;
bool contains (LogVar) const;
bool contains (LogVarSet) const;
int 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 unsigned 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_;
unsigned group_;
static int 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_; }
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

View File

@ -0,0 +1,42 @@
#include "Solver.h"
#include "Util.h"
void
Solver::printAnswer (const VarIds& vids)
{
Vars unobservedVars;
VarIds unobservedVids;
for (unsigned 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]);
}
}
Params res = solveQuery (unobservedVids);
vector<string> stateLines = Util::getStateLines (unobservedVars);
for (unsigned i = 0; i < res.size(); i++) {
cout << "P(" << stateLines[i] << ") = " ;
cout << std::setprecision (Constants::PRECISION) << res[i];
cout << endl;
}
cout << endl;
}
void
Solver::printAllPosterioris (void)
{
VarIds vids;
const VarNodes& vars = fg.varNodes();
for (unsigned i = 0; i < vars.size(); i++) {
vids.push_back (vars[i]->varId());
}
std::sort (vids.begin(), vids.end());
for (unsigned i = 0; i < vids.size(); i++) {
printAnswer ({vids[i]});
}
}

View File

@ -0,0 +1,32 @@
#ifndef HORUS_SOLVER_H
#define HORUS_SOLVER_H
#include <iomanip>
#include "Var.h"
#include "FactorGraph.h"
using namespace std;
class Solver
{
public:
Solver (const FactorGraph& factorGraph) : fg(factorGraph) { }
virtual ~Solver() { } // 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);
protected:
const FactorGraph& fg;
};
#endif // HORUS_SOLVER_H

12
packages/CLPBN/horus/TODO Normal file
View File

@ -0,0 +1,12 @@
- Refactor sum out in factor
- Add a way to sum out several vars at the same time
- Receive ranges as a constant reference in Indexer
- Check if evidence remains in the compressed factor graph
- Consider using hashs instead of vectors of colors to calculate the groups in
counting bp
- use more psize_t instead of unsigned for looping through params
- Find a way to decrease the time required to find an
elimination order for variable elimination
- Add a sequential elimination heuristic

View File

@ -0,0 +1,243 @@
#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:
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_);
}
typedef typename vector<T>::iterator iterator;
typedef typename vector<T>::const_iterator const_iterator;
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 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:
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]) == false) {
return false;
}
}
return true;
}
vector<T> vec_;
Compare cmp_;
};
#endif // HORUS_TINYSET_H

View File

@ -0,0 +1,643 @@
#include <limits>
#include <sstream>
#include <fstream>
#include "Util.h"
#include "Indexer.h"
#include "ElimGraph.h"
namespace Globals {
bool logDomain = false;
unsigned verbosity = 0;
InfAlgorithms infAlgorithm = InfAlgorithms::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;
}
vector<NetInfo> Statistics::netInfo_;
vector<CompressInfo> Statistics::compressInfo_;
unsigned Statistics::primaryNetCount_;
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 readed number is negative" << endl;
abort();
}
return static_cast<unsigned> (val);
}
double
stringToDouble (string str)
{
double val;
stringstream ss;
ss << str;
ss >> val;
return val;
}
void
toLog (Params& v)
{
for (unsigned i = 0; i < v.size(); i++) {
v[i] = log (v[i]);
}
}
void
fromLog (Params& v)
{
for (unsigned i = 0; i < v.size(); i++) {
v[i] = exp (v[i]);
}
}
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;
}
unsigned
expectedSize (const Ranges& ranges)
{
unsigned prod = 1;
for (unsigned i = 0; i < ranges.size(); i++) {
prod *= ranges[i];
}
return prod;
}
unsigned
getNumberOfDigits (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 (unsigned i = 0; i < v.size(); i++) {
if (i != 0) ss << ", " ;
ss << v[i];
}
ss << "]" ;
return ss.str();
}
vector<string>
getStateLines (const Vars& vars)
{
StatesIndexer idx (vars);
vector<string> jointStrings;
while (idx.valid()) {
stringstream ss;
for (unsigned i = 0; i < vars.size(); i++) {
if (i != 0) ss << ", " ;
ss << vars[i]->label() << "=" << vars[i]->states()[(idx[i])];
}
jointStrings.push_back (ss.str());
++ idx;
}
return jointStrings;
}
bool
setHorusFlag (string key, string value)
{
bool returnVal = true;
if (key == "verbosity") {
stringstream ss;
ss << value;
ss >> Globals::verbosity;
} else if (key == "inf_alg") {
if ( value == "ve") {
Globals::infAlgorithm = InfAlgorithms::VE;
} else if (value == "bp") {
Globals::infAlgorithm = InfAlgorithms::BP;
} else if (value == "cbp") {
Globals::infAlgorithm = InfAlgorithms::CBP;
} else {
cerr << "warning: invalid value `" << value << "' " ;
cerr << "for `" << key << "'" << endl;
returnVal = false;
}
} else if (key == "elim_heuristic") {
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)
{
double sum = LogAware::addIdenty();
if (Globals::logDomain) {
for (unsigned i = 0; i < v.size(); i++) {
sum = Util::logSum (sum, v[i]);
}
assert (sum != -numeric_limits<double>::infinity());
for (unsigned i = 0; i < v.size(); i++) {
v[i] -= sum;
}
} else {
for (unsigned i = 0; i < v.size(); i++) {
sum += v[i];
}
assert (sum != 0.0);
for (unsigned i = 0; i < v.size(); i++) {
v[i] /= sum;
}
}
}
double
getL1Distance (const Params& v1, const Params& v2)
{
assert (v1.size() == v2.size());
double dist = 0.0;
if (Globals::logDomain) {
for (unsigned i = 0; i < v1.size(); i++) {
dist += abs (exp(v1[i]) - exp(v2[i]));
}
} else {
for (unsigned i = 0; i < v1.size(); i++) {
dist += abs (v1[i] - v2[i]);
}
}
return dist;
}
double
getMaxNorm (const Params& v1, const Params& v2)
{
assert (v1.size() == v2.size());
double max = 0.0;
if (Globals::logDomain) {
for (unsigned i = 0; i < v1.size(); i++) {
double diff = abs (exp(v1[i]) - exp(v2[i]));
if (diff > max) {
max = diff;
}
}
} else {
for (unsigned i = 0; i < v1.size(); i++) {
double diff = abs (v1[i] - v2[i]);
if (diff > max) {
max = diff;
}
}
}
return max;
}
double
pow (double p, unsigned expoent)
{
return Globals::logDomain ? p * expoent : std::pow (p, expoent);
}
double
pow (double p, double expoent)
{
// assumes that `expoent' is never in log domain
return Globals::logDomain ? p * expoent : std::pow (p, expoent);
}
void
pow (Params& v, unsigned expoent)
{
if (expoent == 1) {
return;
}
if (Globals::logDomain) {
for (unsigned i = 0; i < v.size(); i++) {
v[i] *= expoent;
}
} else {
for (unsigned i = 0; i < v.size(); i++) {
v[i] = std::pow (v[i], expoent);
}
}
}
void
pow (Params& v, double expoent)
{
// assumes that `expoent' is never in log domain
if (Globals::logDomain) {
for (unsigned i = 0; i < v.size(); i++) {
v[i] *= expoent;
}
} else {
for (unsigned i = 0; i < v.size(); i++) {
v[i] = std::pow (v[i], expoent);
}
}
}
}
unsigned
Statistics::getSolvedNetworksCounting (void)
{
return netInfo_.size();
}
void
Statistics::incrementPrimaryNetworksCounting (void)
{
primaryNetCount_ ++;
}
unsigned
Statistics::getPrimaryNetworksCounting (void)
{
return primaryNetCount_;
}
void
Statistics::updateStatistics (
unsigned size,
bool loopy,
unsigned nIters,
double time)
{
netInfo_.push_back (NetInfo (size, loopy, nIters, time));
}
void
Statistics::printStatistics (void)
{
cout << getStatisticString();
}
void
Statistics::writeStatistics (const char* fileName)
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "Statistics::writeStats()" << endl;
abort();
}
out << getStatisticString();
out.close();
}
void
Statistics::updateCompressingStatistics (
unsigned nrGroundVars,
unsigned nrGroundFactors,
unsigned nrClusterVars,
unsigned nrClusterFactors,
unsigned nrNeighborless)
{
compressInfo_.push_back (CompressInfo (nrGroundVars, nrGroundFactors,
nrClusterVars, nrClusterFactors, nrNeighborless));
}
string
Statistics::getStatisticString (void)
{
stringstream ss2, ss3, ss4, ss1;
ss1 << "running mode: " ;
switch (Globals::infAlgorithm) {
case InfAlgorithms::VE: ss1 << "ve" << endl; break;
case InfAlgorithms::BP: ss1 << "bp" << endl; break;
case InfAlgorithms::CBP: ss1 << "cbp" << endl; break;
}
ss1 << "message schedule: " ;
switch (BpOptions::schedule) {
case BpOptions::Schedule::SEQ_FIXED:
ss1 << "sequential fixed" << endl;
break;
case BpOptions::Schedule::SEQ_RANDOM:
ss1 << "sequential random" << endl;
break;
case BpOptions::Schedule::PARALLEL:
ss1 << "parallel" << endl;
break;
case BpOptions::Schedule::MAX_RESIDUAL:
ss1 << "max residual" << endl;
break;
}
ss1 << "max iterations: " << BpOptions::maxIter << endl;
ss1 << "accuracy " << BpOptions::accuracy << endl;
ss1 << endl << endl;
Util::printSubHeader ("Network information", ss2);
ss2 << left;
ss2 << setw (15) << "Network Size" ;
ss2 << setw (9) << "Loopy" ;
ss2 << setw (15) << "Iterations" ;
ss2 << setw (15) << "Solving Time" ;
ss2 << endl;
unsigned nLoopyNets = 0;
unsigned nUnconvergedRuns = 0;
double totalSolvingTime = 0.0;
for (unsigned i = 0; i < netInfo_.size(); i++) {
ss2 << setw (15) << netInfo_[i].size;
if (netInfo_[i].loopy) {
ss2 << setw (9) << "yes";
nLoopyNets ++;
} else {
ss2 << setw (9) << "no";
}
if (netInfo_[i].nIters == 0) {
ss2 << setw (15) << "n/a" ;
} else {
ss2 << setw (15) << netInfo_[i].nIters;
if (netInfo_[i].nIters > BpOptions::maxIter) {
nUnconvergedRuns ++;
}
}
ss2 << setw (15) << netInfo_[i].time;
totalSolvingTime += netInfo_[i].time;
ss2 << endl;
}
ss2 << endl << endl;
unsigned c1 = 0, c2 = 0, c3 = 0, c4 = 0;
if (compressInfo_.size() > 0) {
Util::printSubHeader ("Compress information", ss3);
ss3 << left;
ss3 << "Ground Cluster Ground Cluster Neighborless" << endl;
ss3 << "Vars Vars Factors Factors Vars" << endl;
for (unsigned i = 0; i < compressInfo_.size(); i++) {
ss3 << setw (9) << compressInfo_[i].nrGroundVars;
ss3 << setw (10) << compressInfo_[i].nrClusterVars;
ss3 << setw (10) << compressInfo_[i].nrGroundFactors;
ss3 << setw (10) << compressInfo_[i].nrClusterFactors;
ss3 << setw (10) << compressInfo_[i].nrNeighborless;
ss3 << endl;
c1 += compressInfo_[i].nrGroundVars - compressInfo_[i].nrNeighborless;
c2 += compressInfo_[i].nrClusterVars;
c3 += compressInfo_[i].nrGroundFactors - compressInfo_[i].nrNeighborless;
c4 += compressInfo_[i].nrClusterFactors;
if (compressInfo_[i].nrNeighborless != 0) {
c2 --;
c4 --;
}
}
ss3 << endl << endl;
}
ss4 << "primary networks: " << primaryNetCount_ << endl;
ss4 << "solved networks: " << netInfo_.size() << endl;
ss4 << "loopy networks: " << nLoopyNets << endl;
ss4 << "unconverged runs: " << nUnconvergedRuns << endl;
ss4 << "total solving time: " << totalSolvingTime << endl;
if (compressInfo_.size() > 0) {
double pc1 = (1.0 - (c2 / (double)c1)) * 100.0;
double pc2 = (1.0 - (c4 / (double)c3)) * 100.0;
ss4 << setprecision (5);
ss4 << "variable compression: " << pc1 << "%" << endl;
ss4 << "factor compression: " << pc2 << "%" << endl;
}
ss4 << endl << endl;
ss1 << ss4.str() << ss2.str() << ss3.str();
return ss1.str();
}

422
packages/CLPBN/horus/Util.h Normal file
View File

@ -0,0 +1,422 @@
#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 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> int indexOf (const vector<T>&, const T&);
template <typename T> std::string toString (const T&);
template <> std::string toString (const bool&);
unsigned stringToUnsigned (string);
double stringToDouble (string);
void toLog (Params&);
void fromLog (Params&);
double logSum (double, double);
void multiply (Params&, const Params&);
void multiply (Params&, const Params&, unsigned);
void add (Params&, const Params&);
void subtract (Params&, const Params&);
void add (Params&, const Params&, unsigned);
unsigned maxUnsigned (void);
double factorial (unsigned);
double logFactorial (unsigned);
unsigned nrCombinations (unsigned, unsigned);
unsigned expectedSize (const Ranges&);
unsigned getNumberOfDigits (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 (unsigned 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> int
Util::indexOf (const vector<T>& v, const T& e)
{
int pos = std::distance (v.begin(),
std::find (v.begin(), v.end(), e));
if (pos == (int)v.size()) {
pos = -1;
}
return pos;
}
template <typename T> std::string
Util::toString (const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
template <typename T>
std::ostream& operator << (std::ostream& os, const vector<T>& v)
{
os << "[" ;
for (unsigned i = 0; i < v.size(); i++) {
os << ((i != 0) ? ", " : "") << v[i];
}
os << "]" ;
return os;
}
namespace {
const double NEG_INF = -numeric_limits<double>::infinity();
};
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 void
Util::multiply (Params& v1, const Params& v2)
{
assert (v1.size() == v2.size());
for (unsigned i = 0; i < v1.size(); i++) {
v1[i] *= v2[i];
}
}
inline void
Util::multiply (Params& v1, const Params& v2, unsigned repetitions)
{
for (unsigned count = 0; count < v1.size(); ) {
for (unsigned i = 0; i < v2.size(); i++) {
for (unsigned r = 0; r < repetitions; r++) {
v1[count] *= v2[i];
count ++;
}
}
}
}
inline void
Util::add (Params& v1, const Params& v2)
{
assert (v1.size() == v2.size());
std::transform (v1.begin(), v1.end(), v2.begin(),
v1.begin(), plus<double>());
}
inline void
Util::subtract (Params& v1, const Params& v2)
{
assert (v1.size() == v2.size());
std::transform (v1.begin(), v1.end(), v2.begin(),
v1.begin(), minus<double>());
}
inline void
Util::add (Params& v1, const Params& v2, unsigned repetitions)
{
for (unsigned count = 0; count < v1.size(); ) {
for (unsigned i = 0; i < v2.size(); i++) {
for (unsigned r = 0; r < repetitions; r++) {
v1[count] += v2[i];
count ++;
}
}
}
}
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
tl (double v)
{
return Globals::logDomain ? log (v) : v;
}
inline double
fl (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);
};
struct NetInfo
{
NetInfo (unsigned size, bool loopy, unsigned nIters, double time)
{
this->size = size;
this->loopy = loopy;
this->nIters = nIters;
this->time = time;
}
unsigned size;
bool loopy;
unsigned nIters;
double time;
};
struct CompressInfo
{
CompressInfo (unsigned a, unsigned b, unsigned c, unsigned d, unsigned e)
{
nrGroundVars = a;
nrGroundFactors = b;
nrClusterVars = c;
nrClusterFactors = d;
nrNeighborless = e;
}
unsigned nrGroundVars;
unsigned nrGroundFactors;
unsigned nrClusterVars;
unsigned nrClusterFactors;
unsigned nrNeighborless;
};
class Statistics
{
public:
static unsigned getSolvedNetworksCounting (void);
static void incrementPrimaryNetworksCounting (void);
static unsigned getPrimaryNetworksCounting (void);
static void updateStatistics (unsigned, bool, unsigned, double);
static void printStatistics (void);
static void writeStatistics (const char*);
static void updateCompressingStatistics (
unsigned, unsigned, unsigned, unsigned, unsigned);
private:
static string getStatisticString (void);
static vector<NetInfo> netInfo_;
static vector<CompressInfo> compressInfo_;
static unsigned primaryNetCount_;
};
#endif // HORUS_UTIL_H

View File

@ -0,0 +1,102 @@
#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 (unsigned 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;
}

108
packages/CLPBN/horus/Var.h Normal file
View File

@ -0,0 +1,108 @@
#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) { };
unsigned varId (void) const { return varId_; }
unsigned range (void) const { return range_; }
int getEvidence (void) const { return evidence_; }
unsigned getIndex (void) const { return index_; }
void setIndex (unsigned idx) { index_ = idx; }
operator unsigned () const { return index_; }
bool hasEvidence (void) const
{
return evidence_ != Constants::NO_EVIDENCE;
}
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_;
unsigned index_;
static unordered_map<VarId, VarInfo> varsInfo_;
};
#endif // BP_Var_H

View File

@ -0,0 +1,216 @@
#include <algorithm>
#include "VarElimSolver.h"
#include "ElimGraph.h"
#include "Factor.h"
#include "Util.h"
VarElimSolver::~VarElimSolver (void)
{
delete factorList_.back();
}
Params
VarElimSolver::solveQuery (VarIds queryVids)
{
if (Globals::verbosity > 1) {
cout << "Solving query on " ;
for (unsigned 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::fromLog (params);
}
return params;
}
void
VarElimSolver::printSolverFlags (void) const
{
stringstream ss;
ss << "variable elimination [" ;
ss << "elim_heuristic=" ;
ElimHeuristic eh = ElimGraph::elimHeuristic;
switch (eh) {
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
VarElimSolver::createFactorList (void)
{
const FacNodes& facNodes = fg.facNodes();
factorList_.reserve (facNodes.size() * 2);
for (unsigned i = 0; i < facNodes.size(); i++) {
factorList_.push_back (new Factor (facNodes[i]->factor()));
const VarNodes& neighs = facNodes[i]->neighbors();
for (unsigned j = 0; j < neighs.size(); j++) {
unordered_map<VarId,vector<unsigned> >::iterator it
= varFactors_.find (neighs[j]->varId());
if (it == varFactors_.end()) {
it = varFactors_.insert (make_pair (
neighs[j]->varId(), vector<unsigned>())).first;
}
it->second.push_back (i);
}
}
}
void
VarElimSolver::absorveEvidence (void)
{
if (Globals::verbosity > 2) {
Util::printDashedLine();
cout << "(initial factor list)" << endl;
printActiveFactors();
}
const VarNodes& varNodes = fg.varNodes();
for (unsigned 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<unsigned>& idxs =
varFactors_.find (varNodes[i]->varId())->second;
for (unsigned 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
VarElimSolver::findEliminationOrder (const VarIds& vids)
{
elimOrder_ = ElimGraph::getEliminationOrder (factorList_, vids);
}
void
VarElimSolver::processFactorList (const VarIds& vids)
{
totalFactorSize_ = 0;
largestFactorSize_ = 0;
for (unsigned 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 (unsigned i = 0; i < factorList_.size(); i++) {
if (factorList_[i]) {
finalFactor->multiply (*factorList_[i]);
delete factorList_[i];
factorList_[i] = 0;
}
}
VarIds unobservedVids;
for (unsigned 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
VarElimSolver::eliminate (VarId elimVar)
{
Factor* result = 0;
vector<unsigned>& idxs = varFactors_.find (elimVar)->second;
for (unsigned i = 0; i < idxs.size(); i++) {
unsigned 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 (unsigned i = 0; i < resultVarIds.size(); i++) {
vector<unsigned>& idxs =
varFactors_.find (resultVarIds[i])->second;
idxs.push_back (factorList_.size() - 1);
}
}
}
void
VarElimSolver::printActiveFactors (void)
{
for (unsigned i = 0; i < factorList_.size(); i++) {
if (factorList_[i] != 0) {
cout << factorList_[i]->getLabel() << " " ;
cout << factorList_[i]->params() << endl;
}
}
}

View File

@ -0,0 +1,46 @@
#ifndef HORUS_VARELIMSOLVER_H
#define HORUS_VARELIMSOLVER_H
#include "unordered_map"
#include "Solver.h"
#include "FactorGraph.h"
#include "Horus.h"
using namespace std;
class VarElimSolver : public Solver
{
public:
VarElimSolver (const FactorGraph& fg) : Solver (fg) { }
~VarElimSolver (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<unsigned>> varFactors_;
};
#endif // HORUS_VARELIMSOLVER_H

View File

@ -0,0 +1,78 @@
function prepare_new_run
{
YAP=~/bin/$SHORTNAME-$SOLVER
LOG_FILE=$SOLVER.log
#LOG_FILE=results`date "+ %H:%M:%S %d-%m-%Y"`.
rm -f $LOG_FILE
rm -f ignore.$LOG_FILE
cp ~/bin/yap $YAP
}
function run_solver
{
constraint=$1
solver_flag=true
if [ -n "$2" ]; then
if [ $SOLVER = hve ]; then
solver_flag=clpbn_horus:set_horus_flag\(elim_heuristic,$2\)
elif [ $SOLVER = bp ]; then
solver_flag=clpbn_horus:set_horus_flag\(schedule,$2\)
elif [ $SOLVER = cbp ]; then
solver_flag=clpbn_horus:set_horus_flag\(schedule,$2\)
else
echo "unknow flag $2"
fi
fi
/usr/bin/time -o $LOG_FILE -a -f "%U\t%S\t%e\t%M" \
$YAP << EOF >> $LOG_FILE &>> ignore.$LOG_FILE
nogc.
[$NETWORK].
[$constraint].
clpbn_horus:set_solver($SOLVER).
clpbn_horus:set_horus_flag(use_logarithms, true).
clpbn_horus:set_horus_flag(verbosity, 1).
$solver_flag.
$QUERY.
open("$LOG_FILE", 'append', S), format(S, '$constraint ~15+ ', []), close(S).
EOF
}
function clear_log_files
{
rm -f *~
rm -f ../*~
rm -f school/*.log school/*~
rm -f ../school/*.log ../school/*~
rm -f city/*.log city/*~
rm -f ../city/*.log ../city/*~
rm -f workshop_attrs/*.log workshop_attrs/*~
rm -f ../workshop_attrs/*.log ../workshop_attrs/*~
echo all done!
}
function write_header
{
echo -n "****************************************" >> $LOG_FILE
echo "****************************************" >> $LOG_FILE
echo "results for solver $1 user(s) sys(s) real(s), mem(kB)" >> $LOG_FILE
echo -n "****************************************" >> $LOG_FILE
echo "****************************************" >> $LOG_FILE
}
if [ $1 ] && [ $1 == "clean" ]; then
clear_log_files
fi

View File

@ -0,0 +1,4 @@
************************************************************************
results for solver bp(shedule=seq_fixed)
************************************************************************
city1000: real:0:00.20 user:0.12 sys:0.02

View File

@ -0,0 +1,37 @@
#!/bin/bash
source city.sh
source ../benchs.sh
SOLVER="bp"
function run_all_graphs
{
write_header $1
run_solver city1000 $2
run_solver city5000 $2
run_solver city10000 $2
run_solver city15000 $2
run_solver city20000 $2
run_solver city25000 $2
run_solver city30000 $2
run_solver city35000 $2
run_solver city40000 $2
run_solver city45000 $2
run_solver city50000 $2
run_solver city55000 $2
run_solver city60000 $2
run_solver city65000 $2
return
run_solver city70000 $2
run_solver city75000 $2
run_solver city80000 $2
run_solver city85000 $2
run_solver city90000 $2
run_solver city95000 $2
run_solver city100000 $2
}
prepare_new_run
run_all_graphs "bp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,36 @@
#!/bin/bash
source city.sh
source ../benchs.sh
SOLVER="cbp"
function run_all_graphs
{
write_header $1
run_solver city1000 $2
run_solver city5000 $2
run_solver city10000 $2
run_solver city15000 $2
run_solver city20000 $2
run_solver city25000 $2
run_solver city30000 $2
run_solver city35000 $2
run_solver city40000 $2
run_solver city45000 $2
run_solver city50000 $2
run_solver city55000 $2
run_solver city60000 $2
run_solver city65000 $2
run_solver city70000 $2
run_solver city75000 $2
run_solver city80000 $2
run_solver city85000 $2
run_solver city90000 $2
run_solver city95000 $2
run_solver city100000 $2
}
prepare_new_run
run_all_graphs "cbp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,6 @@
#!/bin/bash
NETWORK="'../../examples/city'"
SHORTNAME="city"
QUERY="is_joe_guilty(X)"

View File

@ -0,0 +1,36 @@
#!/bin/bash
source city.sh
source ../benchs.sh
SOLVER="fove"
function run_all_graphs
{
write_header $1
run_solver city1000 $2
run_solver city5000 $2
run_solver city10000 $2
run_solver city15000 $2
run_solver city20000 $2
run_solver city25000 $2
run_solver city30000 $2
run_solver city35000 $2
run_solver city40000 $2
run_solver city45000 $2
run_solver city50000 $2
run_solver city55000 $2
run_solver city60000 $2
run_solver city65000 $2
run_solver city70000 $2
run_solver city75000 $2
run_solver city80000 $2
run_solver city85000 $2
run_solver city90000 $2
run_solver city95000 $2
run_solver city100000 $2
}
prepare_new_run
run_all_graphs "fove "

View File

@ -0,0 +1,33 @@
#! /home/tgomes/bin/yap -L --
:- initialization(main).
main :-
unix(argv([N])),
atomic_concat(['city', N, '.yap'], FileName),
open(FileName, 'write', S),
atom_number(N, N2),
generate_people(S, N2, 1),
write(S, '\n'),
generate_evidence(S, N2, 1),
write(S, '\n'),
close(S).
generate_people(S, N, Counting) :-
Counting > N, !.
generate_people(S, N, Counting) :-
format(S, 'people(p~w, nyc).~n', [Counting]),
Counting1 is Counting + 1,
generate_people(S, N, Counting1).
generate_evidence(S, N, Counting) :-
Counting > N, !.
generate_evidence(S, N, Counting) :- !,
format(S, 'ev(descn(p~w, t)).~n', [Counting]),
Counting1 is Counting + 1,
generate_evidence(S, N, Counting1).

View File

@ -0,0 +1,37 @@
#!/bin/bash
source city.sh
source ../benchs.sh
SOLVER="hve"
function run_all_graphs
{
write_header $1
run_solver city1000 $2
run_solver city5000 $2
run_solver city10000 $2
run_solver city15000 $2
run_solver city20000 $2
run_solver city25000 $2
run_solver city30000 $2
run_solver city35000 $2
run_solver city40000 $2
run_solver city45000 $2
run_solver city50000 $2
run_solver city55000 $2
run_solver city60000 $2
run_solver city65000 $2
run_solver city70000 $2
run_solver city75000 $2
run_solver city80000 $2
run_solver city85000 $2
run_solver city90000 $2
run_solver city95000 $2
run_solver city100000 $2
}
prepare_new_run
run_all_graphs "hve(elim_heuristic=min_neighbors) " min_neighbors

View File

@ -0,0 +1,96 @@
YAP 6.3.2 (i686-linux): Sáb Abr 28 13:56:07 WEST 2012
yes
% consulting /home/tiago/yap-6.3/packages/CLPBN/clpbn/bp/examples/city.yap...
% reconsulting /home/tiago/share/Yap/pfl.yap...
% reconsulting /home/tiago/share/Yap/lists.yap...
% reconsulting /home/tiago/share/Yap/error.pl...
% reconsulted /home/tiago/share/Yap/error.pl in module error, 4 msec 27448 bytes
% reconsulted /home/tiago/share/Yap/lists.yap in module lists, 4 msec 60536 bytes
% reconsulting /home/tiago/share/Yap/clpbn.yap...
% reconsulting /home/tiago/share/Yap/atts.yap...
% reconsulted /home/tiago/share/Yap/atts.yap in module attributes, 0 msec 22808 bytes
% reconsulting /home/tiago/share/Yap/terms.yap...
% reconsulted /home/tiago/share/Yap/terms.yap in module terms, 0 msec 1480 bytes
% reconsulting /home/tiago/share/Yap/clpbn/ve.yap...
% reconsulting /home/tiago/share/Yap/ordsets.yap...
% reconsulted /home/tiago/share/Yap/ordsets.yap in module ordsets, 4 msec 23928 bytes
% reconsulting /home/tiago/share/Yap/clpbn/xbif.yap...
% reconsulting /home/tiago/share/Yap/clpbn/dists.yap...
% reconsulting /home/tiago/share/Yap/matrix.yap...
% reconsulted /home/tiago/share/Yap/matrix.yap in module matrix, 0 msec 20608 bytes
% reconsulting /home/tiago/share/Yap/clpbn/matrix_cpt_utils.yap...
% reconsulted /home/tiago/share/Yap/clpbn/matrix_cpt_utils.yap in module clpbn_matrix_utils, 0 msec 33504 bytes
% reconsulted /home/tiago/share/Yap/clpbn/dists.yap in module clpbn_dist, 4 msec 97560 bytes
% reconsulted /home/tiago/share/Yap/clpbn/xbif.yap in module xbif, 4 msec 109176 bytes
% reconsulting /home/tiago/share/Yap/clpbn/graphviz.yap...
% reconsulted /home/tiago/share/Yap/clpbn/graphviz.yap in module clpbn_gviz, 0 msec 7784 bytes
% reconsulting /home/tiago/share/Yap/clpbn/utils.yap...
% reconsulted /home/tiago/share/Yap/clpbn/utils.yap in module clpbn_utils, 0 msec 13912 bytes
% reconsulting /home/tiago/share/Yap/clpbn/display.yap...
% reconsulted /home/tiago/share/Yap/clpbn/display.yap in module clpbn_display, 0 msec 11232 bytes
% reconsulting /home/tiago/share/Yap/clpbn/connected.yap...
% reconsulting /home/tiago/share/Yap/dgraphs.yap...
% reconsulting /home/tiago/share/Yap/rbtrees.yap...
% reconsulted /home/tiago/share/Yap/rbtrees.yap in module rbtrees, 8 msec 117496 bytes
% reconsulting /home/tiago/share/Yap/wdgraphs.yap...
% reconsulting /home/tiago/share/Yap/heaps.yap...
% reconsulted /home/tiago/share/Yap/heaps.yap in module heaps, 4 msec 13520 bytes
% reconsulted /home/tiago/share/Yap/wdgraphs.yap in module wdgraphs, 4 msec 72176 bytes
% reconsulted /home/tiago/share/Yap/dgraphs.yap in module dgraphs, 16 msec 243240 bytes
% reconsulted /home/tiago/share/Yap/clpbn/connected.yap in module clpbn_connected, 16 msec 261736 bytes
% reconsulting /home/tiago/share/Yap/clpbn/aggregates.yap...
% reconsulted /home/tiago/share/Yap/clpbn/aggregates.yap in module clpbn_aggregates, 0 msec 36512 bytes
% reconsulted /home/tiago/share/Yap/clpbn/ve.yap in module clpbn_ve, 36 msec 500808 bytes
% reconsulting /home/tiago/share/Yap/clpbn/bp.yap...
% reconsulting /home/tiago/share/Yap/charsio.yap...
% reconsulted /home/tiago/share/Yap/charsio.yap in module charsio, 0 msec 10592 bytes
% reconsulting /home/tiago/share/Yap/bhash.yap...
% reconsulted /home/tiago/share/Yap/bhash.yap in module b_hash, 0 msec 30624 bytes
% reconsulting /home/tiago/share/Yap/clpbn/horus.yap...
% Warning: (/home/tiago/share/Yap/clpbn/horus.yap:23).
% Importing private predicate pfl:set_pfl_flag/2 to clpbn_horus.
% reconsulted /home/tiago/share/Yap/clpbn/horus.yap in module clpbn_horus, 4 msec 14248 bytes
% reconsulted /home/tiago/share/Yap/clpbn/bp.yap in module clpbn_bp, 8 msec 87944 bytes
% reconsulting /home/tiago/share/Yap/clpbn/fove.yap...
% reconsulted /home/tiago/share/Yap/clpbn/fove.yap in module clpbn_fove, 4 msec 17464 bytes
% reconsulting /home/tiago/share/Yap/clpbn/jt.yap...
% reconsulting /home/tiago/share/Yap/undgraphs.yap...
% reconsulting /home/tiago/share/Yap/wundgraphs.yap...
% reconsulted /home/tiago/share/Yap/wundgraphs.yap in module wundgraphs, 4 msec 37816 bytes
% reconsulted /home/tiago/share/Yap/undgraphs.yap in module undgraphs, 8 msec 66048 bytes
% reconsulted /home/tiago/share/Yap/clpbn/jt.yap in module jt, 12 msec 143960 bytes
% reconsulting /home/tiago/share/Yap/clpbn/bdd.yap...
% reconsulting /home/tiago/share/Yap/hacks.yap...
% reconsulted /home/tiago/share/Yap/hacks.yap in module yap_hacks, 0 msec 4968 bytes
ERROR!! (/home/tiago/share/Yap/clpbn/bdd.yap:54).
PERMISSION ERROR- use_module(library(bdd)): cannot read from library(bdd)
% reconsulted /home/tiago/share/Yap/clpbn/bdd.yap in module clpbn_bdd, 8 msec 152336 bytes
% reconsulting /home/tiago/share/Yap/clpbn/gibbs.yap...
% reconsulting /home/tiago/share/Yap/clpbn/topsort.yap...
% reconsulted /home/tiago/share/Yap/clpbn/topsort.yap in module topsort, 0 msec 5848 bytes
% reconsulted /home/tiago/share/Yap/clpbn/gibbs.yap in module clpbn_gibbs, 0 msec 79344 bytes
% reconsulting /home/tiago/share/Yap/clpbn/pgrammar.yap...
% reconsulted /home/tiago/share/Yap/clpbn/pgrammar.yap in module clpbn_pgrammar, 4 msec 44088 bytes
% reconsulting /home/tiago/share/Yap/clpbn/graphs.yap...
% reconsulted /home/tiago/share/Yap/clpbn/graphs.yap in module clpbn2graph, 0 msec 8408 bytes
% reconsulting /home/tiago/share/Yap/clpbn/evidence.yap...
% reconsulted /home/tiago/share/Yap/clpbn/evidence.yap in module clpbn_evidence, 4 msec 21256 bytes
% reconsulting /home/tiago/share/Yap/clpbn/ground_factors.yap...
% reconsulted /home/tiago/share/Yap/clpbn/ground_factors.yap in module clpbn_ground_factors, 4 msec 16360 bytes
% reconsulted /home/tiago/share/Yap/clpbn.yap in module clpbn, 92 msec 1188576 bytes
% reconsulted /home/tiago/share/Yap/pfl.yap in module pfl, 96 msec 1277856 bytes
% consulted /home/tiago/yap-6.3/packages/CLPBN/clpbn/bp/examples/city.yap in module user, 96 msec 1313552 bytes
yes
ERROR!!
PERMISSION ERROR- consult(city1000): cannot read from city1000
yes
yes
yes
yes
belief propagation [schedule=seq_fixed,max_iter=1000,accuracy=0.0001,log_domain=true]
Sum-Product converged in 6 iterations
p(X=y)= 0.2383192848945889,
p(X=n)= 0.761680715105411
S = '<stream>'(0xa0288d8)

View File

@ -0,0 +1,31 @@
#!/bin/bash
source cw.sh
source ../benchs.sh
SOLVER="bp"
function run_all_graphs
{
write_header $1
run_solver p1000w$N_WORKSHOPS $2
run_solver p5000w$N_WORKSHOPS $2
run_solver p10000w$N_WORKSHOPS $2
run_solver p15000w$N_WORKSHOPS $2
run_solver p20000w$N_WORKSHOPS $2
run_solver p25000w$N_WORKSHOPS $2
return
run_solver p30000w$N_WORKSHOPS $2
run_solver p35000w$N_WORKSHOPS $2
run_solver p40000w$N_WORKSHOPS $2
run_solver p45000w$N_WORKSHOPS $2
run_solver p50000w$N_WORKSHOPS $2
run_solver p55000w$N_WORKSHOPS $2
run_solver p60000w$N_WORKSHOPS $2
run_solver p65000w$N_WORKSHOPS $2
run_solver p70000w$N_WORKSHOPS $2
}
prepare_new_run
run_all_graphs "bp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,30 @@
#!/bin/bash
source cw.sh
source ../benchs.sh
SOLVER="cbp"
function run_all_graphs
{
write_header $1
run_solver p1000w$N_WORKSHOPS $2
run_solver p5000w$N_WORKSHOPS $2
run_solver p10000w$N_WORKSHOPS $2
run_solver p15000w$N_WORKSHOPS $2
run_solver p20000w$N_WORKSHOPS $2
run_solver p25000w$N_WORKSHOPS $2
run_solver p30000w$N_WORKSHOPS $2
run_solver p35000w$N_WORKSHOPS $2
run_solver p40000w$N_WORKSHOPS $2
run_solver p45000w$N_WORKSHOPS $2
run_solver p50000w$N_WORKSHOPS $2
run_solver p55000w$N_WORKSHOPS $2
run_solver p60000w$N_WORKSHOPS $2
run_solver p65000w$N_WORKSHOPS $2
run_solver p70000w$N_WORKSHOPS $2
}
prepare_new_run
run_all_graphs "cbp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,8 @@
#!/bin/bash
NETWORK="'../../examples/comp_workshops'"
SHORTNAME="cw"
QUERY="series(X)"
N_WORKSHOPS=10

View File

@ -0,0 +1,31 @@
#!/bin/bash
source cw.sh
source ../benchs.sh
SOLVER="fove"
function run_all_graphs
{
write_header $1
run_solver p1000w$N_WORKSHOPS $2
run_solver p5000w$N_WORKSHOPS $2
run_solver p10000w$N_WORKSHOPS $2
run_solver p15000w$N_WORKSHOPS $2
run_solver p20000w$N_WORKSHOPS $2
run_solver p25000w$N_WORKSHOPS $2
run_solver p30000w$N_WORKSHOPS $2
run_solver p35000w$N_WORKSHOPS $2
run_solver p40000w$N_WORKSHOPS $2
run_solver p45000w$N_WORKSHOPS $2
run_solver p50000w$N_WORKSHOPS $2
run_solver p55000w$N_WORKSHOPS $2
run_solver p60000w$N_WORKSHOPS $2
run_solver p65000w$N_WORKSHOPS $2
run_solver p70000w$N_WORKSHOPS $2
}
prepare_new_run
run_all_graphs "fove "

View File

@ -0,0 +1,35 @@
#!/home/tgomes/bin/yap -L --
:- use_module(library(lists)).
:- initialization(main).
main :-
unix(argv(Args)),
nth(1, Args, NP), % number of invitees
nth(2, Args, NW), % number of workshops
atomic_concat(['p', NP , 'w', NW, '.yap'], FileName),
open(FileName, 'write', S),
atom_number(NP, NP2),
atom_number(NW, NW2),
gen(S, NP2, NW2, 1),
write(S, '\n'),
close(S).
gen(_, NP, _, Count) :-
Count > NP, !.
gen(S, NP, NW, Count) :-
gen_workshops(S, Count, NW, 1),
Count1 is Count + 1,
gen(S, NP, NW, Count1).
gen_workshops(_, _, NW, Count) :-
Count > NW, !.
gen_workshops(S, P, NW, Count) :-
format(S, 'c(p~w,w~w).~n', [P,Count]),
Count1 is Count + 1,
gen_workshops(S, P, NW, Count1).

View File

@ -0,0 +1,30 @@
#!/bin/bash
source cw.sh
source ../benchs.sh
SOLVER="hve"
function run_all_graphs
{
write_header $1
run_solver p1000w$N_WORKSHOPS $2
run_solver p5000w$N_WORKSHOPS $2
run_solver p10000w$N_WORKSHOPS $2
run_solver p15000w$N_WORKSHOPS $2
run_solver p20000w$N_WORKSHOPS $2
run_solver p25000w$N_WORKSHOPS $2
run_solver p30000w$N_WORKSHOPS $2
run_solver p35000w$N_WORKSHOPS $2
run_solver p40000w$N_WORKSHOPS $2
run_solver p45000w$N_WORKSHOPS $2
run_solver p50000w$N_WORKSHOPS $2
run_solver p55000w$N_WORKSHOPS $2
run_solver p60000w$N_WORKSHOPS $2
run_solver p65000w$N_WORKSHOPS $2
run_solver p70000w$N_WORKSHOPS $2
}
prepare_new_run
run_all_graphs "hve(elim_heuristic=min_neighbors) " min_neighbors

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,95 @@
#!/bin/bash
#cp ~/bin/yap ~/bin/school_all
#YAP=~/bin/school_all
YAP=~/bin/yap
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=results.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
# yap -g "['../../../../examples/School/sch32'], [missing5], use_module(library(clpbn/learning/em)), graph(L), clpbn:set_clpbn_flag(em_solver,bp), clpbn_horus:set_horus_flag(inf_alg, bp), statistics(runtime, _), em(L,0.01,10,_,Lik), statistics(runtime, [T,_])."
function run_solver
{
if [ $2 = bp ]
then
if [ $4 = ve ]
then
extra_flag1=clpbn_horus:set_horus_flag\(inf_alg,$4\)
extra_flag2=clpbn_horus:set_horus_flag\(elim_heuristic,$5\)
else
extra_flag1=clpbn_horus:set_horus_flag\(inf_alg,$4\)
extra_flag2=clpbn_horus:set_horus_flag\(schedule,$5\)
fi
else
extra_flag1=true
extra_flag2=true
fi
/usr/bin/time -o "$OUT_FILE_NAME" -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF &>> "ignore.$OUT_FILE_NAME"
:- [pos:train].
:- ['../../../../examples/School/sch32'].
:- use_module(library(clpbn/learning/em)).
:- use_module(library(clpbn/bp)).
[$1].
graph(L),
clpbn:set_clpbn_flag(em_solver,$2),
$extra_flag1, $extra_flag2,
em(L,0.01,10,_,Lik),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~11+ Lik = ~3f, ',[Lik]),
close(S).
EOF
}
function run_all_graphs
{
echo "************************************************************************" >> "$OUT_FILE_NAME"
echo "results for solver $2" >> "$OUT_FILE_NAME"
echo "************************************************************************" >> "$OUT_FILE_NAME"
run_solver missing5 $1 missing5 $3 $4 $5
run_solver missing10 $1 missing10 $3 $4 $5
#run_solver missing20 $1 missing20 $3 $4 $5
#run_solver missing30 $1 missing30 $3 $4 $5
#run_solver missing40 $1 missing40 $3 $4 $5
#run_solver missing50 $1 missing50 $3 $4 $5
}
#run_all_graphs bp "hve(min_neighbors) " ve min_neighbors
#run_all_graphs bp "bp(seq_fixed) " bp seq_fixed
#run_all_graphs bp "cbp(seq_fixed) " cbp seq_fixed
exit
run_all_graphs bp "hve(min_neighbors) " ve min_neighbors
run_all_graphs bp "hve(min_weight) " ve min_weight
run_all_graphs bp "hve(min_fill) " ve min_fill
run_all_graphs bp "hve(w_min_fill) " ve weighted_min_fill
run_all_graphs bp "bp(seq_fixed) " bp seq_fixed
run_all_graphs bp "bp(max_residual) " bp max_residual
run_all_graphs bp "cbp(seq_fixed) " cbp seq_fixed
run_all_graphs bp "cbp(max_residual) " cbp max_residual
run_all_graphs gibbs "gibbs "
echo "************************************************************************" >> "$OUT_FILE_NAME"
echo "results for solver ve" >> "$OUT_FILE_NAME"
echo "************************************************************************" >> "$OUT_FILE_NAME"
run_solver missing5 ve missing5 $3 $4 $5
run_solver missing10 ve missing10 $3 $4 $5
run_solver missing20 ve missing20 $3 $4 $5
run_solver missing30 ve missing30 $3 $4 $5
run_solver missing40 ve missing40 $3 $4 $5
#run_solver missing50 ve missing50 $3 $4 $5 #+24h!
echo "************************************************************************" >> "$OUT_FILE_NAME"
echo "results for solver jt" >> "$OUT_FILE_NAME"
echo "************************************************************************" >> "$OUT_FILE_NAME"
run_solver missing5 jt missing5 $3 $4 $5
run_solver missing10 jt missing10 $3 $4 $5
run_solver missing20 jt missing20 $3 $4 $5
#run_solver missing30 jt missing30 $3 $4 $5 #+24h!
#run_solver missing40 jt missing40 $3 $4 $5 #+24h!
#run_solver missing50 jt missing50 $3 $4 $5 #+24h!
exit

View File

@ -0,0 +1,30 @@
#!/bin/bash
source sm.sh
source ../benchs.sh
SOLVER="bp"
function run_all_graphs
{
write_header $1
run_solver pop100 $2
run_solver pop200 $2
run_solver pop300 $2
run_solver pop400 $2
run_solver pop500 $2
run_solver pop600 $2
run_solver pop700 $2
run_solver pop800 $2
run_solver pop900 $2
run_solver pop1000 $2
run_solver pop1100 $2
run_solver pop1200 $2
run_solver pop1300 $2
run_solver pop1400 $2
run_solver pop1500 $2
}
prepare_new_run
run_all_graphs "bp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,30 @@
#!/bin/bash
source sm.sh
source ../benchs.sh
SOLVER="cbp"
function run_all_graphs
{
write_header $1
run_solver pop100 $2
run_solver pop200 $2
run_solver pop300 $2
run_solver pop400 $2
run_solver pop500 $2
run_solver pop600 $2
run_solver pop700 $2
run_solver pop800 $2
run_solver pop900 $2
run_solver pop1000 $2
run_solver pop1100 $2
run_solver pop1200 $2
run_solver pop1300 $2
run_solver pop1400 $2
run_solver pop1500 $2
}
prepare_new_run
run_all_graphs "cbp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,31 @@
#!/bin/bash
source sm.sh
source ../benchs.sh
SOLVER="fove"
function run_all_graphs
{
write_header $1
run_solver pop100 $2
run_solver pop200 $2
run_solver pop300 $2
run_solver pop400 $2
run_solver pop500 $2
run_solver pop600 $2
run_solver pop700 $2
run_solver pop800 $2
run_solver pop900 $2
run_solver pop1000 $2
run_solver pop1100 $2
run_solver pop1200 $2
run_solver pop1300 $2
run_solver pop1400 $2
run_solver pop1500 $2
}
prepare_new_run
run_all_graphs "fove "

View File

@ -0,0 +1,23 @@
#!/home/tgomes/bin/yap -L --
:- initialization(main).
main :-
unix(argv([N])),
atomic_concat(['pop', N, '.yap'], FileName),
open(FileName, 'write', S),
atom_number(N, N2),
generate_people(S, N2, 4),
write(S, '\n'),
close(S).
generate_people(S, N, Counting) :-
Counting > N, !.
generate_people(S, N, Counting) :-
format(S, 'people(p~w).~n', [Counting]),
Counting1 is Counting + 1,
generate_people(S, N, Counting1).

View File

@ -0,0 +1,33 @@
#!/bin/bash
source sm.sh
source ../benchs.sh
SOLVER="hve"
function run_all_graphs
{
write_header $1
run_solver pop100 $2
#run_solver pop200 $2
#run_solver pop300 $2
#run_solver pop400 $2
#run_solver pop500 $2
#run_solver pop600 $2
#run_solver pop700 $2
#run_solver pop800 $2
#run_solver pop900 $2
#run_solver pop1000 $2
#run_solver pop1100 $2
#run_solver pop1200 $2
#run_solver pop1300 $2
#run_solver pop1400 $2
#run_solver pop1500 $2
}
prepare_new_run
run_all_graphs "hve(elim_heuristic=min_neighbors) " min_neighbors
#run_all_graphs "hve(elim_heuristic=min_weight) " min_weight
#run_all_graphs "hve(elim_heuristic=min_fill) " min_fill
#run_all_graphs "hve(elim_heuristic=weighted_min_fill) " weighted_min_fill

View File

@ -0,0 +1,6 @@
#!/bin/bash
NETWORK="'../../examples/smokers2'"
SHORTNAME="sm"
QUERY="smokes(p1,t), smokes(p2,t), friends(p1,p2,X)"

View File

@ -0,0 +1,37 @@
#!/bin/bash
source wa.sh
source ../benchs.sh
SOLVER="bp"
function run_all_graphs
{
write_header $1
run_solver p1000attrs$N_ATTRS $2
run_solver p5000attrs$N_ATTRS $2
run_solver p10000attrs$N_ATTRS $2
run_solver p15000attrs$N_ATTRS $2
run_solver p20000attrs$N_ATTRS $2
run_solver p25000attrs$N_ATTRS $2
run_solver p30000attrs$N_ATTRS $2
run_solver p35000attrs$N_ATTRS $2
return
run_solver p40000attrs$N_ATTRS $2
run_solver p45000attrs$N_ATTRS $2
run_solver p50000attrs$N_ATTRS $2
run_solver p55000attrs$N_ATTRS $2
run_solver p60000attrs$N_ATTRS $2
run_solver p65000attrs$N_ATTRS $2
run_solver p70000attrs$N_ATTRS $2
run_solver p75000attrs$N_ATTRS $2
run_solver p80000attrs$N_ATTRS $2
run_solver p85000attrs$N_ATTRS $2
run_solver p90000attrs$N_ATTRS $2
run_solver p95000attrs$N_ATTRS $2
run_solver p100000attrs$N_ATTRS $2
}
prepare_new_run
run_all_graphs "bp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,36 @@
#!/bin/bash
source wa.sh
source ../benchs.sh
SOLVER="cbp"
function run_all_graphs
{
write_header $1
run_solver p1000attrs$N_ATTRS $2
run_solver p5000attrs$N_ATTRS $2
run_solver p10000attrs$N_ATTRS $2
run_solver p15000attrs$N_ATTRS $2
run_solver p20000attrs$N_ATTRS $2
run_solver p25000attrs$N_ATTRS $2
run_solver p30000attrs$N_ATTRS $2
run_solver p35000attrs$N_ATTRS $2
run_solver p40000attrs$N_ATTRS $2
run_solver p45000attrs$N_ATTRS $2
run_solver p50000attrs$N_ATTRS $2
run_solver p55000attrs$N_ATTRS $2
run_solver p60000attrs$N_ATTRS $2
run_solver p65000attrs$N_ATTRS $2
run_solver p70000attrs$N_ATTRS $2
run_solver p75000attrs$N_ATTRS $2
run_solver p80000attrs$N_ATTRS $2
run_solver p85000attrs$N_ATTRS $2
run_solver p90000attrs$N_ATTRS $2
run_solver p95000attrs$N_ATTRS $2
run_solver p100000attrs$N_ATTRS $2
}
prepare_new_run
run_all_graphs "cbp(shedule=seq_fixed) " seq_fixed

View File

@ -0,0 +1,37 @@
#!/bin/bash
source wa.sh
source ../benchs.sh
SOLVER="fove"
function run_all_graphs
{
write_header $1
run_solver p1000attrs$N_ATTRS $2
run_solver p5000attrs$N_ATTRS $2
run_solver p10000attrs$N_ATTRS $2
run_solver p15000attrs$N_ATTRS $2
run_solver p20000attrs$N_ATTRS $2
run_solver p25000attrs$N_ATTRS $2
run_solver p30000attrs$N_ATTRS $2
run_solver p35000attrs$N_ATTRS $2
run_solver p40000attrs$N_ATTRS $2
run_solver p45000attrs$N_ATTRS $2
run_solver p50000attrs$N_ATTRS $2
run_solver p55000attrs$N_ATTRS $2
run_solver p60000attrs$N_ATTRS $2
run_solver p65000attrs$N_ATTRS $2
run_solver p70000attrs$N_ATTRS $2
run_solver p75000attrs$N_ATTRS $2
run_solver p80000attrs$N_ATTRS $2
run_solver p85000attrs$N_ATTRS $2
run_solver p90000attrs$N_ATTRS $2
run_solver p95000attrs$N_ATTRS $2
run_solver p100000attrs$N_ATTRS $2
}
prepare_new_run
run_all_graphs "fove "

View File

@ -0,0 +1,39 @@
#!/home/tgomes/bin/yap -L --
:- use_module(library(lists)).
:- initialization(main).
main :-
unix(argv(Args)),
nth(1, Args, NP), % number of invitees
nth(2, Args, NA), % number of attributes
atomic_concat(['p', NP , 'attrs', NA, '.yap'], FileName),
open(FileName, 'write', S),
atom_number(NP, NP2),
atom_number(NA, NA2),
generate_people(S, NP2, 1),
write(S, '\n'),
generate_attrs(S, NA2, 7),
write(S, '\n'),
close(S).
generate_people(S, N, Counting) :-
Counting > N, !.
generate_people(S, N, Counting) :-
format(S, 'people(p~w).~n', [Counting]),
Counting1 is Counting + 1,
generate_people(S, N, Counting1).
generate_attrs(S, N, Counting) :-
Counting > N, !.
generate_attrs(S, N, Counting) :-
%format(S, 'people(p~w).~n', [Counting]),
format(S, 'markov attends(P)::[t,f], attr~w::[t,f]', [Counting]),
format(S, '; [0.7, 0.3, 0.3, 0.3] ; [people(P)].~n',[]),
Counting1 is Counting + 1,
generate_attrs(S, N, Counting1).

View File

@ -0,0 +1,36 @@
#!/bin/bash
source wa.sh
source ../benchs.sh
SOLVER="hve"
function run_all_graphs
{
write_header $1
run_solver p1000attrs$N_ATTRS $2
run_solver p5000attrs$N_ATTRS $2
run_solver p10000attrs$N_ATTRS $2
run_solver p15000attrs$N_ATTRS $2
run_solver p20000attrs$N_ATTRS $2
run_solver p25000attrs$N_ATTRS $2
run_solver p30000attrs$N_ATTRS $2
run_solver p35000attrs$N_ATTRS $2
run_solver p40000attrs$N_ATTRS $2
run_solver p45000attrs$N_ATTRS $2
run_solver p50000attrs$N_ATTRS $2
run_solver p55000attrs$N_ATTRS $2
run_solver p60000attrs$N_ATTRS $2
run_solver p65000attrs$N_ATTRS $2
run_solver p70000attrs$N_ATTRS $2
run_solver p75000attrs$N_ATTRS $2
run_solver p80000attrs$N_ATTRS $2
run_solver p85000attrs$N_ATTRS $2
run_solver p90000attrs$N_ATTRS $2
run_solver p95000attrs$N_ATTRS $2
run_solver p100000attrs$N_ATTRS $2
}
prepare_new_run
run_all_graphs "hve(elim_heuristic=min_neighbors) " min_neighbors

View File

@ -0,0 +1,9 @@
#!/bin/bash
NETWORK="'../../examples/workshop_attrs'"
SHORTNAME="wa"
QUERY="series(X)"
N_ATTRS=6

View File

@ -0,0 +1,47 @@
5
1
0
2
2
0 0.001
1 0.999
1
1
2
2
0 0.002
1 0.998
3
1 0 2
2 2 2
8
0 0.95
1 0.94
2 0.29
3 0.001
4 0.05
5 0.06
6 0.71
7 0.999
2
2 3
2 2
4
0 0.9
1 0.05
2 0.1
3 0.95
2
2 4
2 2
4
0 0.7
1 0.01
2 0.3
3 0.99

View File

@ -0,0 +1,28 @@
MARKOV
5
2 2 2 2 2
5
1 0
1 1
3 2 0 1
2 3 2
2 4 2
2
.001 .999
2
.002 .998
8
.95 .94 .29 .001
.05 .06 .71 .999
4
.9 .05
.1 .95
4
.7 .01
.3 .99

View File

@ -0,0 +1,41 @@
:- use_module(library(pfl)).
%:- set_pfl_flag(solver,ve).
:- set_pfl_flag(solver,bp), clpbn_horus:set_horus_flag(inf_alg,ve).
%:- set_pfl_flag(solver,bp), clpbn_horus:set_horus_flag(inf_alg,bp).
%:- set_pfl_flag(solver,fove).
% :- yap_flag(write_strings, off).
bayes burglary::[b1,b3] ; [0.001, 0.999] ; [].
bayes earthquake::[e1,e2] ; [0.002, 0.998]; [].
bayes alarm::[a1,a2] , burglary, earthquake ; [0.95, 0.94, 0.29, 0.001, 0.05, 0.06, 0.71, 0.999] ; [].
bayes john_calls::[j1,j2] , alarm ; [0.9, 0.05, 0.1, 0.95] ; [].
bayes mary_calls::[m1,m2] , alarm ; [0.7, 0.01, 0.3, 0.99] ; [].
b_cpt([0.001, 0.999]).
e_cpt([0.002, 0.998]).
a_cpt([0.95, 0.94, 0.29, 0.001,
0.05, 0.06, 0.71, 0.999]).
jc_cpt([0.9, 0.05,
0.1, 0.95]).
mc_cpt([0.7, 0.01,
0.3, 0.99]).
% ?- alarm(A).
?- john_calls(J), mary_calls(m1).
%?- john_calls(J), mary_calls(m1), alarm(a1).
%?- john_calls(J), alarm(a1).

View File

@ -0,0 +1,15 @@
# example in counting belief propagation paper
MARKOV
3
2 2 2
2
2 0 1
2 2 1
4
1.2 1.4 2.0 0.4
4
1.2 1.4 2.0 0.4

View File

@ -0,0 +1,105 @@
:- use_module(library(pfl)).
%:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- multifile people/2.
:- multifile ev/1.
people(joe,nyc).
people(p2, nyc).
people(p3, nyc).
people(p4, nyc).
people(p5, nyc).
ev(descn(p2, t)).
ev(descn(p3, t)).
ev(descn(p4, t)).
ev(descn(p5, t)).
bayes city_conservativeness(C)::[y,n] ; cons_table(C) ; [people(_,C)].
bayes gender(P)::[m,f] ; gender_table(P) ; [people(P,_)].
bayes hair_color(P)::[t,f], city_conservativeness(C) ; hair_color_table(P) ; [people(P,C)].
bayes car_color(P)::[t,f], hair_color(P) ; car_color_table(P); [people(P,_)].
bayes height(P)::[t,f], gender(P) ; height_table(P) ; [people(P,_)].
bayes shoe_size(P):[t,f], height(P) ; shoe_size_table(P); [people(P,_)].
bayes guilty(P)::[y,n] ; guilty_table(P) ; [people(P,_)].
bayes descn(P)::[t,f], car_color(P), hair_color(P), height(P), guilty(P) ; descn_table(P) ; [people(P,_)].
bayes witness(C)::[t,f], descn(Joe), descn(P2) ; wit_table ; [people(_,C), Joe=joe, P2=p2].
% FIXME
%cons_table(amsterdam, [0.2, 0.8]) :- !.
cons_table(_, [0.8, 0.2]).
gender_table(_, [0.55, 0.45]).
hair_color_table(_,
/* conservative_city */
/* y n */
[ 0.05, 0.1,
0.95, 0.9 ]).
car_color_table(_,
/* t f */
[ 0.9, 0.2,
0.1, 0.8 ]).
height_table(_,
/* m f */
[ 0.6, 0.4,
0.4, 0.6 ]).
shoe_size_table(_,
/* t f */
[ 0.9, 0.1,
0.1, 0.9 ]).
guilty_table(_, [0.23, 0.77]).
descn_table(_,
/* color, hair, height, guilt */
/* ttttt tttf ttft ttff tfttt tftf tfft tfff ttttt fttf ftft ftff ffttt fftf ffft ffff */
[ 0.99, 0.5, 0.23, 0.88, 0.41, 0.3, 0.76, 0.87, 0.44, 0.43, 0.29, 0.72, 0.23, 0.91, 0.95, 0.92,
0.01, 0.5, 0.77, 0.12, 0.59, 0.7, 0.24, 0.13, 0.56, 0.57, 0.71, 0.28, 0.77, 0.09, 0.05, 0.08]).
wit_table([0.2, 0.45, 0.24, 0.34,
0.8, 0.55, 0.76, 0.66]).
runall(G, Wrapper) :-
findall(G, Wrapper, L),
execute_all(L).
execute_all([]).
execute_all(G.L) :-
call(G),
execute_all(L).
is_joe_guilty(Guilty) :-
witness(nyc, t),
runall(X, ev(X)),
guilty(joe, Guilty).
% ?- is_joe_guilty(Guilty)

View File

@ -0,0 +1,33 @@
:- use_module(library(pfl)).
%:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- multifile c/2.
c(p1,w1).
c(p1,w2).
c(p1,w3).
c(p2,w1).
c(p2,w2).
c(p2,w3).
c(p3,w1).
c(p3,w2).
c(p3,w3).
c(p4,w1).
c(p4,w2).
c(p4,w3).
c(p5,w1).
c(p5,w2).
c(p5,w3).
markov attends(P)::[t,f], hot(W)::[t,f] ; [0.2, 0.8, 0.8, 0.8] ; [c(P,W)].
markov attends(P)::[t,f], series::[t,f] ; [0.501, 0.499, 0.499, 0.499] ; [c(P,_)].
% ?- series(X).

View File

@ -0,0 +1,21 @@
:- use_module(library(pfl)).
:- set_pfl_flag(solver,fove).
%:- set_pfl_flag(solver,bp), clpbn_horus:set_horus_flag(inf_alg,ve).
%:- set_pfl_flag(solver,bp), clpbn_horus:set_horus_flag(inf_alg,bp).
%:- set_pfl_flag(solver,bp), clpbn_horus:set_horus_flag(inf_alg,cbp).
t(ann).
t(dave).
% p(ann,t).
markov p(X)::[t,f] ; [0.1, 0.3] ; [t(X)].
% use standard Prolog queries: provide evidence first.
?- p(ann,t), p(ann,X).
% ?- p(ann,X).

View File

@ -0,0 +1,21 @@
:- use_module(library(pfl)).
:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- clpbn_horus:set_horus_flag(verbosity,5).
people(p1,p1).
people(p1,p2).
people(p2,p1).
people(p2,p2).
markov p(A,A)::[t,f] ; [1.0,4.5] ; [people(A,_)].
markov p(A,B)::[t,f] ; [1.0,4.5] ; [people(A,B)].
?- p(p1,p1,X).

View File

@ -0,0 +1,31 @@
:- use_module(library(pfl)).
%:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- multifile people/1.
people @ 5.
people(X,Y) :-
people(X),
people(Y),
X \== Y.
markov smokes(X)::[t,f]; [1.0, 4.0552]; [people(X)].
markov cancer(X)::[t,f]; [1.0, 9.9742]; [people(X)].
markov friends(X,Y)::[t,f] ; [1.0, 99.48432] ; [people(X,Y)].
markov smokes(X)::[t,f], cancer(X)::[t,f] ; [4.48169, 4.48169, 1.0, 4.48169] ; [people(X)].
markov friends(X,Y)::[t,f], smokes(X)::[t,f], smokes(Y)::[t,f] ;
[3.004166, 3.004166, 3.004166, 3.004166, 3.004166, 1.0, 1.0, 3.004166] ; [people(X,Y)].
% ?- friends(p1,p2,X).

View File

@ -0,0 +1,31 @@
:- use_module(library(pfl)).
%:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- multifile people/1.
people @ 5.
people(X,Y) :-
people(X),
people(Y).
% X \== Y.
markov smokes(X)::[t,f]; [1.0, 4.0552]; [people(X)].
markov asthma(X)::[t,f]; [1.0, 9.9742] ; [people(X)].
markov friends(X,Y)::[t,f]; [1.0, 99.48432] ; [people(X,Y)].
markov asthma(X)::[t,f], smokes(X)::[t,f]; [4.48169, 4.48169, 1.0, 4.48169] ; [people(X)].
markov asthma(X)::[t,f], friends(X,Y)::[t,f], smokes(Y)::[t,f];
[3.004166, 3.004166, 3.004166, 3.004166, 3.004166, 1.0, 1.0, 3.004166] ; [people(X,Y)].
% ?- smokes(p1,t), smokes(p2,t), friends(p1,p2,X)

View File

@ -0,0 +1,239 @@
27
1
12
2
2
0 9.974182
1 1.000000
1
13
2
2
0 9.974182
1 1.000000
1
14
2
2
0 9.974182
1 1.000000
1
9
2
2
0 4.055200
1 1.000000
1
10
2
2
0 4.055200
1 1.000000
1
11
2
2
0 4.055200
1 1.000000
1
0
2
2
0 7.389056
1 1.000000
1
3
2
2
0 7.389056
1 1.000000
1
6
2
2
0 7.389056
1 1.000000
1
1
2
2
0 7.389056
1 1.000000
1
4
2
2
0 7.389056
1 1.000000
1
7
2
2
0 7.389056
1 1.000000
1
2
2
2
0 7.389056
1 1.000000
1
5
2
2
0 7.389056
1 1.000000
1
8
2
2
0 7.389056
1 1.000000
2
9 12
2 2
4
0 4.481689
1 1.000000
2 4.481689
3 4.481689
2
10 13
2 2
4
0 4.481689
1 1.000000
2 4.481689
3 4.481689
2
11 14
2 2
4
0 4.481689
1 1.000000
2 4.481689
3 4.481689
2
0 9
2 2
4
0 3.004166
1 3.004166
2 3.004166
3 3.004166
3
3 10 9
2 2 2
8
0 3.004166
1 3.004166
2 3.004166
3 1.000000
4 3.004166
5 1.000000
6 3.004166
7 3.004166
3
6 11 9
2 2 2
8
0 3.004166
1 3.004166
2 3.004166
3 1.000000
4 3.004166
5 1.000000
6 3.004166
7 3.004166
3
1 9 10
2 2 2
8
0 3.004166
1 3.004166
2 3.004166
3 1.000000
4 3.004166
5 1.000000
6 3.004166
7 3.004166
2
4 10
2 2
4
0 3.004166
1 3.004166
2 3.004166
3 3.004166
3
7 11 10
2 2 2
8
0 3.004166
1 3.004166
2 3.004166
3 1.000000
4 3.004166
5 1.000000
6 3.004166
7 3.004166
3
2 9 11
2 2 2
8
0 3.004166
1 3.004166
2 3.004166
3 1.000000
4 3.004166
5 1.000000
6 3.004166
7 3.004166
3
5 10 11
2 2 2
8
0 3.004166
1 3.004166
2 3.004166
3 1.000000
4 3.004166
5 1.000000
6 3.004166
7 3.004166
2
8 11
2 2
4
0 3.004166
1 3.004166
2 3.004166
3 3.004166

View File

@ -0,0 +1,110 @@
:- use_module(library(pfl)).
:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- multifile people/2.
:- multifile ev/1.
:- clpbn_horus:set_horus_flag(verbosity,5).
people(joe,nyc).
people(p2, nyc).
people(p3, nyc).
people(p4, nyc).
people(p5, nyc).
people(p6, nyc).
people(p7, nyc).
people(p8, nyc).
%ev(descn(p2, t)).
%ev(descn(p3, t)).
%ev(descn(p4, t)).
%ev(descn(p5, t)).
bayes city_conservativeness(C)::[y,n] ; cons_table(C) ; [people(_,C)].
bayes gender(P)::[m,f] ; gender_table(P) ; [people(P,_)].
bayes hair_color(P)::[t,f], city_conservativeness(C) ; hair_color_table(P) ; [people(P,C)].
bayes car_color(P)::[t,f], hair_color(P) ; car_color_table(P); [people(P,_)].
bayes height(P)::[t,f], gender(P) ; height_table(P) ; [people(P,_)].
bayes shoe_size(P):[t,f], height(P) ; shoe_size_table(P); [people(P,_)].
bayes guilty(P)::[y,n] ; guilty_table(P) ; [people(P,_)].
bayes descn(P)::[t,f], car_color(P), hair_color(P), height(P), guilty(P) ; descn_table(P) ; [people(P,_)].
bayes witness(C)::[t,f], descn(Joe), descn(P2) ; wit_table ; [people(_,C), Joe=joe, P2=p2].
% FIXME
%cons_table(amsterdam, [0.2, 0.8]) :- !.
cons_table(_, [0.8, 0.2]).
gender_table(_, [0.55, 0.45]).
hair_color_table(_,
/* conservative_city */
/* y n */
[ 0.05, 0.1,
0.95, 0.9 ]).
car_color_table(_,
/* t f */
[ 0.9, 0.2,
0.1, 0.8 ]).
height_table(_,
/* m f */
[ 0.6, 0.4,
0.4, 0.6 ]).
shoe_size_table(_,
/* t f */
[ 0.9, 0.1,
0.1, 0.9 ]).
guilty_table(_, [0.23, 0.77]).
descn_table(_,
/* color, hair, height, guilt */
/* ttttt tttf ttft ttff tfttt tftf tfft tfff ttttt fttf ftft ftff ffttt fftf ffft ffff */
[ 0.99, 0.5, 0.23, 0.88, 0.41, 0.3, 0.76, 0.87, 0.44, 0.43, 0.29, 0.72, 0.23, 0.91, 0.95, 0.92,
0.01, 0.5, 0.77, 0.12, 0.59, 0.7, 0.24, 0.13, 0.56, 0.57, 0.71, 0.28, 0.77, 0.09, 0.05, 0.08]).
wit_table([0.2, 0.45, 0.24, 0.34,
0.8, 0.55, 0.76, 0.66]).
runall(G, Wrapper) :-
findall(G, Wrapper, L),
execute_all(L).
execute_all([]).
execute_all(G.L) :-
call(G),
execute_all(L).
is_joe_guilty(Guilty) :-
witness(nyc, t),
runall(X, ev(X)),
guilty(joe, Guilty).
?- is_joe_guilty(Guilty).

View File

@ -0,0 +1,33 @@
:- use_module(library(pfl)).
:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- multifile people/1.
:- clpbn_horus:set_horus_flag(verbosity,5).
people @ 5.
people(X,Y) :-
people(X),
people(Y),
X \== Y.
markov smokes(X)::[t,f]; [1.0, 4.0552]; [people(X)].
markov cancer(X)::[t,f]; [1.0, 9.9742]; [people(X)].
markov friends(X,Y)::[t,f] ; [1.0, 99.48432] ; [people(X,Y)].
markov smokes(X)::[t,f], cancer(X)::[t,f] ; [4.48169, 4.48169, 1.0, 4.48169] ; [people(X)].
markov friends(X,Y)::[t,f], smokes(X)::[t,f], smokes(Y)::[t,f] ;
[3.004166, 3.004166, 3.004166, 3.004166, 3.004166, 1.0, 1.0, 3.004166] ; [people(X,Y)].
?- friends(p1,p2,X).

View File

@ -0,0 +1,33 @@
:- use_module(library(pfl)).
:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- clpbn_horus:set_horus_flag(verbosity,5).
:- clpbn_horus:set_horus_flag(use_logarithms,true).
:- multifile people/1.
people @ 12.
people(X,Y) :-
people(X),
people(Y).
markov smokes(X)::[t,f]; [1.0, 4.0]; [people(X)].
markov asthma(X)::[t,f]; [2.5, 9.0] ; [people(X)].
markov friends(X,Y)::[t,f]; [1.0, 14.0] ; [people(X,Y)].
markov asthma(X)::[t,f], smokes(X)::[t,f]; [4.5, 4.3, 2.0, 1.45] ; [people(X)].
markov asthma(X)::[t,f], friends(X,Y)::[t,f], smokes(Y)::[t,f];
[2.1, 3.3, 7.4, 3.9, 1.6, 5.0, 4.0, 3.0] ; [people(X,Y)].
?- friends(p1,p2,X).

View File

@ -0,0 +1,29 @@
:- use_module(library(pfl)).
%:- set_solver(fove).
%:- set_solver(hve).
%:- set_solver(bp).
%:- set_solver(cbp).
:- yap_flag(write_strings, off).
:- multifile people/1.
people @ 5.
markov attends(P)::[t,f], attr1::[t,f] ; [0.7, 0.3, 0.3, 0.3] ; [people(P)].
markov attends(P)::[t,f], attr2::[t,f] ; [0.7, 0.3, 0.3, 0.3] ; [people(P)].
markov attends(P)::[t,f], attr3::[t,f] ; [0.7, 0.3, 0.3, 0.3] ; [people(P)].
markov attends(P)::[t,f], attr4::[t,f] ; [0.7, 0.3, 0.3, 0.3] ; [people(P)].
markov attends(P)::[t,f], attr5::[t,f] ; [0.7, 0.3, 0.3, 0.3] ; [people(P)].
markov attends(P)::[t,f], attr6::[t,f] ; [0.7, 0.3, 0.3, 0.3] ; [people(P)].
markov attends(P)::[t,f], series::[t,f] ; [0.501, 0.499, 0.499, 0.499] ; [people(P)].
% ?- series(X).

File diff suppressed because it is too large Load Diff

BIN
packages/CLPBN/horus/hcli Executable file

Binary file not shown.