Merge branch 'master' of git.dcc.fc.up.pt:yap-6.3

This commit is contained in:
Ricardo Rocha 2011-12-12 17:25:02 +00:00
commit 5f6fd7daea
64 changed files with 6554 additions and 10069 deletions

View File

@ -8,6 +8,8 @@
:- module(clpbn_bp,
[bp/3,
check_if_bp_done/1,
set_solver_parameter/2,
use_log_space/0,
init_bp_solver/4,
run_bp_solver/3,
finalize_bp_solver/1
@ -34,116 +36,136 @@
:- attribute id/1.
:- dynamic num_bayes_nets/1.
:- dynamic network_counting/1.
check_if_bp_done(_Var).
num_bayes_nets(0).
network_counting(0).
:- set_solver_parameter(run_mode, normal).
%:- set_solver_parameter(run_mode, convert).
%: -set_solver_parameter(run_mode, compress).
:- set_solver_parameter(schedule, seq_fixed).
%:- set_solver_parameter(schedule, seq_random).
%:- set_solver_parameter(schedule, parallel).
%:- set_solver_parameter(schedule, max_residual).
:- set_solver_parameter(accuracy, 0.0001).
:- set_solver_parameter(max_iter, 1000).
:- set_solver_parameter(always_loopy_solver, false).
% :- use_log_space.
bp([[]],_,_) :- !.
bp([QueryVars], AllVars, Output) :-
init_bp_solver(_, AllVars, _, BayesNet),
run_bp_solver([QueryVars], LPs, BayesNet),
finalize_bp_solver(BayesNet),
clpbn_bind_vals([QueryVars], LPs, Output).
init_bp_solver(_, AllVars, _, BayesNet),
run_bp_solver([QueryVars], LPs, BayesNet),
finalize_bp_solver(BayesNet),
clpbn_bind_vals([QueryVars], LPs, Output).
init_bp_solver(_, AllVars, _, (BayesNet, DistIds)) :-
%inc_num_bayes_nets,
%(showprofres(50) -> true ; true),
process_ids(AllVars, 0, DistIds0),
get_vars_info(AllVars, VarsInfo),
sort(DistIds0, DistIds),
%(num_bayes_nets(0) -> writeln(vars:VarsInfo) ; true),
%(num_bayes_nets(0) -> writeln(dists:DistsInfo) ; true),
create_network(VarsInfo, BayesNet).
%set_extra_vars_info(BayesNet, ExtraVarsInfo).
%inc_network_counting,
process_ids(AllVars, 0, DistIds0),
get_vars_info(AllVars, VarsInfo),
sort(DistIds0, DistIds),
%(network_counting(0) -> writeln(vars:VarsInfo) ; true),
%(network_counting(0) -> writeln(distsids:DistIds) ; true),
create_network(VarsInfo, BayesNet).
%get_extra_vars_info(AllVars, ExtraVarsInfo),
%(network_counting(0) -> writeln(extra:ExtraVarsInfo) ; true),
%set_extra_vars_info(BayesNet, ExtraVarsInfo).
process_ids([], _, []).
process_ids([V|Vs], VarId0, [DistId|DistIds]) :-
clpbn:get_atts(V, [dist(DistId, _)]), !,
put_atts(V, [id(VarId0)]),
VarId is VarId0 + 1,
process_ids(Vs, VarId, DistIds).
clpbn:get_atts(V, [dist(DistId, _)]), !,
put_atts(V, [id(VarId0)]),
VarId is VarId0 + 1,
process_ids(Vs, VarId, DistIds).
process_ids([_|Vs], VarId, DistIds) :-
process_ids(Vs, VarId, DistIds).
process_ids(Vs, VarId, DistIds).
get_vars_info([], []).
get_vars_info([V|Vs], [var(VarId, DSize, Ev, ParentIds, DistId)|VarsInfo]) :-
clpbn:get_atts(V, [dist(DistId, Parents)]), !,
get_atts(V, [id(VarId)]),
get_dist_domain_size(DistId, DSize),
get_evidence(V, Ev),
vars2ids(Parents, ParentIds),
get_vars_info(Vs, VarsInfo).
clpbn:get_atts(V, [dist(DistId, Parents)]), !,
get_atts(V, [id(VarId)]),
get_dist_domain_size(DistId, DSize),
get_evidence(V, Ev),
vars2ids(Parents, ParentIds),
get_vars_info(Vs, VarsInfo).
get_vars_info([_|Vs], VarsInfo) :-
get_vars_info(Vs, VarsInfo).
get_vars_info(Vs, VarsInfo).
vars2ids([], []).
vars2ids([V|QueryVars], [VarId|Ids]) :-
get_atts(V, [id(VarId)]),
vars2ids(QueryVars, Ids).
get_atts(V, [id(VarId)]),
vars2ids(QueryVars, Ids).
get_evidence(V, Ev) :-
clpbn:get_atts(V, [evidence(Ev)]), !.
clpbn:get_atts(V, [evidence(Ev)]), !.
get_evidence(_V, -1). % no evidence !!!
get_extra_vars_info([], []).
get_extra_vars_info([V|Vs], [v(VarId, Label, Domain)|VarsInfo]) :-
get_atts(V, [id(VarId)]), !,
clpbn:get_atts(V, [key(Key),dist(DistId, _)]),
term_to_atom(Key, Label),
get_dist_domain(DistId, Domain0),
numbers2atoms(Domain0, Domain),
get_extra_vars_info(Vs, VarsInfo).
get_atts(V, [id(VarId)]), !,
clpbn:get_atts(V, [key(Key),dist(DistId, _)]),
term_to_atom(Key, Label),
get_dist_domain(DistId, Domain0),
numbers2atoms(Domain0, Domain),
get_extra_vars_info(Vs, VarsInfo).
get_extra_vars_info([_|Vs], VarsInfo) :-
get_extra_vars_info(Vs, VarsInfo).
numbers2atoms([], []).
numbers2atoms([Atom|L0], [Atom|L]) :-
atom(Atom), !,
numbers2atoms(L0, L).
atom(Atom), !,
numbers2atoms(L0, L).
numbers2atoms([Number|L0], [Atom|L]) :-
number_atom(Number, Atom),
numbers2atoms(L0, L).
number_atom(Number, Atom),
numbers2atoms(L0, L).
run_bp_solver(QVsL0, LPs, (BayesNet, DistIds)) :-
get_dists_parameters(DistIds, DistsParams),
set_parameters(BayesNet, DistsParams),
process_query_list(QVsL0, QVsL),
%writeln(' qvs':QVsL),
%(num_bayes_nets(1506) -> writeln(qvs:QVsL) ; true),
run_solver(BayesNet, QVsL, LPs).
get_dists_parameters(DistIds, DistsParams),
set_parameters(BayesNet, DistsParams),
process_query_list(QVsL0, QVsL),
%(network_counting(0) -> writeln(qvs:QVsL) ; true),
run_solver(BayesNet, QVsL, LPs).
process_query_list([], []).
process_query_list([[V]|QueryVars], [VarId|Ids]) :- !,
get_atts(V, [id(VarId)]),
process_query_list(QueryVars, Ids).
get_atts(V, [id(VarId)]),
process_query_list(QueryVars, Ids).
process_query_list([Vs|QueryVars], [VarIds|Ids]) :-
vars2ids(Vs, VarIds),
process_query_list(QueryVars, Ids).
vars2ids(Vs, VarIds),
process_query_list(QueryVars, Ids).
get_dists_parameters([],[]).
get_dists_parameters([Id|Ids], [dist(Id, Params)|DistsInfo]) :-
get_dist_params(Id, Params),
get_dists_parameters(Ids, DistsInfo).
get_dist_params(Id, Params),
get_dists_parameters(Ids, DistsInfo).
finalize_bp_solver((BayesNet, _)) :-
delete_bayes_net(BayesNet).
free_bayesian_network(BayesNet).
inc_num_bayes_nets :-
retract(num_bayes_nets(Count0)),
Count is Count0 + 1,
assert(num_bayes_nets(Count)).
inc_network_counting :-
retract(network_counting(Count0)),
Count is Count0 + 1,
assert(network_counting(Count)).

View File

@ -1,149 +0,0 @@
#include <cassert>
#include <cmath>
#include <iostream>
#include "BPNodeInfo.h"
#include "BPSolver.h"
BPNodeInfo::BPNodeInfo (BayesNode* node)
{
node_ = node;
ds_ = node->getDomainSize();
piValsCalc_ = false;
ldValsCalc_ = false;
nPiMsgsRcv_ = 0;
nLdMsgsRcv_ = 0;
piVals_.resize (ds_, 1);
ldVals_.resize (ds_, 1);
const BnNodeSet& childs = node->getChilds();
for (unsigned i = 0; i < childs.size(); i++) {
cmsgs_.insert (make_pair (childs[i], false));
}
const BnNodeSet& parents = node->getParents();
for (unsigned i = 0; i < parents.size(); i++) {
pmsgs_.insert (make_pair (parents[i], false));
}
}
ParamSet
BPNodeInfo::getBeliefs (void) const
{
double sum = 0.0;
ParamSet beliefs (ds_);
for (unsigned xi = 0; xi < ds_; xi++) {
double prod = piVals_[xi] * ldVals_[xi];
beliefs[xi] = prod;
sum += prod;
}
assert (sum);
//normalize the beliefs
for (unsigned xi = 0; xi < ds_; xi++) {
beliefs[xi] /= sum;
}
return beliefs;
}
bool
BPNodeInfo::readyToSendPiMsgTo (const BayesNode* child) const
{
for (unsigned i = 0; i < inChildLinks_.size(); i++) {
if (inChildLinks_[i]->getSource() != child
&& !inChildLinks_[i]->messageWasSended()) {
return false;
}
}
return true;
}
bool
BPNodeInfo::readyToSendLambdaMsgTo (const BayesNode* parent) const
{
for (unsigned i = 0; i < inParentLinks_.size(); i++) {
if (inParentLinks_[i]->getSource() != parent
&& !inParentLinks_[i]->messageWasSended()) {
return false;
}
}
return true;
}
double
BPNodeInfo::getPiValue (unsigned idx) const
{
assert (idx >=0 && idx < ds_);
return piVals_[idx];
}
void
BPNodeInfo::setPiValue (unsigned idx, Param value)
{
assert (idx >=0 && idx < ds_);
piVals_[idx] = value;
}
double
BPNodeInfo::getLambdaValue (unsigned idx) const
{
assert (idx >=0 && idx < ds_);
return ldVals_[idx];
}
void
BPNodeInfo::setLambdaValue (unsigned idx, Param value)
{
assert (idx >=0 && idx < ds_);
ldVals_[idx] = value;
}
double
BPNodeInfo::getBeliefChange (void)
{
double change = 0.0;
if (oldBeliefs_.size() == 0) {
oldBeliefs_ = getBeliefs();
change = 9999999999.0;
} else {
ParamSet currentBeliefs = getBeliefs();
for (unsigned xi = 0; xi < ds_; xi++) {
change += abs (currentBeliefs[xi] - oldBeliefs_[xi]);
}
oldBeliefs_ = currentBeliefs;
}
return change;
}
bool
BPNodeInfo::receivedBottomInfluence (void) const
{
// if all lambda values are equal, then neither
// this node neither its descendents have evidence,
// we can use this to don't send lambda messages his parents
bool childInfluenced = false;
for (unsigned xi = 1; xi < ds_; xi++) {
if (ldVals_[xi] != ldVals_[0]) {
childInfluenced = true;
break;
}
}
return childInfluenced;
}

View File

@ -1,82 +0,0 @@
#ifndef BP_BP_NODE_H
#define BP_BP_NODE_H
#include <vector>
#include <map>
#include "BPSolver.h"
#include "BayesNode.h"
#include "Shared.h"
//class Edge;
using namespace std;
class BPNodeInfo
{
public:
BPNodeInfo (int);
BPNodeInfo (BayesNode*);
ParamSet getBeliefs (void) const;
double getPiValue (unsigned) const;
void setPiValue (unsigned, Param);
double getLambdaValue (unsigned) const;
void setLambdaValue (unsigned, Param);
double getBeliefChange (void);
bool receivedBottomInfluence (void) const;
ParamSet& getPiValues (void) { return piVals_; }
ParamSet& getLambdaValues (void) { return ldVals_; }
bool arePiValuesCalculated (void) { return piValsCalc_; }
bool areLambdaValuesCalculated (void) { return ldValsCalc_; }
void markPiValuesAsCalculated (void) { piValsCalc_ = true; }
void markLambdaValuesAsCalculated (void) { ldValsCalc_ = true; }
void incNumPiMsgsRcv (void) { nPiMsgsRcv_ ++; }
void incNumLambdaMsgsRcv (void) { nLdMsgsRcv_ ++; }
bool receivedAllPiMessages (void)
{
return node_->getParents().size() == nPiMsgsRcv_;
}
bool receivedAllLambdaMessages (void)
{
return node_->getChilds().size() == nLdMsgsRcv_;
}
bool readyToSendPiMsgTo (const BayesNode*) const ;
bool readyToSendLambdaMsgTo (const BayesNode*) const;
CEdgeSet getIncomingParentLinks (void) { return inParentLinks_; }
CEdgeSet getIncomingChildLinks (void) { return inChildLinks_; }
CEdgeSet getOutcomingParentLinks (void) { return outParentLinks_; }
CEdgeSet getOutcomingChildLinks (void) { return outChildLinks_; }
void addIncomingParentLink (Edge* l) { inParentLinks_.push_back (l); }
void addIncomingChildLink (Edge* l) { inChildLinks_.push_back (l); }
void addOutcomingParentLink (Edge* l) { outParentLinks_.push_back (l); }
void addOutcomingChildLink (Edge* l) { outChildLinks_.push_back (l); }
private:
DISALLOW_COPY_AND_ASSIGN (BPNodeInfo);
ParamSet piVals_; // pi values
ParamSet ldVals_; // lambda values
ParamSet oldBeliefs_;
unsigned nPiMsgsRcv_;
unsigned nLdMsgsRcv_;
bool piValsCalc_;
bool ldValsCalc_;
EdgeSet inParentLinks_;
EdgeSet inChildLinks_;
EdgeSet outParentLinks_;
EdgeSet outChildLinks_;
unsigned ds_;
const BayesNode* node_;
map<const BayesNode*, bool> pmsgs_;
map<const BayesNode*, bool> cmsgs_;
};
#endif //BP_BP_NODE_H

View File

@ -1,905 +0,0 @@
#include <cstdlib>
#include <limits>
#include <time.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "BPSolver.h"
BPSolver::BPSolver (const BayesNet& bn) : Solver (&bn)
{
bn_ = &bn;
useAlwaysLoopySolver_ = false;
//jointCalcType_ = CHAIN_RULE;
jointCalcType_ = JUNCTION_NODE;
}
BPSolver::~BPSolver (void)
{
for (unsigned i = 0; i < nodesI_.size(); i++) {
delete nodesI_[i];
}
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
}
void
BPSolver::runSolver (void)
{
clock_t start_ = clock();
unsigned size = bn_->getNumberOfNodes();
unsigned nIters = 0;
initializeSolver();
if (bn_->isSingleConnected() && !useAlwaysLoopySolver_) {
runPolyTreeSolver();
Statistics::numSolvedPolyTrees ++;
} else {
runLoopySolver();
Statistics::numSolvedLoopyNets ++;
if (nIter_ >= SolverOptions::maxIter) {
Statistics::numUnconvergedRuns ++;
} else {
nIters = nIter_;
}
if (DL >= 2) {
cout << endl;
if (nIter_ < SolverOptions::maxIter) {
cout << "Belief propagation converged in " ;
cout << nIter_ << " iterations" << endl;
} else {
cout << "The maximum number of iterations was hit, terminating..." ;
cout << endl;
}
}
}
double time = (double (clock() - start_)) / CLOCKS_PER_SEC;
Statistics::updateStats (size, nIters, time);
if (EXPORT_TO_DOT && size > EXPORT_MIN_SIZE) {
stringstream ss;
ss << size << "." ;
ss << Statistics::getCounting (size) << ".dot" ;
bn_->exportToDotFormat (ss.str().c_str());
}
}
ParamSet
BPSolver::getPosterioriOf (Vid vid) const
{
BayesNode* node = bn_->getBayesNode (vid);
assert (node);
return nodesI_[node->getIndex()]->getBeliefs();
}
ParamSet
BPSolver::getJointDistributionOf (const VidSet& jointVids)
{
if (DL >= 2) {
cout << "calculating joint distribution on: " ;
for (unsigned i = 0; i < jointVids.size(); i++) {
Variable* var = bn_->getBayesNode (jointVids[i]);
cout << var->getLabel() << " " ;
}
cout << endl;
}
if (jointCalcType_ == JUNCTION_NODE) {
return getJointByJunctionNode (jointVids);
} else {
return getJointByChainRule (jointVids);
}
}
void
BPSolver::initializeSolver (void)
{
if (DL >= 2) {
if (!useAlwaysLoopySolver_) {
cout << "-> solver type = polytree solver" << endl;
cout << "-> schedule = n/a";
} else {
cout << "-> solver = loopy solver" << endl;
cout << "-> schedule = ";
switch (SolverOptions::schedule) {
case SolverOptions::S_SEQ_FIXED: cout << "sequential fixed" ; break;
case SolverOptions::S_SEQ_RANDOM: cout << "sequential random" ; break;
case SolverOptions::S_PARALLEL: cout << "parallel" ; break;
case SolverOptions::S_MAX_RESIDUAL: cout << "max residual" ; break;
}
}
cout << endl;
cout << "-> joint method = " ;
if (jointCalcType_ == JUNCTION_NODE) {
cout << "junction node" << endl;
} else {
cout << "chain rule " << endl;
}
cout << "-> max iters = " << SolverOptions::maxIter << endl;
cout << "-> accuracy = " << SolverOptions::accuracy << endl;
cout << endl;
}
CBnNodeSet nodes = bn_->getBayesNodes();
for (unsigned i = 0; i < nodesI_.size(); i++) {
delete nodesI_[i];
}
nodesI_.clear();
nodesI_.reserve (nodes.size());
links_.clear();
sortedOrder_.clear();
edgeMap_.clear();
for (unsigned i = 0; i < nodes.size(); i++) {
nodesI_.push_back (new BPNodeInfo (nodes[i]));
}
BnNodeSet roots = bn_->getRootNodes();
for (unsigned i = 0; i < roots.size(); i++) {
const ParamSet& params = roots[i]->getParameters();
ParamSet& piVals = M(roots[i])->getPiValues();
for (unsigned ri = 0; ri < roots[i]->getDomainSize(); ri++) {
piVals[ri] = params[ri];
}
}
for (unsigned i = 0; i < nodes.size(); i++) {
CBnNodeSet parents = nodes[i]->getParents();
for (unsigned j = 0; j < parents.size(); j++) {
Edge* newLink = new Edge (parents[j], nodes[i], PI_MSG);
links_.push_back (newLink);
M(nodes[i])->addIncomingParentLink (newLink);
M(parents[j])->addOutcomingChildLink (newLink);
}
CBnNodeSet childs = nodes[i]->getChilds();
for (unsigned j = 0; j < childs.size(); j++) {
Edge* newLink = new Edge (childs[j], nodes[i], LAMBDA_MSG);
links_.push_back (newLink);
M(nodes[i])->addIncomingChildLink (newLink);
M(childs[j])->addOutcomingParentLink (newLink);
}
}
for (unsigned i = 0; i < nodes.size(); i++) {
if (nodes[i]->hasEvidence()) {
ParamSet& piVals = M(nodes[i])->getPiValues();
ParamSet& ldVals = M(nodes[i])->getLambdaValues();
for (unsigned xi = 0; xi < nodes[i]->getDomainSize(); xi++) {
piVals[xi] = 0.0;
ldVals[xi] = 0.0;
}
piVals[nodes[i]->getEvidence()] = 1.0;
ldVals[nodes[i]->getEvidence()] = 1.0;
}
}
}
void
BPSolver::runPolyTreeSolver (void)
{
CBnNodeSet nodes = bn_->getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
if (nodes[i]->isRoot()) {
M(nodes[i])->markPiValuesAsCalculated();
}
if (nodes[i]->isLeaf()) {
M(nodes[i])->markLambdaValuesAsCalculated();
}
}
bool finish = false;
while (!finish) {
finish = true;
for (unsigned i = 0; i < nodes.size(); i++) {
if (M(nodes[i])->arePiValuesCalculated() == false
&& M(nodes[i])->receivedAllPiMessages()) {
if (!nodes[i]->hasEvidence()) {
updatePiValues (nodes[i]);
}
M(nodes[i])->markPiValuesAsCalculated();
finish = false;
}
if (M(nodes[i])->areLambdaValuesCalculated() == false
&& M(nodes[i])->receivedAllLambdaMessages()) {
if (!nodes[i]->hasEvidence()) {
updateLambdaValues (nodes[i]);
}
M(nodes[i])->markLambdaValuesAsCalculated();
finish = false;
}
if (M(nodes[i])->arePiValuesCalculated()) {
CEdgeSet outChildLinks = M(nodes[i])->getOutcomingChildLinks();
for (unsigned j = 0; j < outChildLinks.size(); j++) {
BayesNode* child = outChildLinks[j]->getDestination();
if (!outChildLinks[j]->messageWasSended()) {
if (M(nodes[i])->readyToSendPiMsgTo (child)) {
outChildLinks[j]->setNextMessage (getMessage (outChildLinks[j]));
outChildLinks[j]->updateMessage();
M(child)->incNumPiMsgsRcv();
}
finish = false;
}
}
}
if (M(nodes[i])->areLambdaValuesCalculated()) {
CEdgeSet outParentLinks = M(nodes[i])->getOutcomingParentLinks();
for (unsigned j = 0; j < outParentLinks.size(); j++) {
BayesNode* parent = outParentLinks[j]->getDestination();
if (!outParentLinks[j]->messageWasSended()) {
if (M(nodes[i])->readyToSendLambdaMsgTo (parent)) {
outParentLinks[j]->setNextMessage (getMessage (outParentLinks[j]));
outParentLinks[j]->updateMessage();
M(parent)->incNumLambdaMsgsRcv();
}
finish = false;
}
}
}
}
}
}
void
BPSolver::runLoopySolver()
{
nIter_ = 0;
while (!converged() && nIter_ < SolverOptions::maxIter) {
nIter_++;
if (DL >= 2) {
cout << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
cout << " Iteration " << nIter_ << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
}
switch (SolverOptions::schedule) {
case SolverOptions::S_SEQ_RANDOM:
random_shuffle (links_.begin(), links_.end());
// no break
case SolverOptions::S_SEQ_FIXED:
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->setNextMessage (getMessage (links_[i]));
links_[i]->updateMessage();
updateValues (links_[i]);
}
break;
case SolverOptions::S_PARALLEL:
for (unsigned i = 0; i < links_.size(); i++) {
//calculateNextMessage (links_[i]);
}
for (unsigned i = 0; i < links_.size(); i++) {
//updateMessage (links_[i]);
//updateValues (links_[i]);
}
break;
case SolverOptions::S_MAX_RESIDUAL:
maxResidualSchedule();
break;
}
}
}
bool
BPSolver::converged (void) const
{
// this can happen if the graph is fully disconnected
if (links_.size() == 0) {
return true;
}
if (nIter_ == 0 || nIter_ == 1) {
return false;
}
bool converged = true;
if (SolverOptions::schedule == SolverOptions::S_MAX_RESIDUAL) {
Param maxResidual = (*(sortedOrder_.begin()))->getResidual();
if (maxResidual < SolverOptions::accuracy) {
converged = true;
} else {
converged = false;
}
} else {
CBnNodeSet nodes = bn_->getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
if (!nodes[i]->hasEvidence()) {
double change = M(nodes[i])->getBeliefChange();
if (DL >= 2) {
cout << nodes[i]->getLabel() + " belief change = " ;
cout << change << endl;
}
if (change > SolverOptions::accuracy) {
converged = false;
if (DL == 0) break;
}
}
}
}
return converged;
}
void
BPSolver::maxResidualSchedule (void)
{
if (nIter_ == 1) {
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->setNextMessage (getMessage (links_[i]));
links_[i]->updateResidual();
SortedOrder::iterator it = sortedOrder_.insert (links_[i]);
edgeMap_.insert (make_pair (links_[i], it));
if (DL >= 2) {
cout << "calculating " << links_[i]->toString() << endl;
}
}
return;
}
for (unsigned c = 0; c < sortedOrder_.size(); c++) {
if (DL >= 2) {
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();
Edge* edge = *it;
if (DL >= 2) {
cout << "updating " << edge->toString() << endl;
}
if (edge->getResidual() < SolverOptions::accuracy) {
return;
}
edge->updateMessage();
updateValues (edge);
edge->clearResidual();
sortedOrder_.erase (it);
edgeMap_.find (edge)->second = sortedOrder_.insert (edge);
// update the messages that depend on message source --> destin
CEdgeSet outChildLinks =
M(edge->getDestination())->getOutcomingChildLinks();
for (unsigned i = 0; i < outChildLinks.size(); i++) {
if (outChildLinks[i]->getDestination() != edge->getSource()) {
if (DL >= 2) {
cout << " calculating " << outChildLinks[i]->toString() << endl;
}
outChildLinks[i]->setNextMessage (getMessage (outChildLinks[i]));
outChildLinks[i]->updateResidual();
EdgeMap::iterator iter = edgeMap_.find (outChildLinks[i]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (outChildLinks[i]);
}
}
CEdgeSet outParentLinks =
M(edge->getDestination())->getOutcomingParentLinks();
for (unsigned i = 0; i < outParentLinks.size(); i++) {
if (outParentLinks[i]->getDestination() != edge->getSource()) {
//&& !outParentLinks[i]->getDestination()->hasEvidence()) FIXME{
if (DL >= 2) {
cout << " calculating " << outParentLinks[i]->toString() << endl;
}
outParentLinks[i]->setNextMessage (getMessage (outParentLinks[i]));
outParentLinks[i]->updateResidual();
EdgeMap::iterator iter = edgeMap_.find (outParentLinks[i]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (outParentLinks[i]);
}
}
}
}
void
BPSolver::updatePiValues (BayesNode* x)
{
// π(Xi)
if (DL >= 3) {
cout << "updating " << PI << " values for " << x->getLabel() << endl;
}
CEdgeSet parentLinks = M(x)->getIncomingParentLinks();
assert (x->getParents() == parentLinks.size());
const vector<CptEntry>& entries = x->getCptEntries();
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
ParamSet messageProducts (entries.size());
for (unsigned k = 0; k < entries.size(); k++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
double messageProduct = 1.0;
const DConf& conf = entries[k].getDomainConfiguration();
for (unsigned i = 0; i < parentLinks.size(); i++) {
assert (parentLinks[i]->getSource() == parents[i]);
assert (parentLinks[i]->getDestination() == x);
messageProduct *= parentLinks[i]->getMessage()[conf[i]];
if (DL >= 5) {
if (i != 0) *calcs1 << "." ;
if (i != 0) *calcs2 << "*" ;
*calcs1 << PI << "(" << parentLinks[i]->getSource()->getLabel();
*calcs1 << " --> " << x->getLabel() << ")" ;
*calcs1 << "[" ;
*calcs1 << parentLinks[i]->getSource()->getDomain()[conf[i]];
*calcs1 << "]";
*calcs2 << parentLinks[i]->getMessage()[conf[i]];
}
}
messageProducts[k] = messageProduct;
if (DL >= 5) {
cout << " mp" << k;
cout << " = " << (*calcs1).str();
if (parentLinks.size() == 1) {
cout << " = " << messageProduct << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << messageProduct << endl;
}
delete calcs1;
delete calcs2;
}
}
for (unsigned xi = 0; xi < x->getDomainSize(); xi++) {
double sum = 0.0;
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
for (unsigned k = 0; k < entries.size(); k++) {
sum += x->getProbability (xi, entries[k]) * messageProducts[k];
if (DL >= 5) {
if (k != 0) *calcs1 << " + " ;
if (k != 0) *calcs2 << " + " ;
*calcs1 << x->cptEntryToString (xi, entries[k]);
*calcs1 << ".mp" << k;
*calcs2 << x->getProbability (xi, entries[k]);
*calcs2 << "*" << messageProducts[k];
}
}
M(x)->setPiValue (xi, sum);
if (DL >= 5) {
cout << " " << PI << "(" << x->getLabel() << ")" ;
cout << "[" << x->getDomain()[xi] << "]" ;
cout << " = " << (*calcs1).str();
cout << " = " << (*calcs2).str();
cout << " = " << sum << endl;
delete calcs1;
delete calcs2;
}
}
}
void
BPSolver::updateLambdaValues (BayesNode* x)
{
// λ(Xi)
if (DL >= 3) {
cout << "updating " << LD << " values for " << x->getLabel() << endl;
}
CEdgeSet childLinks = M(x)->getIncomingChildLinks();
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
for (unsigned xi = 0; xi < x->getDomainSize(); xi++) {
double product = 1.0;
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
for (unsigned i = 0; i < childLinks.size(); i++) {
assert (childLinks[i]->getDestination() == x);
product *= childLinks[i]->getMessage()[xi];
if (DL >= 5) {
if (i != 0) *calcs1 << "." ;
if (i != 0) *calcs2 << "*" ;
*calcs1 << LD << "(" << childLinks[i]->getSource()->getLabel();
*calcs1 << "-->" << x->getLabel() << ")" ;
*calcs1 << "[" << x->getDomain()[xi] << "]" ;
*calcs2 << childLinks[i]->getMessage()[xi];
}
}
M(x)->setLambdaValue (xi, product);
if (DL >= 5) {
cout << " " << LD << "(" << x->getLabel() << ")" ;
cout << "[" << x->getDomain()[xi] << "]" ;
cout << " = " << (*calcs1).str();
if (childLinks.size() == 1) {
cout << " = " << product << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << product << endl;
}
delete calcs1;
delete calcs2;
}
}
}
ParamSet
BPSolver::calculateNextPiMessage (Edge* edge)
{
// πX(Zi)
BayesNode* z = edge->getSource();
BayesNode* x = edge->getDestination();
ParamSet zxPiNextMessage (z->getDomainSize());
CEdgeSet zChildLinks = M(z)->getIncomingChildLinks();
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
for (unsigned zi = 0; zi < z->getDomainSize(); zi++) {
double product = M(z)->getPiValue (zi);
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
*calcs1 << PI << "(" << z->getLabel() << ")";
*calcs1 << "[" << z->getDomain()[zi] << "]" ;
*calcs2 << product;
}
for (unsigned i = 0; i < zChildLinks.size(); i++) {
assert (zChildLinks[i]->getDestination() == z);
if (zChildLinks[i]->getSource() != x) {
product *= zChildLinks[i]->getMessage()[zi];
if (DL >= 5) {
*calcs1 << "." << LD << "(" << zChildLinks[i]->getSource()->getLabel();
*calcs1 << "-->" << z->getLabel() << ")";
*calcs1 << "[" << z->getDomain()[zi] + "]" ;
*calcs2 << " * " << zChildLinks[i]->getMessage()[zi];
}
}
}
zxPiNextMessage[zi] = product;
if (DL >= 5) {
cout << " " << PI << "(" << z->getLabel();
cout << "-->" << x->getLabel() << ")" ;
cout << "[" << z->getDomain()[zi] << "]" ;
cout << " = " << (*calcs1).str();
if (zChildLinks.size() == 1) {
cout << " = " << product << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << product << endl;
}
delete calcs1;
delete calcs2;
}
}
return zxPiNextMessage;
}
ParamSet
BPSolver::calculateNextLambdaMessage (Edge* edge)
{
// λY(Xi)
BayesNode* y = edge->getSource();
BayesNode* x = edge->getDestination();
if (!M(y)->receivedBottomInfluence()) {
//cout << "returning 1" << endl;
//return edge->getMessage();
}
if (x->hasEvidence()) {
//cout << "returning 2" << endl;
//return edge->getMessage();
}
ParamSet yxLambdaNextMessage (x->getDomainSize());
CEdgeSet yParentLinks = M(y)->getIncomingParentLinks();
const vector<CptEntry>& allEntries = y->getCptEntries();
int parentIndex = y->getIndexOfParent (x);
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
vector<CptEntry> entries;
DConstraint constr = make_pair (parentIndex, 0);
for (unsigned i = 0; i < allEntries.size(); i++) {
if (allEntries[i].matchConstraints(constr)) {
entries.push_back (allEntries[i]);
}
}
ParamSet messageProducts (entries.size());
for (unsigned k = 0; k < entries.size(); k++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
double messageProduct = 1.0;
const DConf& conf = entries[k].getDomainConfiguration();
for (unsigned i = 0; i < yParentLinks.size(); i++) {
assert (yParentLinks[i]->getDestination() == y);
if (yParentLinks[i]->getSource() != x) {
if (DL >= 5) {
if (messageProduct != 1.0) *calcs1 << "*" ;
if (messageProduct != 1.0) *calcs2 << "*" ;
*calcs1 << PI << "(" << yParentLinks[i]->getSource()->getLabel();
*calcs1 << "-->" << y->getLabel() << ")" ;
*calcs1 << "[" ;
*calcs1 << yParentLinks[i]->getSource()->getDomain()[conf[i]];
*calcs1 << "]" ;
*calcs2 << yParentLinks[i]->getMessage()[conf[i]];
}
messageProduct *= yParentLinks[i]->getMessage()[conf[i]];
}
}
messageProducts[k] = messageProduct;
if (DL >= 5) {
cout << " mp" << k;
cout << " = " << (*calcs1).str();
if (yParentLinks.size() == 1) {
cout << 1 << endl;
} else if (yParentLinks.size() == 2) {
cout << " = " << messageProduct << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << messageProduct << endl;
}
delete calcs1;
delete calcs2;
}
}
for (unsigned xi = 0; xi < x->getDomainSize(); xi++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
vector<CptEntry> entries;
DConstraint constr = make_pair (parentIndex, xi);
for (unsigned i = 0; i < allEntries.size(); i++) {
if (allEntries[i].matchConstraints(constr)) {
entries.push_back (allEntries[i]);
}
}
double outerSum = 0.0;
for (unsigned yi = 0; yi < y->getDomainSize(); yi++) {
if (DL >= 5) {
(yi != 0) ? *calcs1 << " + {" : *calcs1 << "{" ;
(yi != 0) ? *calcs2 << " + {" : *calcs2 << "{" ;
}
double innerSum = 0.0;
for (unsigned k = 0; k < entries.size(); k++) {
if (DL >= 5) {
if (k != 0) *calcs1 << " + " ;
if (k != 0) *calcs2 << " + " ;
*calcs1 << y->cptEntryToString (yi, entries[k]);
*calcs1 << ".mp" << k;
*calcs2 << y->getProbability (yi, entries[k]);
*calcs2 << "*" << messageProducts[k];
}
innerSum += y->getProbability (yi, entries[k]) * messageProducts[k];
}
outerSum += innerSum * M(y)->getLambdaValue (yi);
if (DL >= 5) {
*calcs1 << "}." << LD << "(" << y->getLabel() << ")" ;
*calcs1 << "[" << y->getDomain()[yi] << "]";
*calcs2 << "}*" << M(y)->getLambdaValue (yi);
}
}
yxLambdaNextMessage[xi] = outerSum;
if (DL >= 5) {
cout << " " << LD << "(" << y->getLabel();
cout << "-->" << x->getLabel() << ")" ;
cout << "[" << x->getDomain()[xi] << "]" ;
cout << " = " << (*calcs1).str();
cout << " = " << (*calcs2).str();
cout << " = " << outerSum << endl;
delete calcs1;
delete calcs2;
}
}
return yxLambdaNextMessage;
}
ParamSet
BPSolver::getJointByJunctionNode (const VidSet& jointVids) const
{
BnNodeSet jointVars;
for (unsigned i = 0; i < jointVids.size(); i++) {
jointVars.push_back (bn_->getBayesNode (jointVids[i]));
}
BayesNet* mrn = bn_->getMinimalRequesiteNetwork (jointVids);
BnNodeSet parents;
unsigned dsize = 1;
for (unsigned i = 0; i < jointVars.size(); i++) {
parents.push_back (mrn->getBayesNode (jointVids[i]));
dsize *= jointVars[i]->getDomainSize();
}
unsigned nParams = dsize * dsize;
ParamSet params (nParams);
for (unsigned i = 0; i < nParams; i++) {
unsigned row = i / dsize;
unsigned col = i % dsize;
if (row == col) {
params[i] = 1;
} else {
params[i] = 0;
}
}
unsigned maxVid = std::numeric_limits<unsigned>::max();
Distribution* dist = new Distribution (params);
mrn->addNode (maxVid, dsize, NO_EVIDENCE, parents, dist);
mrn->setIndexes();
BPSolver solver (*mrn);
solver.runSolver();
const ParamSet& results = solver.getPosterioriOf (maxVid);
delete mrn;
delete dist;
return results;
}
ParamSet
BPSolver::getJointByChainRule (const VidSet& jointVids) const
{
BnNodeSet jointVars;
for (unsigned i = 0; i < jointVids.size(); i++) {
jointVars.push_back (bn_->getBayesNode (jointVids[i]));
}
BayesNet* mrn = bn_->getMinimalRequesiteNetwork (jointVids[0]);
BPSolver solver (*mrn);
solver.runSolver();
ParamSet prevBeliefs = solver.getPosterioriOf (jointVids[0]);
delete mrn;
VarSet observedVars = {jointVars[0]};
for (unsigned i = 1; i < jointVids.size(); i++) {
mrn = bn_->getMinimalRequesiteNetwork (jointVids[i]);
ParamSet newBeliefs;
vector<DConf> confs =
Util::getDomainConfigurations (observedVars);
for (unsigned j = 0; j < confs.size(); j++) {
for (unsigned k = 0; k < observedVars.size(); k++) {
if (!observedVars[k]->hasEvidence()) {
BayesNode* node = mrn->getBayesNode (observedVars[k]->getVarId());
if (node) {
node->setEvidence (confs[j][k]);
}
}
}
BPSolver solver (*mrn);
solver.runSolver();
ParamSet beliefs = solver.getPosterioriOf (jointVids[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]->getDomainSize() == 0) {
count ++;
}
newBeliefs[j] *= prevBeliefs[count];
}
prevBeliefs = newBeliefs;
observedVars.push_back (jointVars[i]);
delete mrn;
}
return prevBeliefs;
}
void
BPSolver::printMessageStatusOf (const BayesNode* var) const
{
cout << left;
cout << setw (10) << "domain" ;
cout << setw (20) << PI << "(" + var->getLabel() + ")" ;
cout << setw (20) << LD << "(" + var->getLabel() + ")" ;
cout << setw (16) << "belief" ;
cout << endl;
cout << "--------------------------------" ;
cout << "--------------------------------" ;
cout << endl;
BPNodeInfo* x = M(var);
ParamSet& piVals = x->getPiValues();
ParamSet& ldVals = x->getLambdaValues();
ParamSet beliefs = x->getBeliefs();
const Domain& domain = var->getDomain();
CBnNodeSet& childs = var->getChilds();
for (unsigned xi = 0; xi < var->getDomainSize(); xi++) {
cout << setw (10) << domain[xi];
cout << setw (19) << piVals[xi];
cout << setw (19) << ldVals[xi];
cout.precision (PRECISION);
cout << setw (16) << beliefs[xi];
cout << endl;
}
cout << endl;
if (childs.size() > 0) {
string s = "(" + var->getLabel() + ")" ;
for (unsigned j = 0; j < childs.size(); j++) {
cout << setw (10) << "domain" ;
cout << setw (28) << PI + childs[j]->getLabel() + s;
cout << setw (28) << LD + childs[j]->getLabel() + s;
cout << endl;
cout << "--------------------------------" ;
cout << "--------------------------------" ;
cout << endl;
/* FIXME
const ParamSet& piMessage = x->getPiMessage (childs[j]);
const ParamSet& lambdaMessage = x->getLambdaMessage (childs[j]);
for (unsigned xi = 0; xi < var->getDomainSize(); xi++) {
cout << setw (10) << domain[xi];
cout.precision (PRECISION);
cout << setw (27) << piMessage[xi];
cout.precision (PRECISION);
cout << setw (27) << lambdaMessage[xi];
cout << endl;
}
cout << endl;
*/
}
}
}
void
BPSolver::printAllMessageStatus (void) const
{
CBnNodeSet nodes = bn_->getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
printMessageStatusOf (nodes[i]);
}
}

View File

@ -1,192 +0,0 @@
#ifndef BP_BP_SOLVER_H
#define BP_BP_SOLVER_H
#include <vector>
#include <set>
#include "Solver.h"
#include "BayesNet.h"
#include "BPNodeInfo.h"
#include "Shared.h"
using namespace std;
class BPNodeInfo;
static const string PI = "pi" ;
static const string LD = "ld" ;
enum MessageType {PI_MSG, LAMBDA_MSG};
enum JointCalcType {CHAIN_RULE, JUNCTION_NODE};
class Edge
{
public:
Edge (BayesNode* s, BayesNode* d, MessageType t)
{
source_ = s;
destin_ = d;
type_ = t;
if (type_ == PI_MSG) {
currMsg_.resize (s->getDomainSize(), 1);
nextMsg_.resize (s->getDomainSize(), 1);
} else {
currMsg_.resize (d->getDomainSize(), 1);
nextMsg_.resize (d->getDomainSize(), 1);
}
msgSended_ = false;
residual_ = 0.0;
}
//void setMessage (ParamSet msg)
//{
// Util::normalize (msg);
// residual_ = Util::getMaxNorm (currMsg_, msg);
// currMsg_ = msg;
//}
void setNextMessage (CParamSet msg)
{
nextMsg_ = msg;
Util::normalize (nextMsg_);
residual_ = Util::getMaxNorm (currMsg_, nextMsg_);
}
void updateMessage (void)
{
currMsg_ = nextMsg_;
if (DL >= 3) {
cout << "updating " << toString() << endl;
}
msgSended_ = true;
}
void updateResidual (void)
{
residual_ = Util::getMaxNorm (currMsg_, nextMsg_);
}
string toString (void) const
{
stringstream ss;
if (type_ == PI_MSG) {
ss << PI;
} else if (type_ == LAMBDA_MSG) {
ss << LD;
} else {
abort();
}
ss << "(" << source_->getLabel();
ss << " --> " << destin_->getLabel() << ")" ;
return ss.str();
}
BayesNode* getSource (void) const { return source_; }
BayesNode* getDestination (void) const { return destin_; }
MessageType getMessageType (void) const { return type_; }
CParamSet getMessage (void) const { return currMsg_; }
bool messageWasSended (void) const { return msgSended_; }
double getResidual (void) const { return residual_; }
void clearResidual (void) { residual_ = 0.0; }
private:
BayesNode* source_;
BayesNode* destin_;
MessageType type_;
ParamSet currMsg_;
ParamSet nextMsg_;
bool msgSended_;
double residual_;
};
class BPSolver : public Solver
{
public:
BPSolver (const BayesNet&);
~BPSolver (void);
void runSolver (void);
ParamSet getPosterioriOf (Vid) const;
ParamSet getJointDistributionOf (const VidSet&);
private:
DISALLOW_COPY_AND_ASSIGN (BPSolver);
void initializeSolver (void);
void runPolyTreeSolver (void);
void runLoopySolver (void);
void maxResidualSchedule (void);
bool converged (void) const;
void updatePiValues (BayesNode*);
void updateLambdaValues (BayesNode*);
ParamSet calculateNextLambdaMessage (Edge* edge);
ParamSet calculateNextPiMessage (Edge* edge);
ParamSet getJointByJunctionNode (const VidSet&) const;
ParamSet getJointByChainRule (const VidSet&) const;
void printMessageStatusOf (const BayesNode*) const;
void printAllMessageStatus (void) const;
ParamSet getMessage (Edge* edge)
{
if (DL >= 3) {
cout << " calculating " << edge->toString() << endl;
}
if (edge->getMessageType() == PI_MSG) {
return calculateNextPiMessage (edge);
} else if (edge->getMessageType() == LAMBDA_MSG) {
return calculateNextLambdaMessage (edge);
} else {
abort();
}
return ParamSet();
}
void updateValues (Edge* edge)
{
if (!edge->getDestination()->hasEvidence()) {
if (edge->getMessageType() == PI_MSG) {
updatePiValues (edge->getDestination());
} else if (edge->getMessageType() == LAMBDA_MSG) {
updateLambdaValues (edge->getDestination());
} else {
abort();
}
}
}
BPNodeInfo* M (const BayesNode* node) const
{
assert (node);
assert (node == bn_->getBayesNode (node->getVarId()));
assert (node->getIndex() < nodesI_.size());
return nodesI_[node->getIndex()];
}
const BayesNet* bn_;
vector<BPNodeInfo*> nodesI_;
unsigned nIter_;
vector<Edge*> links_;
bool useAlwaysLoopySolver_;
JointCalcType jointCalcType_;
struct compare
{
inline bool operator() (const Edge* e1, const Edge* e2)
{
return e1->getResidual() > e2->getResidual();
}
};
typedef multiset<Edge*, compare> SortedOrder;
SortedOrder sortedOrder_;
typedef map<Edge*, SortedOrder::iterator> EdgeMap;
EdgeMap edgeMap_;
};
#endif //BP_BP_SOLVER_H

View File

@ -4,111 +4,12 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include "xmlParser/xmlParser.h"
#include "BayesNet.h"
BayesNet::BayesNet (const char* fileName)
{
map<string, Domain> domains;
XMLNode xMainNode = XMLNode::openFileHelper (fileName, "BIF");
// only the first network is parsed, others are ignored
XMLNode xNode = xMainNode.getChildNode ("NETWORK");
unsigned nVars = xNode.nChildNode ("VARIABLE");
for (unsigned i = 0; i < nVars; i++) {
XMLNode var = xNode.getChildNode ("VARIABLE", i);
string type = var.getAttribute ("TYPE");
if (type != "nature") {
cerr << "error: only \"nature\" variables are supported" << endl;
abort();
}
Domain domain;
string varLabel = var.getChildNode("NAME").getText();
unsigned dsize = var.nChildNode ("OUTCOME");
for (unsigned j = 0; j < dsize; j++) {
if (var.getChildNode("OUTCOME", j).getText() == 0) {
stringstream ss;
ss << j + 1;
domain.push_back (ss.str());
} else {
domain.push_back (var.getChildNode("OUTCOME", j).getText());
}
}
domains.insert (make_pair (varLabel, domain));
}
unsigned nDefs = xNode.nChildNode ("DEFINITION");
if (nVars != nDefs) {
cerr << "error: different number of variables and definitions" << endl;
abort();
}
queue<unsigned> indexes;
for (unsigned i = 0; i < nDefs; i++) {
indexes.push (i);
}
while (!indexes.empty()) {
unsigned index = indexes.front();
indexes.pop();
XMLNode def = xNode.getChildNode ("DEFINITION", index);
string varLabel = def.getChildNode("FOR").getText();
map<string, Domain>::const_iterator iter;
iter = domains.find (varLabel);
if (iter == domains.end()) {
cerr << "error: unknow variable `" << varLabel << "'" << endl;
abort();
}
bool processItLatter = false;
BnNodeSet parents;
unsigned nParams = iter->second.size();
for (int j = 0; j < def.nChildNode ("GIVEN"); j++) {
string parentLabel = def.getChildNode("GIVEN", j).getText();
BayesNode* parentNode = getBayesNode (parentLabel);
if (parentNode) {
nParams *= parentNode->getDomainSize();
parents.push_back (parentNode);
}
else {
iter = domains.find (parentLabel);
if (iter == domains.end()) {
cerr << "error: unknow parent `" << parentLabel << "'" << endl;
abort();
} else {
// this definition contains a parent that doesn't
// have a corresponding bayesian node instance yet,
// so process this definition latter
indexes.push (index);
processItLatter = true;
break;
}
}
}
if (!processItLatter) {
unsigned count = 0;
ParamSet params (nParams);
stringstream s (def.getChildNode("TABLE").getText());
while (!s.eof() && count < nParams) {
s >> params[count];
count ++;
}
if (count != nParams) {
cerr << "error: invalid number of parameters " ;
cerr << "for variable `" << varLabel << "'" << endl;
abort();
}
params = reorderParameters (params, iter->second.size());
addNode (varLabel, iter->second, parents, params);
}
}
setIndexes();
}
BayesNet::~BayesNet (void)
{
@ -119,26 +20,130 @@ BayesNet::~BayesNet (void)
BayesNode*
BayesNet::addNode (Vid vid)
void
BayesNet::readFromBifFormat (const char* fileName)
{
indexMap_.insert (make_pair (vid, nodes_.size()));
nodes_.push_back (new BayesNode (vid));
return nodes_.back();
XMLNode xMainNode = XMLNode::openFileHelper (fileName, "BIF");
// only the first network is parsed, others are ignored
XMLNode xNode = xMainNode.getChildNode ("NETWORK");
unsigned nVars = xNode.nChildNode ("VARIABLE");
for (unsigned i = 0; i < nVars; i++) {
XMLNode var = xNode.getChildNode ("VARIABLE", i);
if (string (var.getAttribute ("TYPE")) != "nature") {
cerr << "error: only \"nature\" variables are supported" << endl;
abort();
}
States states;
string label = var.getChildNode("NAME").getText();
unsigned nrStates = var.nChildNode ("OUTCOME");
for (unsigned j = 0; j < nrStates; j++) {
if (var.getChildNode("OUTCOME", j).getText() == 0) {
stringstream ss;
ss << j + 1;
states.push_back (ss.str());
} else {
states.push_back (var.getChildNode("OUTCOME", j).getText());
}
}
addNode (label, states);
}
unsigned nDefs = xNode.nChildNode ("DEFINITION");
if (nVars != nDefs) {
cerr << "error: different number of variables and definitions" << endl;
abort();
}
for (unsigned i = 0; i < nDefs; i++) {
XMLNode def = xNode.getChildNode ("DEFINITION", i);
string label = def.getChildNode("FOR").getText();
BayesNode* node = getBayesNode (label);
if (!node) {
cerr << "error: unknow variable `" << label << "'" << endl;
abort();
}
BnNodeSet parents;
unsigned nParams = node->nrStates();
for (int j = 0; j < def.nChildNode ("GIVEN"); j++) {
string parentLabel = def.getChildNode("GIVEN", j).getText();
BayesNode* parentNode = getBayesNode (parentLabel);
if (!parentNode) {
cerr << "error: unknow variable `" << parentLabel << "'" << endl;
abort();
}
nParams *= parentNode->nrStates();
parents.push_back (parentNode);
}
node->setParents (parents);
unsigned count = 0;
ParamSet params (nParams);
stringstream s (def.getChildNode("TABLE").getText());
while (!s.eof() && count < nParams) {
s >> params[count];
count ++;
}
if (count != nParams) {
cerr << "error: invalid number of parameters " ;
cerr << "for variable `" << label << "'" << endl;
abort();
}
params = reorderParameters (params, node->nrStates());
Distribution* dist = new Distribution (params);
node->setDistribution (dist);
addDistribution (dist);
}
setIndexes();
if (NSPACE == NumberSpace::LOGARITHM) {
distributionsToLogs();
}
}
void
BayesNet::addNode (BayesNode* n)
{
indexMap_.insert (make_pair (n->varId(), nodes_.size()));
nodes_.push_back (n);
}
BayesNode*
BayesNet::addNode (Vid vid,
BayesNet::addNode (string label, const States& states)
{
VarId vid = nodes_.size();
indexMap_.insert (make_pair (vid, nodes_.size()));
GraphicalModel::addVariableInformation (vid, label, states);
BayesNode* node = new BayesNode (VarNode (vid, states.size()));
nodes_.push_back (node);
return node;
}
BayesNode*
BayesNet::addNode (VarId vid,
unsigned dsize,
int evidence,
BnNodeSet& parents,
Distribution* dist)
{
indexMap_.insert (make_pair (vid, nodes_.size()));
nodes_.push_back (new BayesNode (
vid, dsize, evidence, parents, dist));
nodes_.push_back (new BayesNode (vid, dsize, evidence, parents, dist));
return nodes_.back();
}
BayesNode*
BayesNet::addNode (VarId vid,
unsigned dsize,
int evidence,
Distribution* dist)
{
indexMap_.insert (make_pair (vid, nodes_.size()));
nodes_.push_back (new BayesNode (vid, dsize, evidence, dist));
return nodes_.back();
}
@ -146,14 +151,16 @@ BayesNet::addNode (Vid vid,
BayesNode*
BayesNet::addNode (string label,
Domain domain,
States states,
BnNodeSet& parents,
ParamSet& params)
{
indexMap_.insert (make_pair (nodes_.size(), nodes_.size()));
VarId vid = nodes_.size();
indexMap_.insert (make_pair (vid, nodes_.size()));
GraphicalModel::addVariableInformation (vid, label, states);
Distribution* dist = new Distribution (params);
BayesNode* node = new BayesNode (
nodes_.size(), label, domain, parents, dist);
vid, states.size(), NO_EVIDENCE, parents, dist);
dists_.push_back (dist);
nodes_.push_back (node);
return node;
@ -162,7 +169,7 @@ BayesNet::addNode (string label,
BayesNode*
BayesNet::getBayesNode (Vid vid) const
BayesNet::getBayesNode (VarId vid) const
{
IndexMap::const_iterator it = indexMap_.find (vid);
if (it == indexMap_.end()) {
@ -179,7 +186,7 @@ BayesNet::getBayesNode (string label) const
{
BayesNode* node = 0;
for (unsigned i = 0; i < nodes_.size(); i++) {
if (nodes_[i]->getLabel() == label) {
if (nodes_[i]->label() == label) {
node = nodes_[i];
break;
}
@ -190,10 +197,25 @@ BayesNet::getBayesNode (string label) const
Variable*
BayesNet::getVariable (Vid vid) const
VarNode*
BayesNet::getVariableNode (VarId vid) const
{
return getBayesNode (vid);
BayesNode* node = getBayesNode (vid);
assert (node);
return node;
}
VarNodes
BayesNet::getVariableNodes (void) const
{
VarNodes vars;
for (unsigned i = 0; i < nodes_.size(); i++) {
vars.push_back (nodes_[i]);
}
return vars;
}
@ -230,7 +252,7 @@ BayesNet::getBayesNodes (void) const
unsigned
BayesNet::getNumberOfNodes (void) const
BayesNet::nrNodes (void) const
{
return nodes_.size();
}
@ -265,37 +287,25 @@ BayesNet::getLeafNodes (void) const
VarSet
BayesNet::getVariables (void) const
BayesNet*
BayesNet::getMinimalRequesiteNetwork (VarId vid) const
{
VarSet vars;
for (unsigned i = 0; i < nodes_.size(); i++) {
vars.push_back (nodes_[i]);
}
return vars;
return getMinimalRequesiteNetwork (VarIdSet() = {vid});
}
BayesNet*
BayesNet::getMinimalRequesiteNetwork (Vid vid) const
{
return getMinimalRequesiteNetwork (VidSet() = {vid});
}
BayesNet*
BayesNet::getMinimalRequesiteNetwork (const VidSet& queryVids) const
BayesNet::getMinimalRequesiteNetwork (const VarIdSet& queryVarIds) const
{
BnNodeSet queryVars;
for (unsigned i = 0; i < queryVids.size(); i++) {
assert (getBayesNode (queryVids[i]));
queryVars.push_back (getBayesNode (queryVids[i]));
for (unsigned i = 0; i < queryVarIds.size(); i++) {
assert (getBayesNode (queryVarIds[i]));
queryVars.push_back (getBayesNode (queryVarIds[i]));
}
// cout << "query vars: " ;
// for (unsigned i = 0; i < queryVars.size(); i++) {
// cout << queryVars[i]->getLabel() << " " ;
// cout << queryVars[i]->label() << " " ;
// }
// cout << endl;
@ -344,7 +354,7 @@ BayesNet::getMinimalRequesiteNetwork (const VidSet& queryVids) const
cout << "----------------------------------------------------------" ;
cout << endl;
for (unsigned i = 0; i < states.size(); i++) {
cout << nodes_[i]->getLabel() << ":\t\t" ;
cout << nodes_[i]->label() << ":\t\t" ;
if (states[i]) {
states[i]->markedOnTop ? cout << "yes\t" : cout << "no\t" ;
states[i]->markedOnBottom ? cout << "yes\t" : cout << "no\t" ;
@ -374,51 +384,46 @@ void
BayesNet::constructGraph (BayesNet* bn,
const vector<StateInfo*>& states) const
{
BnNodeSet mrnNodes;
vector<VarIdSet> parents;
for (unsigned i = 0; i < nodes_.size(); i++) {
bool isRequired = false;
if (states[i]) {
isRequired = (nodes_[i]->hasEvidence() && states[i]->visited)
||
||
states[i]->markedOnTop;
}
if (isRequired) {
BnNodeSet parents;
parents.push_back (VarIdSet());
if (states[i]->markedOnTop) {
const BnNodeSet& ps = nodes_[i]->getParents();
for (unsigned j = 0; j < ps.size(); j++) {
BayesNode* parent = bn->getBayesNode (ps[j]->getVarId());
if (!parent) {
parent = bn->addNode (ps[j]->getVarId());
}
parents.push_back (parent);
parents.back().push_back (ps[j]->varId());
}
}
BayesNode* node = bn->getBayesNode (nodes_[i]->getVarId());
if (node) {
node->setData (nodes_[i]->getDomainSize(),
nodes_[i]->getEvidence(), parents,
nodes_[i]->getDistribution());
} else {
node = bn->addNode (nodes_[i]->getVarId(),
nodes_[i]->getDomainSize(),
nodes_[i]->getEvidence(), parents,
nodes_[i]->getDistribution());
}
if (nodes_[i]->hasDomain()) {
node->setDomain (nodes_[i]->getDomain());
}
if (nodes_[i]->hasLabel()) {
node->setLabel (nodes_[i]->getLabel());
}
assert (bn->getBayesNode (nodes_[i]->varId()) == 0);
BayesNode* mrnNode = bn->addNode (nodes_[i]->varId(),
nodes_[i]->nrStates(),
nodes_[i]->getEvidence(),
nodes_[i]->getDistribution());
mrnNodes.push_back (mrnNode);
}
}
for (unsigned i = 0; i < mrnNodes.size(); i++) {
BnNodeSet ps;
for (unsigned j = 0; j < parents[i].size(); j++) {
assert (bn->getBayesNode (parents[i][j]) != 0);
ps.push_back (bn->getBayesNode (parents[i][j]));
}
mrnNodes[i]->setParents (ps);
}
bn->setIndexes();
}
bool
BayesNet::isSingleConnected (void) const
BayesNet::isPolyTree (void) const
{
return !containsUndirectedCycle();
}
@ -435,6 +440,16 @@ BayesNet::setIndexes (void)
void
BayesNet::distributionsToLogs (void)
{
for (unsigned i = 0; i < dists_.size(); i++) {
Util::toLog (dists_[i]->params);
}
}
void
BayesNet::freeDistributions (void)
{
@ -456,9 +471,9 @@ BayesNet::printGraphicalModel (void) const
void
BayesNet::exportToDotFormat (const char* fileName,
bool showNeighborless,
CVidSet& highlightVids) const
BayesNet::exportToGraphViz (const char* fileName,
bool showNeighborless,
const VarIdSet& highlightVarIds) const
{
ofstream out (fileName);
if (!out.is_open()) {
@ -467,27 +482,32 @@ BayesNet::exportToDotFormat (const char* fileName,
abort();
}
out << "digraph \"" << fileName << "\" {" << endl;
out << "digraph {" << endl;
out << "ranksep=1" << endl;
for (unsigned i = 0; i < nodes_.size(); i++) {
if (showNeighborless || nodes_[i]->hasNeighbors()) {
out << '"' << nodes_[i]->getLabel() << '"' ;
out << nodes_[i]->varId() ;
if (nodes_[i]->hasEvidence()) {
out << " [style=filled, fillcolor=yellow]" << endl;
out << " [" ;
out << "label=\"" << nodes_[i]->label() << "\"," ;
out << "style=filled, fillcolor=yellow" ;
out << "]" ;
} else {
out << endl;
out << " [" ;
out << "label=\"" << nodes_[i]->label() << "\"" ;
out << "]" ;
}
out << endl;
}
}
for (unsigned i = 0; i < highlightVids.size(); i++) {
BayesNode* node = getBayesNode (highlightVids[i]);
for (unsigned i = 0; i < highlightVarIds.size(); i++) {
BayesNode* node = getBayesNode (highlightVarIds[i]);
if (node) {
out << '"' << node->getLabel() << '"' ;
// out << " [shape=polygon, sides=6]" << endl;
out << node->varId() ;
out << " [shape=box3d]" << endl;
} else {
cout << "error: invalid variable id: " << highlightVids[i] << endl;
cout << "error: invalid variable id: " << highlightVarIds[i] << endl;
abort();
}
}
@ -495,8 +515,7 @@ BayesNet::exportToDotFormat (const char* fileName,
for (unsigned i = 0; i < nodes_.size(); i++) {
const BnNodeSet& childs = nodes_[i]->getChilds();
for (unsigned j = 0; j < childs.size(); j++) {
out << '"' << nodes_[i]->getLabel() << '"' << " -> " ;
out << '"' << childs[j]->getLabel() << '"' << endl;
out << nodes_[i]->varId() << " -> " << childs[j]->varId() << " [style=bold]" << endl ;
}
}
@ -521,24 +540,24 @@ BayesNet::exportToBifFormat (const char* fileName) const
out << "<NAME>" << fileName << "</NAME>" << endl << endl;
for (unsigned i = 0; i < nodes_.size(); i++) {
out << "<VARIABLE TYPE=\"nature\">" << endl;
out << "\t<NAME>" << nodes_[i]->getLabel() << "</NAME>" << endl;
const Domain& domain = nodes_[i]->getDomain();
for (unsigned j = 0; j < domain.size(); j++) {
out << "\t<OUTCOME>" << domain[j] << "</OUTCOME>" << endl;
out << "\t<NAME>" << nodes_[i]->label() << "</NAME>" << endl;
const States& states = nodes_[i]->states();
for (unsigned j = 0; j < states.size(); j++) {
out << "\t<OUTCOME>" << states[j] << "</OUTCOME>" << endl;
}
out << "</VARIABLE>" << endl << endl;
}
for (unsigned i = 0; i < nodes_.size(); i++) {
out << "<DEFINITION>" << endl;
out << "\t<FOR>" << nodes_[i]->getLabel() << "</FOR>" << endl;
out << "\t<FOR>" << nodes_[i]->label() << "</FOR>" << endl;
const BnNodeSet& parents = nodes_[i]->getParents();
for (unsigned j = 0; j < parents.size(); j++) {
out << "\t<GIVEN>" << parents[j]->getLabel();
out << "\t<GIVEN>" << parents[j]->label();
out << "</GIVEN>" << endl;
}
ParamSet params = revertParameterReorder (nodes_[i]->getParameters(),
nodes_[i]->getDomainSize());
nodes_[i]->nrStates());
out << "\t<TABLE>" ;
for (unsigned j = 0; j < params.size(); j++) {
out << " " << params[j];
@ -571,9 +590,7 @@ BayesNet::containsUndirectedCycle (void) const
bool
BayesNet::containsUndirectedCycle (int v,
int p,
vector<bool>& visited) const
BayesNet::containsUndirectedCycle (int v, int p, vector<bool>& visited) const
{
visited[v] = true;
vector<int> adjacencies = getAdjacentNodes (v);
@ -611,8 +628,7 @@ BayesNet::getAdjacentNodes (int v) const
ParamSet
BayesNet::reorderParameters (CParamSet params,
unsigned domainSize) const
BayesNet::reorderParameters (const ParamSet& params, unsigned dsize) const
{
// the interchange format for bayesian networks keeps the probabilities
// in the following order:
@ -623,13 +639,13 @@ BayesNet::reorderParameters (CParamSet params,
// p(a1|b1,c1) p(a1|b1,c2) p(a1|b2,c1) p(a1|b2,c2) p(a2|b1,c1) p(a2|b1,c2)
// p(a2|b2,c1) p(a2|b2,c2).
unsigned count = 0;
unsigned rowSize = params.size() / domainSize;
unsigned rowSize = params.size() / dsize;
ParamSet reordered;
while (reordered.size() < params.size()) {
unsigned idx = count;
for (unsigned i = 0; i < rowSize; i++) {
reordered.push_back (params[idx]);
idx += domainSize;
idx += dsize ;
}
count++;
}
@ -639,15 +655,14 @@ BayesNet::reorderParameters (CParamSet params,
ParamSet
BayesNet::revertParameterReorder (CParamSet params,
unsigned domainSize) const
BayesNet::revertParameterReorder (const ParamSet& params, unsigned dsize) const
{
unsigned count = 0;
unsigned rowSize = params.size() / domainSize;
unsigned rowSize = params.size() / dsize;
ParamSet reordered;
while (reordered.size() < params.size()) {
unsigned idx = count;
for (unsigned i = 0; i < domainSize; i++) {
for (unsigned i = 0; i < dsize; i++) {
reordered.push_back (params[idx]);
idx += rowSize;
}

View File

@ -1,5 +1,5 @@
#ifndef BP_BAYES_NET_H
#define BP_BAYES_NET_H
#ifndef HORUS_BAYESNET_H
#define HORUS_BAYESNET_H
#include <vector>
#include <queue>
@ -44,61 +44,59 @@ struct StateInfo
typedef vector<Distribution*> DistSet;
typedef queue<ScheduleInfo, list<ScheduleInfo> > Scheduling;
typedef map<unsigned, unsigned> Histogram;
typedef map<unsigned, double> Times;
class BayesNet : public GraphicalModel
{
public:
BayesNet (void) {};
BayesNet (const char*);
~BayesNet (void);
BayesNode* addNode (unsigned);
BayesNode* addNode (unsigned, unsigned, int, BnNodeSet&,
Distribution*);
BayesNode* addNode (string, Domain, BnNodeSet&, ParamSet&);
BayesNode* getBayesNode (Vid) const;
BayesNode* getBayesNode (string) const;
Variable* getVariable (Vid) const;
void addDistribution (Distribution*);
Distribution* getDistribution (unsigned) const;
const BnNodeSet& getBayesNodes (void) const;
unsigned getNumberOfNodes (void) const;
BnNodeSet getRootNodes (void) const;
BnNodeSet getLeafNodes (void) const;
VarSet getVariables (void) const;
BayesNet* getMinimalRequesiteNetwork (Vid) const;
BayesNet* getMinimalRequesiteNetwork (const VidSet&) const;
void constructGraph (BayesNet*,
const vector<StateInfo*>&) const;
bool isSingleConnected (void) const;
void setIndexes (void);
void freeDistributions (void);
void printGraphicalModel (void) const;
void exportToDotFormat (const char*, bool = true,
CVidSet = VidSet()) const;
void exportToBifFormat (const char*) const;
static Histogram histogram_;
static Times times_;
void readFromBifFormat (const char*);
void addNode (BayesNode*);
BayesNode* addNode (string, const States&);
BayesNode* addNode (VarId, unsigned, int, BnNodeSet&, Distribution*);
BayesNode* addNode (VarId, unsigned, int, Distribution*);
BayesNode* addNode (string, States, BnNodeSet&, ParamSet&);
BayesNode* getBayesNode (VarId) const;
BayesNode* getBayesNode (string) const;
VarNode* getVariableNode (VarId) const;
VarNodes getVariableNodes (void) const;
void addDistribution (Distribution*);
Distribution* getDistribution (unsigned) const;
const BnNodeSet& getBayesNodes (void) const;
unsigned nrNodes (void) const;
BnNodeSet getRootNodes (void) const;
BnNodeSet getLeafNodes (void) const;
BayesNet* getMinimalRequesiteNetwork (VarId) const;
BayesNet* getMinimalRequesiteNetwork (const VarIdSet&) const;
void constructGraph (
BayesNet*, const vector<StateInfo*>&) const;
bool isPolyTree (void) const;
void setIndexes (void);
void distributionsToLogs (void);
void freeDistributions (void);
void printGraphicalModel (void) const;
void exportToGraphViz (const char*, bool = true,
const VarIdSet& = VarIdSet()) const;
void exportToBifFormat (const char*) const;
private:
DISALLOW_COPY_AND_ASSIGN (BayesNet);
bool containsUndirectedCycle (void) const;
bool containsUndirectedCycle (int, int,
vector<bool>&)const;
vector<int> getAdjacentNodes (int) const ;
ParamSet reorderParameters (CParamSet, unsigned) const;
ParamSet revertParameterReorder (CParamSet, unsigned) const;
void scheduleParents (const BayesNode*, Scheduling&) const;
void scheduleChilds (const BayesNode*, Scheduling&) const;
bool containsUndirectedCycle (void) const;
bool containsUndirectedCycle (int, int, vector<bool>&)const;
vector<int> getAdjacentNodes (int) const;
ParamSet reorderParameters (const ParamSet&, unsigned) const;
ParamSet revertParameterReorder (const ParamSet&, unsigned) const;
void scheduleParents (const BayesNode*, Scheduling&) const;
void scheduleChilds (const BayesNode*, Scheduling&) const;
BnNodeSet nodes_;
DistSet dists_;
IndexMap indexMap_;
BnNodeSet nodes_;
DistSet dists_;
typedef unordered_map<unsigned, unsigned> IndexMap;
IndexMap indexMap_;
};
@ -123,5 +121,5 @@ BayesNet::scheduleChilds (const BayesNode* n, Scheduling& sch) const
}
}
#endif //BP_BAYES_NET_H
#endif // HORUS_BAYESNET_H

View File

@ -1,34 +1,30 @@
#include <cstdlib>
#include <cassert>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "BayesNode.h"
BayesNode::BayesNode (Vid vid,
BayesNode::BayesNode (VarId vid,
unsigned dsize,
int evidence,
const BnNodeSet& parents,
Distribution* dist) : Variable (vid, dsize, evidence)
Distribution* dist)
: VarNode (vid, dsize, evidence)
{
parents_ = parents;
dist_ = dist;
for (unsigned int i = 0; i < parents.size(); i++) {
parents[i]->addChild (this);
}
dist_ = dist;
}
BayesNode::BayesNode (Vid vid,
string label,
const Domain& domain,
BayesNode::BayesNode (VarId vid,
unsigned dsize,
int evidence,
const BnNodeSet& parents,
Distribution* dist) : Variable (vid, domain,
NO_EVIDENCE, label)
Distribution* dist)
: VarNode (vid, dsize, evidence)
{
parents_ = parents;
dist_ = dist;
@ -40,18 +36,12 @@ BayesNode::BayesNode (Vid vid,
void
BayesNode::setData (unsigned dsize,
int evidence,
const BnNodeSet& parents,
Distribution* dist)
BayesNode::setParents (const BnNodeSet& parents)
{
setDomainSize (dsize);
setEvidence (evidence);
parents_ = parents;
dist_ = dist;
parents_ = parents;
for (unsigned int i = 0; i < parents.size(); i++) {
parents[i]->addChild (this);
}
}
}
@ -64,6 +54,15 @@ BayesNode::addChild (BayesNode* node)
void
BayesNode::setDistribution (Distribution* dist)
{
assert (dist);
dist_ = dist;
}
Distribution*
BayesNode::getDistribution (void)
{
@ -140,14 +139,14 @@ BayesNode::getCptEntries (void)
for (int i = parents_.size() - 1; i >= 0; i--) {
unsigned index = 0;
while (index < rowSize) {
for (unsigned j = 0; j < parents_[i]->getDomainSize(); j++) {
for (unsigned j = 0; j < parents_[i]->nrStates(); j++) {
for (unsigned r = 0; r < nReps; r++) {
confs[index][i] = j;
index++;
}
}
}
nReps *= parents_[i]->getDomainSize();
nReps *= parents_[i]->nrStates();
}
dist_->entries.reserve (rowSize);
@ -180,14 +179,14 @@ BayesNode::cptEntryToString (const CptEntry& entry) const
ss << "p(" ;
const DConf& conf = entry.getDomainConfiguration();
int row = entry.getParameterIndex() / getRowSize();
ss << getDomain()[row];
ss << states()[row];
if (parents_.size() > 0) {
ss << "|" ;
for (unsigned int i = 0; i < conf.size(); i++) {
if (i != 0) {
ss << ",";
}
ss << parents_[i]->getDomain()[conf[i]];
ss << parents_[i]->states()[conf[i]];
}
}
ss << ")" ;
@ -202,14 +201,14 @@ BayesNode::cptEntryToString (int row, const CptEntry& entry) const
stringstream ss;
ss << "p(" ;
const DConf& conf = entry.getDomainConfiguration();
ss << getDomain()[row];
ss << states()[row];
if (parents_.size() > 0) {
ss << "|" ;
for (unsigned int i = 0; i < conf.size(); i++) {
if (i != 0) {
ss << ",";
}
ss << parents_[i]->getDomain()[conf[i]];
ss << parents_[i]->states()[conf[i]];
}
}
ss << ")" ;
@ -226,21 +225,21 @@ BayesNode::getDomainHeaders (void) const
unsigned nReps = 1;
vector<string> headers (rowSize);
for (int i = nParents - 1; i >= 0; i--) {
Domain domain = parents_[i]->getDomain();
States states = parents_[i]->states();
unsigned index = 0;
while (index < rowSize) {
for (unsigned j = 0; j < parents_[i]->getDomainSize(); j++) {
for (unsigned j = 0; j < parents_[i]->nrStates(); j++) {
for (unsigned r = 0; r < nReps; r++) {
if (headers[index] != "") {
headers[index] = domain[j] + "," + headers[index];
headers[index] = states[j] + "," + headers[index];
} else {
headers[index] = domain[j];
headers[index] = states[j];
}
index++;
}
}
}
nReps *= parents_[i]->getDomainSize();
nReps *= parents_[i]->nrStates();
}
return headers;
}
@ -251,8 +250,8 @@ ostream&
operator << (ostream& o, const BayesNode& node)
{
o << "variable " << node.getIndex() << endl;
o << "Var Id: " << node.getVarId() << endl;
o << "Label: " << node.getLabel() << endl;
o << "Var Id: " << node.varId() << endl;
o << "Label: " << node.label() << endl;
o << "Evidence: " ;
if (node.hasEvidence()) {
@ -267,9 +266,9 @@ operator << (ostream& o, const BayesNode& node)
const BnNodeSet& parents = node.getParents();
if (parents.size() != 0) {
for (unsigned int i = 0; i < parents.size() - 1; i++) {
o << parents[i]->getLabel() << ", " ;
o << parents[i]->label() << ", " ;
}
o << parents[parents.size() - 1]->getLabel();
o << parents[parents.size() - 1]->label();
}
o << endl;
@ -277,19 +276,19 @@ operator << (ostream& o, const BayesNode& node)
const BnNodeSet& childs = node.getChilds();
if (childs.size() != 0) {
for (unsigned int i = 0; i < childs.size() - 1; i++) {
o << childs[i]->getLabel() << ", " ;
o << childs[i]->label() << ", " ;
}
o << childs[childs.size() - 1]->getLabel();
o << childs[childs.size() - 1]->label();
}
o << endl;
o << "Domain: " ;
Domain domain = node.getDomain();
for (unsigned int i = 0; i < domain.size() - 1; i++) {
o << domain[i] << ", " ;
States states = node.states();
for (unsigned int i = 0; i < states.size() - 1; i++) {
o << states[i] << ", " ;
}
if (domain.size() != 0) {
o << domain[domain.size() - 1];
if (states.size() != 0) {
o << states[states.size() - 1];
}
o << endl;
@ -298,10 +297,10 @@ operator << (ostream& o, const BayesNode& node)
// min width of following columns
const unsigned int MIN_COMBO_WIDTH = 12;
unsigned int domainWidth = domain[0].length();
for (unsigned int i = 1; i < domain.size(); i++) {
if (domain[i].length() > domainWidth) {
domainWidth = domain[i].length();
unsigned int domainWidth = states[0].length();
for (unsigned int i = 1; i < states.size(); i++) {
if (states[i].length() > domainWidth) {
domainWidth = states[i].length();
}
}
domainWidth = (domainWidth < MIN_DOMAIN_WIDTH)
@ -334,9 +333,9 @@ operator << (ostream& o, const BayesNode& node)
}
o << endl;
for (unsigned int i = 0; i < domain.size(); i++) {
for (unsigned int i = 0; i < states.size(); i++) {
ParamSet row = node.getRow (i);
o << left << setw (domainWidth) << domain[i] << right;
o << left << setw (domainWidth) << states[i] << right;
for (unsigned j = 0; j < node.getRowSize(); j++) {
o << setw (widths[j]) << row[j];
}

View File

@ -1,9 +1,9 @@
#ifndef BP_BAYES_NODE_H
#define BP_BAYES_NODE_H
#ifndef HORUS_BAYESNODE_H
#define HORUS_BAYESNODE_H
#include <vector>
#include "Variable.h"
#include "VarNode.h"
#include "CptEntry.h"
#include "Distribution.h"
#include "Shared.h"
@ -11,16 +11,16 @@
using namespace std;
class BayesNode : public Variable
class BayesNode : public VarNode
{
public:
BayesNode (Vid vid) : Variable (vid) {}
BayesNode (Vid, unsigned, int, const BnNodeSet&, Distribution*);
BayesNode (Vid, string, const Domain&, const BnNodeSet&, Distribution*);
BayesNode (const VarNode& v) : VarNode (v) {}
BayesNode (VarId, unsigned, int, Distribution*);
BayesNode (VarId, unsigned, int, const BnNodeSet&, Distribution*);
void setData (unsigned, int, const BnNodeSet&,
Distribution*);
void setParents (const BnNodeSet&);
void addChild (BayesNode*);
void setDistribution (Distribution*);
Distribution* getDistribution (void);
const ParamSet& getParameters (void);
ParamSet getRow (int) const;
@ -34,12 +34,12 @@ class BayesNode : public Variable
string cptEntryToString (const CptEntry&) const;
string cptEntryToString (int, const CptEntry&) const;
const BnNodeSet& getParents (void) const { return parents_; }
const BnNodeSet& getChilds (void) const { return childs_; }
const BnNodeSet& getParents (void) const { return parents_; }
const BnNodeSet& getChilds (void) const { return childs_; }
unsigned getRowSize (void) const
{
return dist_->params.size() / getDomainSize();
return dist_->params.size() / nrStates();
}
double getProbability (int row, const CptEntry& entry)
@ -52,7 +52,7 @@ class BayesNode : public Variable
private:
DISALLOW_COPY_AND_ASSIGN (BayesNode);
Domain getDomainHeaders (void) const;
States getDomainHeaders (void) const;
friend ostream& operator << (ostream&, const BayesNode&);
BnNodeSet parents_;
@ -62,5 +62,5 @@ class BayesNode : public Variable
ostream& operator << (ostream&, const BayesNode&);
#endif //BP_BAYES_NODE_H
#endif // HORUS_BAYESNODE_H

View File

@ -0,0 +1,962 @@
#include <cstdlib>
#include <limits>
#include <time.h>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "BnBpSolver.h"
BnBpSolver::BnBpSolver (const BayesNet& bn) : Solver (&bn)
{
bayesNet_ = &bn;
jointCalcType_ = CHAIN_RULE;
//jointCalcType_ = JUNCTION_NODE;
}
BnBpSolver::~BnBpSolver (void)
{
for (unsigned i = 0; i < nodesI_.size(); i++) {
delete nodesI_[i];
}
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
}
void
BnBpSolver::runSolver (void)
{
clock_t start;
if (COLLECT_STATISTICS) {
start = clock();
}
initializeSolver();
if (!BpOptions::useAlwaysLoopySolver && bayesNet_->isPolyTree()) {
runPolyTreeSolver();
} else {
runLoopySolver();
if (DL >= 2) {
cout << endl;
if (nIters_ < BpOptions::maxIter) {
cout << "Belief propagation converged in " ;
cout << nIters_ << " iterations" << endl;
} else {
cout << "The maximum number of iterations was hit, terminating..." ;
cout << endl;
}
}
}
unsigned size = bayesNet_->nrNodes();
if (COLLECT_STATISTICS) {
unsigned nIters = 0;
bool loopy = bayesNet_->isPolyTree() == false;
if (loopy) nIters = nIters_;
double time = (double (clock() - start)) / CLOCKS_PER_SEC;
Statistics::updateStatistics (size, loopy, nIters, time);
}
if (EXPORT_TO_GRAPHVIZ && size > EXPORT_MINIMAL_SIZE) {
stringstream ss;
ss << Statistics::getSolvedNetworksCounting() << "." << size << ".dot" ;
bayesNet_->exportToGraphViz (ss.str().c_str());
}
}
ParamSet
BnBpSolver::getPosterioriOf (VarId vid)
{
BayesNode* node = bayesNet_->getBayesNode (vid);
assert (node);
return nodesI_[node->getIndex()]->getBeliefs();
}
ParamSet
BnBpSolver::getJointDistributionOf (const VarIdSet& jointVarIds)
{
if (DL >= 2) {
cout << "calculating joint distribution on: " ;
for (unsigned i = 0; i < jointVarIds.size(); i++) {
VarNode* var = bayesNet_->getBayesNode (jointVarIds[i]);
cout << var->label() << " " ;
}
cout << endl;
}
if (jointCalcType_ == JUNCTION_NODE) {
return getJointByJunctionNode (jointVarIds);
} else {
return getJointByChainRule (jointVarIds);
}
}
void
BnBpSolver::initializeSolver (void)
{
const BnNodeSet& nodes = bayesNet_->getBayesNodes();
for (unsigned i = 0; i < nodesI_.size(); i++) {
delete nodesI_[i];
}
nodesI_.clear();
nodesI_.reserve (nodes.size());
links_.clear();
sortedOrder_.clear();
linkMap_.clear();
for (unsigned i = 0; i < nodes.size(); i++) {
nodesI_.push_back (new BpNodeInfo (nodes[i]));
}
BnNodeSet roots = bayesNet_->getRootNodes();
for (unsigned i = 0; i < roots.size(); i++) {
const ParamSet& params = roots[i]->getParameters();
ParamSet& piVals = ninf(roots[i])->getPiValues();
for (unsigned ri = 0; ri < roots[i]->nrStates(); ri++) {
piVals[ri] = params[ri];
}
}
for (unsigned i = 0; i < nodes.size(); i++) {
const BnNodeSet& parents = nodes[i]->getParents();
for (unsigned j = 0; j < parents.size(); j++) {
BpLink* newLink = new BpLink (
parents[j], nodes[i], LinkOrientation::DOWN);
links_.push_back (newLink);
ninf(nodes[i])->addIncomingParentLink (newLink);
ninf(parents[j])->addOutcomingChildLink (newLink);
}
const BnNodeSet& childs = nodes[i]->getChilds();
for (unsigned j = 0; j < childs.size(); j++) {
BpLink* newLink = new BpLink (
childs[j], nodes[i], LinkOrientation::UP);
links_.push_back (newLink);
ninf(nodes[i])->addIncomingChildLink (newLink);
ninf(childs[j])->addOutcomingParentLink (newLink);
}
}
for (unsigned i = 0; i < nodes.size(); i++) {
if (nodes[i]->hasEvidence()) {
ParamSet& piVals = ninf(nodes[i])->getPiValues();
ParamSet& ldVals = ninf(nodes[i])->getLambdaValues();
for (unsigned xi = 0; xi < nodes[i]->nrStates(); xi++) {
piVals[xi] = Util::noEvidence();
ldVals[xi] = Util::noEvidence();
}
piVals[nodes[i]->getEvidence()] = Util::withEvidence();
ldVals[nodes[i]->getEvidence()] = Util::withEvidence();
}
}
}
void
BnBpSolver::runPolyTreeSolver (void)
{
const BnNodeSet& nodes = bayesNet_->getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
if (nodes[i]->isRoot()) {
ninf(nodes[i])->markPiValuesAsCalculated();
}
if (nodes[i]->isLeaf()) {
ninf(nodes[i])->markLambdaValuesAsCalculated();
}
}
bool finish = false;
while (!finish) {
finish = true;
for (unsigned i = 0; i < nodes.size(); i++) {
if (ninf(nodes[i])->piValuesCalculated() == false
&& ninf(nodes[i])->receivedAllPiMessages()) {
if (!nodes[i]->hasEvidence()) {
updatePiValues (nodes[i]);
}
ninf(nodes[i])->markPiValuesAsCalculated();
finish = false;
}
if (ninf(nodes[i])->lambdaValuesCalculated() == false
&& ninf(nodes[i])->receivedAllLambdaMessages()) {
if (!nodes[i]->hasEvidence()) {
updateLambdaValues (nodes[i]);
}
ninf(nodes[i])->markLambdaValuesAsCalculated();
finish = false;
}
if (ninf(nodes[i])->piValuesCalculated()) {
const BpLinkSet& outChildLinks
= ninf(nodes[i])->getOutcomingChildLinks();
for (unsigned j = 0; j < outChildLinks.size(); j++) {
BayesNode* child = outChildLinks[j]->getDestination();
if (!outChildLinks[j]->messageWasSended()) {
if (ninf(nodes[i])->readyToSendPiMsgTo (child)) {
calculateAndUpdateMessage (outChildLinks[j], false);
ninf(child)->incNumPiMsgsReceived();
}
finish = false;
}
}
}
if (ninf(nodes[i])->lambdaValuesCalculated()) {
const BpLinkSet& outParentLinks =
ninf(nodes[i])->getOutcomingParentLinks();
for (unsigned j = 0; j < outParentLinks.size(); j++) {
BayesNode* parent = outParentLinks[j]->getDestination();
if (!outParentLinks[j]->messageWasSended()) {
if (ninf(nodes[i])->readyToSendLambdaMsgTo (parent)) {
calculateAndUpdateMessage (outParentLinks[j], false);
ninf(parent)->incNumLambdaMsgsReceived();
}
finish = false;
}
}
}
}
}
}
void
BnBpSolver::runLoopySolver()
{
nIters_ = 0;
while (!converged() && nIters_ < BpOptions::maxIter) {
nIters_++;
if (DL >= 2) {
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
cout << " Iteration " << nIters_ << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
}
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]);
updateValues (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]);
updateValues (links_[i]);
}
break;
case BpOptions::Schedule::MAX_RESIDUAL:
maxResidualSchedule();
break;
}
if (DL >= 2) {
cout << endl;
}
}
}
bool
BnBpSolver::converged (void) const
{
// this can happen if the graph is fully disconnected
if (links_.size() == 0) {
return true;
}
if (nIters_ == 0 || nIters_ == 1) {
return false;
}
bool converged = true;
if (BpOptions::schedule == BpOptions::Schedule::MAX_RESIDUAL) {
Param maxResidual = (*(sortedOrder_.begin()))->getResidual();
if (maxResidual < BpOptions::accuracy) {
converged = true;
} else {
converged = false;
}
} else {
for (unsigned i = 0; i < links_.size(); i++) {
Param residual = links_[i]->getResidual();
if (DL >= 2) {
cout << links_[i]->toString() + " residual change = " ;
cout << residual << endl;
}
if (residual > BpOptions::accuracy) {
converged = false;
break;
}
}
}
return converged;
}
void
BnBpSolver::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 < sortedOrder_.size(); c++) {
if (DL >= 2) {
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();
BpLink* link = *it;
if (link->getResidual() < BpOptions::accuracy) {
sortedOrder_.erase (it);
it = sortedOrder_.begin();
return;
}
updateMessage (link);
updateValues (link);
link->clearResidual();
sortedOrder_.erase (it);
linkMap_.find (link)->second = sortedOrder_.insert (link);
const BpLinkSet& outParentLinks =
ninf(link->getDestination())->getOutcomingParentLinks();
for (unsigned i = 0; i < outParentLinks.size(); i++) {
if (outParentLinks[i]->getDestination() != link->getSource()
&& outParentLinks[i]->getDestination()->hasEvidence() == false) {
calculateMessage (outParentLinks[i]);
BpLinkMap::iterator iter = linkMap_.find (outParentLinks[i]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (outParentLinks[i]);
}
}
const BpLinkSet& outChildLinks =
ninf(link->getDestination())->getOutcomingChildLinks();
for (unsigned i = 0; i < outChildLinks.size(); i++) {
if (outChildLinks[i]->getDestination() != link->getSource()) {
calculateMessage (outChildLinks[i]);
BpLinkMap::iterator iter = linkMap_.find (outChildLinks[i]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (outChildLinks[i]);
}
}
if (DL >= 2) {
cout << "----------------------------------------" ;
cout << "----------------------------------------" << endl;
}
}
}
void
BnBpSolver::updatePiValues (BayesNode* x)
{
// π(Xi)
if (DL >= 3) {
cout << "updating " << PI_SYMBOL << " values for " << x->label() << endl;
}
ParamSet& piValues = ninf(x)->getPiValues();
const BpLinkSet& parentLinks = ninf(x)->getIncomingParentLinks();
const vector<CptEntry>& entries = x->getCptEntries();
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
ParamSet messageProducts (entries.size());
for (unsigned k = 0; k < entries.size(); k++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
double messageProduct = Util::multIdenty();
const DConf& conf = entries[k].getDomainConfiguration();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < parentLinks.size(); i++) {
messageProduct *= parentLinks[i]->getMessage()[conf[i]];
if (DL >= 5) {
if (i != 0) *calcs1 << " + " ;
if (i != 0) *calcs2 << " + " ;
*calcs1 << parentLinks[i]->toString (conf[i]);
*calcs2 << parentLinks[i]->getMessage()[conf[i]];
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < parentLinks.size(); i++) {
messageProduct += parentLinks[i]->getMessage()[conf[i]];
}
}
messageProducts[k] = messageProduct;
if (DL >= 5) {
cout << " mp" << k;
cout << " = " << (*calcs1).str();
if (parentLinks.size() == 1) {
cout << " = " << messageProduct << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << messageProduct << endl;
}
delete calcs1;
delete calcs2;
}
}
for (unsigned xi = 0; xi < x->nrStates(); xi++) {
double sum = Util::addIdenty();
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned k = 0; k < entries.size(); k++) {
sum += x->getProbability (xi, entries[k]) * messageProducts[k];
if (DL >= 5) {
if (k != 0) *calcs1 << " + " ;
if (k != 0) *calcs2 << " + " ;
*calcs1 << x->cptEntryToString (xi, entries[k]);
*calcs1 << ".mp" << k;
*calcs2 << Util::fl (x->getProbability (xi, entries[k]));
*calcs2 << "*" << messageProducts[k];
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned k = 0; k < entries.size(); k++) {
Util::logSum (sum,
x->getProbability(xi,entries[k]) + messageProducts[k]);
}
}
piValues[xi] = sum;
if (DL >= 5) {
cout << " " << PI_SYMBOL << "(" << x->label() << ")" ;
cout << "[" << x->states()[xi] << "]" ;
cout << " = " << (*calcs1).str();
cout << " = " << (*calcs2).str();
cout << " = " << piValues[xi] << endl;
delete calcs1;
delete calcs2;
}
}
}
void
BnBpSolver::updateLambdaValues (BayesNode* x)
{
// λ(Xi)
if (DL >= 3) {
cout << "updating " << LD_SYMBOL << " values for " << x->label() << endl;
}
ParamSet& lambdaValues = ninf(x)->getLambdaValues();
const BpLinkSet& childLinks = ninf(x)->getIncomingChildLinks();
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
for (unsigned xi = 0; xi < x->nrStates(); xi++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
double product = Util::multIdenty();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < childLinks.size(); i++) {
product *= childLinks[i]->getMessage()[xi];
if (DL >= 5) {
if (i != 0) *calcs1 << "." ;
if (i != 0) *calcs2 << "*" ;
*calcs1 << childLinks[i]->toString (xi);
*calcs2 << childLinks[i]->getMessage()[xi];
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < childLinks.size(); i++) {
product += childLinks[i]->getMessage()[xi];
}
}
lambdaValues[xi] = product;
if (DL >= 5) {
cout << " " << LD_SYMBOL << "(" << x->label() << ")" ;
cout << "[" << x->states()[xi] << "]" ;
cout << " = " << (*calcs1).str();
if (childLinks.size() == 1) {
cout << " = " << product << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << lambdaValues[xi] << endl;
}
delete calcs1;
delete calcs2;
}
}
}
void
BnBpSolver::calculatePiMessage (BpLink* link)
{
// πX(Zi)
BayesNode* z = link->getSource();
BayesNode* x = link->getDestination();
ParamSet& zxPiNextMessage = link->getNextMessage();
const BpLinkSet& zChildLinks = ninf(z)->getIncomingChildLinks();
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
const ParamSet& zPiValues = ninf(z)->getPiValues();
for (unsigned zi = 0; zi < z->nrStates(); zi++) {
double product = zPiValues[zi];
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
*calcs1 << PI_SYMBOL << "(" << z->label() << ")";
*calcs1 << "[" << z->states()[zi] << "]" ;
*calcs2 << product;
}
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < zChildLinks.size(); i++) {
if (zChildLinks[i]->getSource() != x) {
product *= zChildLinks[i]->getMessage()[zi];
if (DL >= 5) {
*calcs1 << "." << zChildLinks[i]->toString (zi);
*calcs2 << " * " << zChildLinks[i]->getMessage()[zi];
}
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < zChildLinks.size(); i++) {
if (zChildLinks[i]->getSource() != x) {
product += zChildLinks[i]->getMessage()[zi];
}
}
}
zxPiNextMessage[zi] = product;
if (DL >= 5) {
cout << " " << link->toString();
cout << "[" << z->states()[zi] << "]" ;
cout << " = " << (*calcs1).str();
if (zChildLinks.size() == 1) {
cout << " = " << product << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << product << endl;
}
delete calcs1;
delete calcs2;
}
}
Util::normalize (zxPiNextMessage);
}
void
BnBpSolver::calculateLambdaMessage (BpLink* link)
{
// λY(Xi)
BayesNode* y = link->getSource();
BayesNode* x = link->getDestination();
if (x->hasEvidence()) {
return;
}
ParamSet& yxLambdaNextMessage = link->getNextMessage();
const BpLinkSet& yParentLinks = ninf(y)->getIncomingParentLinks();
const ParamSet& yLambdaValues = ninf(y)->getLambdaValues();
const vector<CptEntry>& allEntries = y->getCptEntries();
int parentIndex = y->getIndexOfParent (x);
stringstream* calcs1 = 0;
stringstream* calcs2 = 0;
vector<CptEntry> entries;
DConstraint constr = make_pair (parentIndex, 0);
for (unsigned i = 0; i < allEntries.size(); i++) {
if (allEntries[i].matchConstraints(constr)) {
entries.push_back (allEntries[i]);
}
}
ParamSet messageProducts (entries.size());
for (unsigned k = 0; k < entries.size(); k++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
double messageProduct = Util::multIdenty();
const DConf& conf = entries[k].getDomainConfiguration();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < yParentLinks.size(); i++) {
if (yParentLinks[i]->getSource() != x) {
if (DL >= 5) {
if (messageProduct != Util::multIdenty()) *calcs1 << "*" ;
if (messageProduct != Util::multIdenty()) *calcs2 << "*" ;
*calcs1 << yParentLinks[i]->toString (conf[i]);
*calcs2 << yParentLinks[i]->getMessage()[conf[i]];
}
messageProduct *= yParentLinks[i]->getMessage()[conf[i]];
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < yParentLinks.size(); i++) {
if (yParentLinks[i]->getSource() != x) {
messageProduct += yParentLinks[i]->getMessage()[conf[i]];
}
}
}
messageProducts[k] = messageProduct;
if (DL >= 5) {
cout << " mp" << k;
cout << " = " << (*calcs1).str();
if (yParentLinks.size() == 1) {
cout << 1 << endl;
} else if (yParentLinks.size() == 2) {
cout << " = " << messageProduct << endl;
} else {
cout << " = " << (*calcs2).str();
cout << " = " << messageProduct << endl;
}
delete calcs1;
delete calcs2;
}
}
for (unsigned xi = 0; xi < x->nrStates(); xi++) {
if (DL >= 5) {
calcs1 = new stringstream;
calcs2 = new stringstream;
}
vector<CptEntry> entries;
DConstraint constr = make_pair (parentIndex, xi);
for (unsigned i = 0; i < allEntries.size(); i++) {
if (allEntries[i].matchConstraints(constr)) {
entries.push_back (allEntries[i]);
}
}
double outerSum = Util::addIdenty();
for (unsigned yi = 0; yi < y->nrStates(); yi++) {
if (DL >= 5) {
(yi != 0) ? *calcs1 << " + {" : *calcs1 << "{" ;
(yi != 0) ? *calcs2 << " + {" : *calcs2 << "{" ;
}
double innerSum = Util::addIdenty();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned k = 0; k < entries.size(); k++) {
if (DL >= 5) {
if (k != 0) *calcs1 << " + " ;
if (k != 0) *calcs2 << " + " ;
*calcs1 << y->cptEntryToString (yi, entries[k]);
*calcs1 << ".mp" << k;
*calcs2 << y->getProbability (yi, entries[k]);
*calcs2 << "*" << messageProducts[k];
}
innerSum += y->getProbability (yi, entries[k]) * messageProducts[k];
}
outerSum += innerSum * yLambdaValues[yi];
break;
case NumberSpace::LOGARITHM:
for (unsigned k = 0; k < entries.size(); k++) {
Util::logSum (innerSum,
y->getProbability(yi, entries[k]) + messageProducts[k]);
}
Util::logSum (outerSum, innerSum + yLambdaValues[yi]);
}
if (DL >= 5) {
*calcs1 << "}." << LD_SYMBOL << "(" << y->label() << ")" ;
*calcs1 << "[" << y->states()[yi] << "]";
*calcs2 << "}*" << yLambdaValues[yi];
}
}
yxLambdaNextMessage[xi] = outerSum;
if (DL >= 5) {
cout << " " << link->toString();
cout << "[" << x->states()[xi] << "]" ;
cout << " = " << (*calcs1).str();
cout << " = " << (*calcs2).str();
cout << " = " << yxLambdaNextMessage[xi] << endl;
delete calcs1;
delete calcs2;
}
}
Util::normalize (yxLambdaNextMessage);
}
ParamSet
BnBpSolver::getJointByJunctionNode (const VarIdSet& jointVarIds)
{
unsigned msgSize = 1;
vector<unsigned> dsizes (jointVarIds.size());
for (unsigned i = 0; i < jointVarIds.size(); i++) {
dsizes[i] = bayesNet_->getBayesNode (jointVarIds[i])->nrStates();
msgSize *= dsizes[i];
}
unsigned reps = 1;
ParamSet jointDist (msgSize, Util::multIdenty());
for (int i = jointVarIds.size() - 1 ; i >= 0; i--) {
Util::multiply (jointDist, getPosterioriOf (jointVarIds[i]), reps);
reps *= dsizes[i] ;
}
return jointDist;
}
ParamSet
BnBpSolver::getJointByChainRule (const VarIdSet& jointVarIds) const
{
BnNodeSet jointVars;
for (unsigned i = 0; i < jointVarIds.size(); i++) {
jointVars.push_back (bayesNet_->getBayesNode (jointVarIds[i]));
}
BayesNet* mrn = bayesNet_->getMinimalRequesiteNetwork (jointVarIds[0]);
BnBpSolver solver (*mrn);
solver.runSolver();
ParamSet prevBeliefs = solver.getPosterioriOf (jointVarIds[0]);
delete mrn;
VarNodes observedVars = {jointVars[0]};
for (unsigned i = 1; i < jointVarIds.size(); i++) {
mrn = bayesNet_->getMinimalRequesiteNetwork (jointVarIds[i]);
ParamSet newBeliefs;
vector<DConf> confs =
Util::getDomainConfigurations (observedVars);
for (unsigned j = 0; j < confs.size(); j++) {
for (unsigned k = 0; k < observedVars.size(); k++) {
if (!observedVars[k]->hasEvidence()) {
BayesNode* node = mrn->getBayesNode (observedVars[k]->varId());
if (node) {
node->setEvidence (confs[j][k]);
}
}
}
BnBpSolver solver (*mrn);
solver.runSolver();
ParamSet 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]->nrStates() == 0) {
count ++;
}
newBeliefs[j] *= prevBeliefs[count];
}
prevBeliefs = newBeliefs;
observedVars.push_back (jointVars[i]);
delete mrn;
}
return prevBeliefs;
}
void
BnBpSolver::printPiLambdaValues (const BayesNode* var) const
{
cout << left;
cout << setw (10) << "states" ;
cout << setw (20) << PI_SYMBOL << "(" + var->label() + ")" ;
cout << setw (20) << LD_SYMBOL << "(" + var->label() + ")" ;
cout << setw (16) << "belief" ;
cout << endl;
cout << "--------------------------------" ;
cout << "--------------------------------" ;
cout << endl;
const States& states = var->states();
const ParamSet& piVals = ninf(var)->getPiValues();
const ParamSet& ldVals = ninf(var)->getLambdaValues();
const ParamSet& beliefs = ninf(var)->getBeliefs();
for (unsigned xi = 0; xi < var->nrStates(); xi++) {
cout << setw (10) << states[xi];
cout << setw (19) << piVals[xi];
cout << setw (19) << ldVals[xi];
cout.precision (PRECISION);
cout << setw (16) << beliefs[xi];
cout << endl;
}
cout << endl;
}
void
BnBpSolver::printAllMessageStatus (void) const
{
const BnNodeSet& nodes = bayesNet_->getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
printPiLambdaValues (nodes[i]);
}
}
BpNodeInfo::BpNodeInfo (BayesNode* node)
{
node_ = node;
piValsCalc_ = false;
ldValsCalc_ = false;
nPiMsgsRcv_ = 0;
nLdMsgsRcv_ = 0;
piVals_.resize (node->nrStates(), Util::one());
ldVals_.resize (node->nrStates(), Util::one());
}
ParamSet
BpNodeInfo::getBeliefs (void) const
{
double sum = 0.0;
ParamSet beliefs (node_->nrStates());
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned xi = 0; xi < node_->nrStates(); xi++) {
beliefs[xi] = piVals_[xi] * ldVals_[xi];
sum += beliefs[xi];
}
break;
case NumberSpace::LOGARITHM:
for (unsigned xi = 0; xi < node_->nrStates(); xi++) {
beliefs[xi] = exp (piVals_[xi] + ldVals_[xi]);
sum += beliefs[xi];
}
}
assert (sum);
for (unsigned xi = 0; xi < node_->nrStates(); xi++) {
beliefs[xi] /= sum;
}
return beliefs;
}
void
BpNodeInfo::markPiValuesAsCalculated (void)
{
piValsCalc_ = true;
}
void
BpNodeInfo::markLambdaValuesAsCalculated (void)
{
ldValsCalc_ = true;
}
bool
BpNodeInfo::receivedAllPiMessages (void)
{
return node_->getParents().size() == nPiMsgsRcv_;
}
bool
BpNodeInfo::receivedAllLambdaMessages (void)
{
return node_->getChilds().size() == nLdMsgsRcv_;
}
bool
BpNodeInfo::readyToSendPiMsgTo (const BayesNode* child) const
{
for (unsigned i = 0; i < inChildLinks_.size(); i++) {
if (inChildLinks_[i]->getSource() != child
&& inChildLinks_[i]->messageWasSended() == false) {
return false;
}
}
return true;
}
bool
BpNodeInfo::readyToSendLambdaMsgTo (const BayesNode* parent) const
{
for (unsigned i = 0; i < inParentLinks_.size(); i++) {
if (inParentLinks_[i]->getSource() != parent
&& inParentLinks_[i]->messageWasSended() == false) {
return false;
}
}
return true;
}
bool
BpNodeInfo::receivedBottomInfluence (void) const
{
// if all lambda values are equal, then neither
// this node neither its descendents have evidence,
// we can use this to don't send lambda messages his parents
bool childInfluenced = false;
for (unsigned xi = 1; xi < node_->nrStates(); xi++) {
if (ldVals_[xi] != ldVals_[0]) {
childInfluenced = true;
break;
}
}
return childInfluenced;
}

View File

@ -0,0 +1,262 @@
#ifndef HORUS_BNBPSOLVER_H
#define HORUS_BNBPSOLVER_H
#include <vector>
#include <set>
#include "Solver.h"
#include "BayesNet.h"
#include "Shared.h"
using namespace std;
class BpNodeInfo;
static const string PI_SYMBOL = "pi" ;
static const string LD_SYMBOL = "ld" ;
enum LinkOrientation {UP, DOWN};
enum JointCalcType {CHAIN_RULE, JUNCTION_NODE};
class BpLink
{
public:
BpLink (BayesNode* s, BayesNode* d, LinkOrientation o)
{
source_ = s;
destin_ = d;
orientation_ = o;
if (orientation_ == LinkOrientation::DOWN) {
v1_.resize (s->nrStates(), Util::tl (1.0/s->nrStates()));
v2_.resize (s->nrStates(), Util::tl (1.0/s->nrStates()));
} else {
v1_.resize (d->nrStates(), Util::tl (1.0/d->nrStates()));
v2_.resize (d->nrStates(), Util::tl (1.0/d->nrStates()));
}
currMsg_ = &v1_;
nextMsg_ = &v2_;
residual_ = 0;
msgSended_ = false;
}
void updateMessage (void)
{
swap (currMsg_, nextMsg_);
msgSended_ = true;
}
void updateResidual (void)
{
residual_ = Util::getMaxNorm (v1_, v2_);
}
string toString (void) const
{
stringstream ss;
if (orientation_ == LinkOrientation::DOWN) {
ss << PI_SYMBOL;
} else {
ss << LD_SYMBOL;
}
ss << "(" << source_->label();
ss << " --> " << destin_->label() << ")" ;
return ss.str();
}
string toString (unsigned stateIndex) const
{
stringstream ss;
ss << toString() << "[" ;
if (orientation_ == LinkOrientation::DOWN) {
ss << source_->states()[stateIndex] << "]" ;
} else {
ss << destin_->states()[stateIndex] << "]" ;
}
return ss.str();
}
BayesNode* getSource (void) const { return source_; }
BayesNode* getDestination (void) const { return destin_; }
LinkOrientation getOrientation (void) const { return orientation_; }
const ParamSet& getMessage (void) const { return *currMsg_; }
ParamSet& getNextMessage (void) { return *nextMsg_; }
bool messageWasSended (void) const { return msgSended_; }
double getResidual (void) const { return residual_; }
void clearResidual (void) { residual_ = 0;}
private:
BayesNode* source_;
BayesNode* destin_;
LinkOrientation orientation_;
ParamSet v1_;
ParamSet v2_;
ParamSet* currMsg_;
ParamSet* nextMsg_;
bool msgSended_;
double residual_;
};
typedef vector<BpLink*> BpLinkSet;
class BpNodeInfo
{
public:
BpNodeInfo (BayesNode*);
ParamSet getBeliefs (void) const;
bool receivedBottomInfluence (void) const;
ParamSet& getPiValues (void) { return piVals_; }
ParamSet& getLambdaValues (void) { return ldVals_; }
void incNumPiMsgsReceived (void) { nPiMsgsRcv_ ++; }
void incNumLambdaMsgsReceived (void) { nLdMsgsRcv_ ++; }
bool piValuesCalculated (void) { return piValsCalc_; }
bool lambdaValuesCalculated (void) { return ldValsCalc_; }
void markPiValuesAsCalculated (void);
void markLambdaValuesAsCalculated (void);
bool receivedAllPiMessages (void);
bool receivedAllLambdaMessages (void);
bool readyToSendPiMsgTo (const BayesNode*) const ;
bool readyToSendLambdaMsgTo (const BayesNode*) const;
const BpLinkSet& getIncomingParentLinks (void) { return inParentLinks_; }
const BpLinkSet& getIncomingChildLinks (void) { return inChildLinks_; }
const BpLinkSet& getOutcomingParentLinks (void) { return outParentLinks_; }
const BpLinkSet& getOutcomingChildLinks (void) { return outChildLinks_; }
void addIncomingParentLink (BpLink* l) { inParentLinks_.push_back (l); }
void addIncomingChildLink (BpLink* l) { inChildLinks_.push_back (l); }
void addOutcomingParentLink (BpLink* l) { outParentLinks_.push_back (l); }
void addOutcomingChildLink (BpLink* l) { outChildLinks_.push_back (l); }
private:
DISALLOW_COPY_AND_ASSIGN (BpNodeInfo);
ParamSet piVals_; // pi values
ParamSet ldVals_; // lambda values
unsigned nPiMsgsRcv_;
unsigned nLdMsgsRcv_;
bool piValsCalc_;
bool ldValsCalc_;
BpLinkSet inParentLinks_;
BpLinkSet inChildLinks_;
BpLinkSet outParentLinks_;
BpLinkSet outChildLinks_;
const BayesNode* node_;
};
class BnBpSolver : public Solver
{
public:
BnBpSolver (const BayesNet&);
~BnBpSolver (void);
void runSolver (void);
ParamSet getPosterioriOf (VarId);
ParamSet getJointDistributionOf (const VarIdSet&);
private:
DISALLOW_COPY_AND_ASSIGN (BnBpSolver);
void initializeSolver (void);
void runPolyTreeSolver (void);
void runLoopySolver (void);
void maxResidualSchedule (void);
bool converged (void) const;
void updatePiValues (BayesNode*);
void updateLambdaValues (BayesNode*);
void calculateLambdaMessage (BpLink*);
void calculatePiMessage (BpLink*);
ParamSet getJointByJunctionNode (const VarIdSet&);
ParamSet getJointByChainRule (const VarIdSet&) const;
void printPiLambdaValues (const BayesNode*) const;
void printAllMessageStatus (void) const;
void calculateAndUpdateMessage (BpLink* link, bool calcResidual = true)
{
if (DL >= 3) {
cout << "calculating & updating " << link->toString() << endl;
}
if (link->getOrientation() == LinkOrientation::DOWN) {
calculatePiMessage (link);
} else if (link->getOrientation() == LinkOrientation::UP) {
calculateLambdaMessage (link);
}
if (calcResidual) {
link->updateResidual();
}
link->updateMessage();
}
void calculateMessage (BpLink* link, bool calcResidual = true)
{
if (DL >= 3) {
cout << "calculating " << link->toString() << endl;
}
if (link->getOrientation() == LinkOrientation::DOWN) {
calculatePiMessage (link);
} else if (link->getOrientation() == LinkOrientation::UP) {
calculateLambdaMessage (link);
}
if (calcResidual) {
link->updateResidual();
}
}
void updateMessage (BpLink* link)
{
if (DL >= 3) {
cout << "updating " << link->toString() << endl;
}
link->updateMessage();
}
void updateValues (BpLink* link)
{
if (!link->getDestination()->hasEvidence()) {
if (link->getOrientation() == LinkOrientation::DOWN) {
updatePiValues (link->getDestination());
} else if (link->getOrientation() == LinkOrientation::UP) {
updateLambdaValues (link->getDestination());
}
}
}
BpNodeInfo* ninf (const BayesNode* node) const
{
assert (node);
assert (node == bayesNet_->getBayesNode (node->varId()));
assert (node->getIndex() < nodesI_.size());
return nodesI_[node->getIndex()];
}
const BayesNet* bayesNet_;
vector<BpLink*> links_;
vector<BpNodeInfo*> nodesI_;
unsigned nIters_;
JointCalcType jointCalcType_;
struct compare
{
inline bool operator() (const BpLink* e1, const BpLink* e2)
{
return e1->getResidual() > e2->getResidual();
}
};
typedef multiset<BpLink*, compare> SortedOrder;
SortedOrder sortedOrder_;
typedef unordered_map<BpLink*, SortedOrder::iterator> BpLinkMap;
BpLinkMap linkMap_;
};
#endif // HORUS_BNBPSOLVER_H

View File

@ -1,811 +0,0 @@
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include "BpNetwork.h"
#include "BpNode.h"
#include "CptEntry.h"
BpNetwork::BpNetwork (void)
{
schedule_ = SEQUENTIAL_SCHEDULE;
maxIter_ = 150;
stableThreashold_ = 0.00000000000000000001;
}
BpNetwork::~BpNetwork (void)
{
for (unsigned int i = 0; i < nodes_.size(); i++) {
delete nodes_[i];
}
nodes_.clear();
}
void
BpNetwork::setSolverParameters (Schedule schedule,
int maxIter,
double stableThreashold)
{
if (maxIter <= 0) {
cerr << "error: maxIter must be greater or equal to 1" << endl;
abort();
}
if (stableThreashold <= 0.0 || stableThreashold >= 1.0) {
cerr << "error: stableThreashold must be greater than 0.0 " ;
cerr << "and lesser than 1.0" << endl;
abort();
}
schedule_ = schedule;
maxIter_ = maxIter;
stableThreashold_ = stableThreashold;
}
void
BpNetwork::runSolver (BayesianNode* queryVar)
{
vector<BayesianNode*> queryVars;
queryVars.push_back (queryVar);
runSolver (queryVars);
}
void
BpNetwork::runSolver (vector<BayesianNode*> queryVars)
{
if (queryVars.size() > 1) {
addJunctionNode (queryVars);
}
else {
string varName = queryVars[0]->getVariableName();
queryNode_ = static_cast<BpNode*> (getNode (varName));
}
if (!isPolyTree()) {
if (DL_ >= 1) {
cout << "The graph is not single connected. " ;
cout << "Iterative belief propagation will be used." ;
cout << endl << endl;
}
schedule_ = PARALLEL_SCHEDULE;
}
if (schedule_ == SEQUENTIAL_SCHEDULE) {
initializeSolver (queryVars);
runNeapolitanSolver();
for (unsigned int i = 0; i < nodes_.size(); i++) {
if (nodes_[i]->hasEvidence()) {
BpNode* v = static_cast<BpNode*> (nodes_[i]);
addEvidence (v);
vector<BpNode*> parents = cast (v->getParents());
for (unsigned int i = 0; i < parents.size(); i++) {
if (!parents[i]->hasEvidence()) {
sendLambdaMessage (v, parents[i]);
}
}
vector<BpNode*> childs = cast (v->getChilds());
for (unsigned int i = 0; i < childs.size(); i++) {
sendPiMessage (v, childs[i]);
}
}
}
} else if (schedule_ == PARALLEL_SCHEDULE) {
BpNode::enableParallelSchedule();
initializeSolver (queryVars);
for (unsigned int i = 0; i < nodes_.size(); i++) {
if (nodes_[i]->hasEvidence()) {
addEvidence (static_cast<BpNode*> (nodes_[i]));
}
}
runIterativeBpSolver();
}
}
void
BpNetwork::printCurrentStatus (void)
{
for (unsigned int i = 0; i < nodes_.size(); i++) {
printCurrentStatusOf (static_cast<BpNode*> (nodes_[i]));
}
}
void
BpNetwork::printCurrentStatusOf (BpNode* x)
{
vector<BpNode*> childs = cast (x->getChilds());
vector<string> domain = x->getDomain();
cout << left;
cout << setw (10) << "domain" ;
cout << setw (20) << "π(" + x->getVariableName() + ")" ;
cout << setw (20) << "λ(" + x->getVariableName() + ")" ;
cout << setw (16) << "belief" ;
cout << endl;
cout << "--------------------------------" ;
cout << "--------------------------------" ;
cout << endl;
double* piValues = x->getPiValues();
double* lambdaValues = x->getLambdaValues();
double* beliefs = x->getBeliefs();
for (int xi = 0; xi < x->getDomainSize(); xi++) {
cout << setw (10) << domain[xi];
cout << setw (19) << piValues[xi];
cout << setw (19) << lambdaValues[xi];
cout.precision (PRECISION_);
cout << setw (16) << beliefs[xi];
cout << endl;
}
cout << endl;
if (childs.size() > 0) {
string s = "(" + x->getVariableName() + ")" ;
for (unsigned int j = 0; j < childs.size(); j++) {
cout << setw (10) << "domain" ;
cout << setw (28) << "π" + childs[j]->getVariableName() + s;
cout << setw (28) << "λ" + childs[j]->getVariableName() + s;
cout << endl;
cout << "--------------------------------" ;
cout << "--------------------------------" ;
cout << endl;
for (int xi = 0; xi < x->getDomainSize(); xi++) {
cout << setw (10) << domain[xi];
cout.precision (PRECISION_);
cout << setw (27) << x->getPiMessage(childs[j], xi);
cout.precision (PRECISION_);
cout << setw (27) << x->getLambdaMessage(childs[j], xi);
cout << endl;
}
cout << endl;
}
}
}
void
BpNetwork::printBeliefs (void)
{
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*> (nodes_[i]);
vector<string> domain = x->getDomain();
cout << setw (20) << left << x->getVariableName() ;
cout << setw (26) << "belief" ;
cout << endl;
cout << "--------------------------------------" ;
cout << endl;
double* beliefs = x->getBeliefs();
for (int xi = 0; xi < x->getDomainSize(); xi++) {
cout << setw (20) << domain[xi];
cout.precision (PRECISION_);
cout << setw (26) << beliefs[xi];
cout << endl;
}
cout << endl;
}
}
vector<double>
BpNetwork::getBeliefs (void)
{
return getBeliefs (queryNode_);
}
vector<double>
BpNetwork::getBeliefs (BpNode* x)
{
double* beliefs = x->getBeliefs();
vector<double> beliefsVec;
for (int xi = 0; xi < x->getDomainSize(); xi++) {
beliefsVec.push_back (beliefs[xi]);
}
return beliefsVec;
}
void
BpNetwork::initializeSolver (vector<BayesianNode*> queryVars)
{
if (DL_ >= 1) {
cout << "Initializing solver" << endl;
if (schedule_ == SEQUENTIAL_SCHEDULE) {
cout << "-> schedule = sequential" << endl;
} else {
cout << "-> schedule = parallel" << endl;
}
cout << "-> max iters = " << maxIter_ << endl;
cout << "-> stable threashold = " << stableThreashold_ << endl;
cout << "-> query vars = " ;
for (unsigned int i = 0; i < queryVars.size(); i++) {
cout << queryVars[i]->getVariableName() << " " ;
}
cout << endl;
}
nIter_ = 0;
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* node = static_cast<BpNode*> (nodes_[i]);
node->allocateMemory();
}
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*> (nodes_[i]);
double* piValues = x->getPiValues();
double* lambdaValues = x->getLambdaValues();
for (int xi = 0; xi < x->getDomainSize(); xi++) {
piValues[xi] = 1.0;
lambdaValues[xi] = 1.0;
}
vector<BpNode*> xChilds = cast (x->getChilds());
for (unsigned int j = 0; j < xChilds.size(); j++) {
double* piMessages = x->getPiMessages (xChilds[j]);
for (int xi = 0; xi < x->getDomainSize(); xi++) {
piMessages[xi] = 1.0;
//x->setPiMessage (xChilds[j], xi, 1.0);
}
}
vector<BpNode*> xParents = cast (x->getParents());
for (unsigned int j = 0; j < xParents.size(); j++) {
double* lambdaMessages = xParents[j]->getLambdaMessages (x);
for (int xi = 0; xi < xParents[j]->getDomainSize(); xi++) {
lambdaMessages[xi] = 1.0;
//xParents[j]->setLambdaMessage (x, xi, 1.0);
}
}
}
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*> (nodes_[i]);
x->normalizeMessages();
}
printCurrentStatus();
vector<BpNode*> roots = cast (getRootNodes());
for (unsigned int i = 0; i < roots.size(); i++) {
double* params = roots[i]->getParameters();
double* piValues = roots[i]->getPiValues();
for (int ri = 0; ri < roots[i]->getDomainSize(); ri++) {
piValues[ri] = params[ri];
}
}
}
void
BpNetwork::addJunctionNode (vector<BayesianNode*> queryVars)
{
const string VAR_NAME = "_Jn";
int nStates = 1;
vector<BayesianNode*> parents;
vector<string> domain;
for (unsigned int i = 0; i < queryVars.size(); i++) {
parents.push_back (queryVars[i]);
nStates *= queryVars[i]->getDomainSize();
}
for (int i = 0; i < nStates; i++) {
stringstream ss;
ss << "_jn" << i;
domain.push_back (ss.str()); // FIXME make domain optional
}
int nParams = nStates * nStates;
double* params = new double [nParams];
for (int i = 0; i < nParams; i++) {
int row = i / nStates;
int col = i % nStates;
if (row == col) {
params[i] = 1;
} else {
params[i] = 0;
}
}
addNode (VAR_NAME, parents, params, nParams, domain);
queryNode_ = static_cast<BpNode*> (getNode (VAR_NAME));
printNetwork();
}
void
BpNetwork::addEvidence (BpNode* v)
{
if (DL_ >= 1) {
cout << "Adding evidence: node " ;
cout << "`" << v->getVariableName() << "' was instantiated as " ;
cout << "`" << v->getDomain()[v->getEvidence()] << "'" ;
cout << endl;
}
double* piValues = v->getPiValues();
double* lambdaValues = v->getLambdaValues();
for (int vi = 0; vi < v->getDomainSize(); vi++) {
if (vi == v->getEvidence()) {
piValues[vi] = 1.0;
lambdaValues[vi] = 1.0;
} else {
piValues[vi] = 0.0;
lambdaValues[vi] = 0.0;
}
}
}
void
BpNetwork::runNeapolitanSolver (void)
{
vector<BpNode*> roots = cast (getRootNodes());
for (unsigned int i = 0; i < roots.size(); i++) {
vector<BpNode*> childs = cast (roots[i]->getChilds());
for (unsigned int j = 0; j < childs.size(); j++) {
sendPiMessage (roots[i], static_cast<BpNode*> (childs[j]));
}
}
}
void
BpNetwork::sendPiMessage (BpNode* z, BpNode* x)
{
nIter_ ++;
if (!(maxIter_ == -1 || nIter_ < maxIter_)) {
cout << "the maximum number of iterations was achieved, terminating..." ;
cout << endl;
return;
}
if (DL_ >= 1) {
cout << "π message " << z->getVariableName();
cout << " --> " << x->getVariableName() << endl;
}
updatePiMessages(z, x);
if (!x->hasEvidence()) {
updatePiValues (x);
vector<BpNode*> xChilds = cast (x->getChilds());
for (unsigned int i = 0; i < xChilds.size(); i++) {
sendPiMessage (x, xChilds[i]);
}
}
bool isAllOnes = true;
double* lambdaValues = x->getLambdaValues();
for (int xi = 0; xi < x->getDomainSize(); xi++) {
if (lambdaValues[xi] != 1.0) {
isAllOnes = false;
break;
}
}
if (!isAllOnes) {
vector<BpNode*> xParents = cast (x->getParents());
for (unsigned int i = 0; i < xParents.size(); i++) {
if (xParents[i] != z && !xParents[i]->hasEvidence()) {
sendLambdaMessage (x, xParents[i]);
}
}
}
}
void
BpNetwork::sendLambdaMessage (BpNode* y, BpNode* x)
{
nIter_ ++;
if (!(maxIter_ == -1 || nIter_ < maxIter_)) {
cout << "the maximum number of iterations was achieved, terminating..." ;
cout << endl;
return;
}
if (DL_ >= 1) {
cout << "λ message " << y->getVariableName();
cout << " --> " << x->getVariableName() << endl;
}
updateLambdaMessages (x, y);
updateLambdaValues (x);
vector<BpNode*> xParents = cast (x->getParents());
for (unsigned int i = 0; i < xParents.size(); i++) {
if (!xParents[i]->hasEvidence()) {
sendLambdaMessage (x, xParents[i]);
}
}
vector<BpNode*> xChilds = cast (x->getChilds());
for (unsigned int i = 0; i < xChilds.size(); i++) {
if (xChilds[i] != y) {
sendPiMessage (x, xChilds[i]);
}
}
}
void
BpNetwork::updatePiValues (BpNode* x)
{
// π(Xi)
vector<BpNode*> parents = cast (x->getParents());
for (int xi = 0; xi < x->getDomainSize(); xi++) {
stringstream calcs1;
stringstream calcs2;
if (DL_ >= 2) {
calcs1 << "π("<< x->getDomain()[xi] << ")" << endl << "= " ;
}
double sum = 0.0;
vector<pair<int, int> > constraints;
vector<CptEntry> entries = x->getCptEntriesOfRow (xi);
for (unsigned int k = 0; k < entries.size(); k++) {
double prod = x->getProbability (entries[k]);
if (DL_ >= 2) {
if (k != 0) calcs1 << endl << "+ " ;
calcs1 << x->entryToString (entries[k]);
if (DL_ >= 3) {
(k == 0) ? calcs2 << "(" << prod : calcs2 << endl << "+ (" << prod;
}
}
vector<int> insts = entries[k].getDomainInstantiations();
for (unsigned int i = 0; i < parents.size(); i++) {
double value = parents[i]->getPiMessage (x, insts[i + 1]);
prod *= value;
if (DL_ >= 2) {
calcs1 << "" << x->getVariableName();
calcs1 << "(" << parents[i]->getDomain()[insts[i + 1]] << ")";
if (DL_ >= 3) calcs2 << "x" << value;
}
}
sum += prod;
if (DL_ >= 3) calcs2 << ")";
}
x->setPiValue (xi, sum);
if (DL_ >= 2) {
cout << calcs1.str();
if (DL_ >= 3) cout << endl << "= " << calcs2.str();
cout << " = " << sum << endl;
}
}
}
void
BpNetwork::updatePiMessages (BpNode* z, BpNode* x)
{
// πX(Zi)
vector<BpNode*> zChilds = cast (z->getChilds());
for (int zi = 0; zi < z->getDomainSize(); zi++) {
stringstream calcs1;
stringstream calcs2;
if (DL_ >= 2) {
calcs1 << "π" << x->getVariableName();
calcs1 << "(" << z->getDomain()[zi] << ") = " ;
}
double prod = z->getPiValue (zi);
if (DL_ >= 2) {
calcs1 << "π(" << z->getDomain()[zi] << ")" ;
if (DL_ >= 3) calcs2 << prod;
}
for (unsigned int i = 0; i < zChilds.size(); i++) {
if (zChilds[i] != x) {
double value = z->getLambdaMessage (zChilds[i], zi);
prod *= value;
if (DL_ >= 2) {
calcs1 << "" << zChilds[i]->getVariableName();
calcs1 << "(" << z->getDomain()[zi] + ")" ;
if (DL_ >= 3) calcs2 << " x " << value;
}
}
}
z->setPiMessage (x, zi, prod);
if (DL_ >= 2) {
cout << calcs1.str();
if (DL_ >= 3) cout << " = " << calcs2.str();
cout << " = " << prod << endl;
}
}
}
void
BpNetwork::updateLambdaValues (BpNode* x)
{
// λ(Xi)
vector<BpNode*> childs = cast (x->getChilds());
for (int xi = 0; xi < x->getDomainSize(); xi++) {
stringstream calcs1;
stringstream calcs2;
if (DL_ >= 2) {
calcs1 << "λ" << "(" << x->getDomain()[xi] << ") = " ;
}
double prod = 1.0;
for (unsigned int i = 0; i < childs.size(); i++) {
double val = x->getLambdaMessage (childs[i], xi);
prod *= val;
if (DL_ >= 2) {
if (i != 0) calcs1 << "." ;
calcs1 << "λ" << childs[i]->getVariableName();
calcs1 << "(" << x->getDomain()[xi] + ")" ;
if (DL_ >= 3) (i == 0) ? calcs2 << val : calcs2 << " x " << val;
}
}
x->setLambdaValue (xi, prod);
if (DL_ >= 2) {
cout << calcs1.str();
if (childs.size() == 0) {
cout << 1 << endl;
} else {
if (DL_ >= 3) cout << " = " << calcs2.str();
cout << " = " << prod << endl;
}
}
}
}
void
BpNetwork::updateLambdaMessages (BpNode* x, BpNode* y)
{
// λY(Xi)
int parentIndex = y->getIndexOfParent (x) + 1;
vector<BpNode*> yParents = cast (y->getParents());
for (int xi = 0; xi < x->getDomainSize(); xi++) {
stringstream calcs1;
stringstream calcs2;
if (DL_ >= 2) {
calcs1 << "λ" << y->getVariableName() ;
calcs1 << "(" << x->getDomain()[xi] << ")" << endl << "= " ;
}
double outer_sum = 0.0;
for (int yi = 0; yi < y->getDomainSize(); yi++) {
if (DL_ >= 2) {
(yi == 0) ? calcs1 << "[" : calcs1 << endl << "+ [" ;
if (DL_ >= 3) {
(yi == 0) ? calcs2 << "[" : calcs2 << endl << "+ [" ;
}
}
double inner_sum = 0.0;
vector<pair<int, int> > constraints;
constraints.push_back (make_pair (0, yi));
constraints.push_back (make_pair (parentIndex, xi));
vector<CptEntry> entries = y->getCptEntries (constraints);
for (unsigned int k = 0; k < entries.size(); k++) {
double prod = y->getProbability (entries[k]);
if (DL_ >= 2) {
if (k != 0) calcs1 << " + " ;
calcs1 << y->entryToString (entries[k]);
if (DL_ >= 3) {
(k == 0) ? calcs2 << "(" << prod : calcs2 << " + (" << prod;
}
}
vector<int> insts = entries[k].getDomainInstantiations();
for (unsigned int i = 0; i < yParents.size(); i++) {
if (yParents[i] != x) {
double val = yParents[i]->getPiMessage (y, insts[i + 1]);
prod *= val;
if (DL_ >= 2) {
calcs1 << "" << y->getVariableName();
calcs1 << "(" << yParents[i]->getDomain()[insts[i + 1]] << ")" ;
if (DL_ >= 3) calcs2 << "x" << val;
}
}
}
inner_sum += prod;
if (DL_ >= 3) {
calcs2 << ")" ;
}
}
outer_sum += inner_sum * y->getLambdaValue (yi);
if (DL_ >= 2) {
calcs1 << "].λ(" << y->getDomain()[yi] << ")";
if (DL_ >= 3) calcs2 << "]x" << y->getLambdaValue (yi);
}
}
x->setLambdaMessage (y, xi, outer_sum);
if (DL_ >= 2) {
cout << calcs1.str();
if (DL_ >= 3) cout << endl << "= " << calcs2.str();
cout << " = " << outer_sum << endl;
}
}
}
void
BpNetwork::runIterativeBpSolver()
{
int nIter = 0;
maxIter_ = 100;
bool converged = false;
while (nIter < maxIter_ && !converged) {
if (DL_ >= 1) {
cout << endl << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
cout << " Iteration " << nIter + 1 << endl;
cout << "****************************************" ;
cout << "****************************************" ;
}
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*>(nodes_[i]);
vector<BpNode*> xParents = cast (x->getParents());
for (unsigned int j = 0; j < xParents.size(); j++) {
//if (!xParents[j]->hasEvidence()) {
if (DL_ >= 1) {
cout << endl << "λ message " << x->getVariableName();
cout << " --> " << xParents[j]->getVariableName() << endl;
}
updateLambdaMessages (xParents[j], x);
//}
}
}
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*>(nodes_[i]);
vector<BpNode*> xChilds = cast (x->getChilds());
for (unsigned int j = 0; j < xChilds.size(); j++) {
if (DL_ >= 1) {
cout << endl << "π message " << x->getVariableName();
cout << " --> " << xChilds[j]->getVariableName() << endl;
}
updatePiMessages (x, xChilds[j]);
}
}
/*
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*>(nodes_[i]);
vector<BpNode*> xChilds = cast (x->getChilds());
for (unsigned int j = 0; j < xChilds.size(); j++) {
if (DL_ >= 1) {
cout << "π message " << x->getVariableName();
cout << " --> " << xChilds[j]->getVariableName() << endl;
}
updatePiMessages (x, xChilds[j]);
}
vector<BpNode*> xParents = cast (x->getParents());
for (unsigned int j = 0; j < xParents.size(); j++) {
//if (!xParents[j]->hasEvidence()) {
if (DL_ >= 1) {
cout << "λ message " << x->getVariableName();
cout << " --> " << xParents[j]->getVariableName() << endl;
}
updateLambdaMessages (xParents[j], x);
//}
}
}
*/
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*> (nodes_[i]);
//cout << endl << "SWAPING MESSAGES FOR " << x->getVariableName() << ":" ;
//cout << endl << endl;
//printCurrentStatusOf (x);
x->swapMessages();
x->normalizeMessages();
//cout << endl << "messages swaped " << endl;
//printCurrentStatusOf (x);
}
converged = true;
for (unsigned int i = 0; i < nodes_.size(); i++) {
BpNode* x = static_cast<BpNode*>(nodes_[i]);
if (DL_ >= 1) {
cout << endl << "var " << x->getVariableName() << ":" << endl;
}
//if (!x->hasEvidence()) {
updatePiValues (x);
updateLambdaValues (x);
double change = x->getBeliefChange();
if (DL_ >= 1) {
cout << "belief change = " << change << endl;
}
if (change > stableThreashold_) {
converged = false;
}
//}
}
if (converged) {
// converged = false;
}
if (DL_ >= 2) {
cout << endl;
printCurrentStatus();
}
nIter++;
}
if (DL_ >= 1) {
cout << endl;
if (converged) {
cout << "Iterative belief propagation converged in " ;
cout << nIter << " iterations" << endl;
} else {
cout << "Iterative belief propagation converged didn't converge" ;
cout << endl;
}
if (DL_ == 1) {
cout << endl;
printBeliefs();
}
cout << endl;
}
}
void
BpNetwork::addNode (string varName,
vector<BayesianNode*> parents,
int evidence,
int distId)
{
for (unsigned int i = 0; i < dists_.size(); i++) {
if (dists_[i]->id == distId) {
BpNode* node = new BpNode (varName, parents, dists_[i], evidence);
nodes_.push_back (node);
break;
}
}
}
void
BpNetwork::addNode (string varName,
vector<BayesianNode*> parents,
double* params,
int nParams,
vector<string> domain)
{
Distribution* dist = new Distribution (params, nParams, domain);
BpNode* node = new BpNode (varName, parents, dist);
dists_.push_back (dist);
nodes_.push_back (node);
}
vector<BpNode*>
BpNetwork::cast (vector<BayesianNode*> nodes)
{
vector<BpNode*> castedNodes (nodes.size());
for (unsigned int i = 0; i < nodes.size(); i++) {
castedNodes[i] = static_cast<BpNode*> (nodes[i]);
}
return castedNodes;
}

View File

@ -1,66 +0,0 @@
#ifndef BP_BP_NETWORK_H
#define BP_BP_NETWORK_H
#include <vector>
#include <string>
#include "BayesianNetwork.h"
using namespace std;
class BpNode;
enum Schedule
{
SEQUENTIAL_SCHEDULE,
PARALLEL_SCHEDULE
};
class BpNetwork : public BayesianNetwork
{
public:
// constructs
BpNetwork (void);
// destruct
~BpNetwork (void);
// methods
void setSolverParameters (Schedule, int, double);
void runSolver (BayesianNode* queryVar);
void runSolver (vector<BayesianNode*>);
void printCurrentStatus (void);
void printCurrentStatusOf (BpNode*);
void printBeliefs (void);
vector<double> getBeliefs (void);
vector<double> getBeliefs (BpNode*);
private:
BpNetwork (const BpNetwork&); // disallow copy
void operator= (const BpNetwork&); // disallow assign
// methods
void initializeSolver (vector<BayesianNode*>);
void addJunctionNode (vector<BayesianNode*>);
void addEvidence (BpNode*);
void runNeapolitanSolver (void);
void sendLambdaMessage (BpNode*, BpNode*);
void sendPiMessage (BpNode*, BpNode*);
void updatePiValues (BpNode*);
void updatePiMessages (BpNode*, BpNode*);
void updateLambdaValues (BpNode*);
void updateLambdaMessages (BpNode*, BpNode*);
void runIterativeBpSolver (void);
void addNode (string, vector<BayesianNode*>, int, int);
void addNode (string, vector<BayesianNode*>,
double*, int, vector<string>);
vector<BpNode*> cast (vector<BayesianNode*>);
// members
Schedule schedule_;
int nIter_;
int maxIter_;
double stableThreashold_;
BpNode* queryNode_;
static const int DL_ = 3;
static const int PRECISION_ = 10;
};
#endif // BP_BP_NETWORK_H

View File

@ -1,250 +0,0 @@
#include <iostream>
#include <cassert>
#include <cmath>
#include "BpNode.h"
bool BpNode::calculateMessageResidual_ = true;
BpNode::BpNode (BayesNode* node)
{
ds_ = node->getDomainSize();
const NodeSet& childs = node->getChilds();
piVals_.resize (ds_, 1);
ldVals_.resize (ds_, 1);
if (calculateMessageResidual_) {
piResiduals_.resize (childs.size(), 0.0);
ldResiduals_.resize (childs.size(), 0.0);
}
childs_ = &childs;
for (unsigned i = 0; i < childs.size(); i++) {
//indexMap_.insert (make_pair (childs[i]->getVarId(), i));
currPiMsgs_.push_back (ParamSet (ds_, 1));
currLdMsgs_.push_back (ParamSet (ds_, 1));
nextPiMsgs_.push_back (ParamSet (ds_, 1));
nextLdMsgs_.push_back (ParamSet (ds_, 1));
}
}
ParamSet
BpNode::getBeliefs (void) const
{
double sum = 0.0;
ParamSet beliefs (ds_);
for (int xi = 0; xi < ds_; xi++) {
double prod = piVals_[xi] * ldVals_[xi];
beliefs[xi] = prod;
sum += prod;
}
assert (sum);
//normalize the beliefs
for (int xi = 0; xi < ds_; xi++) {
beliefs[xi] /= sum;
}
return beliefs;
}
double
BpNode::getPiValue (int idx) const
{
assert (idx >=0 && idx < ds_);
return piVals_[idx];
}
void
BpNode::setPiValue (int idx, double value)
{
assert (idx >=0 && idx < ds_);
piVals_[idx] = value;
}
double
BpNode::getLambdaValue (int idx) const
{
assert (idx >=0 && idx < ds_);
return ldVals_[idx];
}
void
BpNode::setLambdaValue (int idx, double value)
{
assert (idx >=0 && idx < ds_);
ldVals_[idx] = value;
}
ParamSet&
BpNode::getPiValues (void)
{
return piVals_;
}
ParamSet&
BpNode::getLambdaValues (void)
{
return ldVals_;
}
double
BpNode::getPiMessageValue (const BayesNode* destination, int idx) const
{
assert (idx >=0 && idx < ds_);
return currPiMsgs_[getIndex(destination)][idx];
}
double
BpNode::getLambdaMessageValue (const BayesNode* source, int idx) const
{
assert (idx >=0 && idx < ds_);
return currLdMsgs_[getIndex(source)][idx];
}
const ParamSet&
BpNode::getPiMessage (const BayesNode* destination) const
{
return currPiMsgs_[getIndex(destination)];
}
const ParamSet&
BpNode::getLambdaMessage (const BayesNode* source) const
{
return currLdMsgs_[getIndex(source)];
}
ParamSet&
BpNode::piNextMessageReference (const BayesNode* destination)
{
return nextPiMsgs_[getIndex(destination)];
}
ParamSet&
BpNode::lambdaNextMessageReference (const BayesNode* source)
{
return nextLdMsgs_[getIndex(source)];
}
void
BpNode::updatePiMessage (const BayesNode* destination)
{
int idx = getIndex (destination);
currPiMsgs_[idx] = nextPiMsgs_[idx];
Util::normalize (currPiMsgs_[idx]);
}
void
BpNode::updateLambdaMessage (const BayesNode* source)
{
int idx = getIndex (source);
currLdMsgs_[idx] = nextLdMsgs_[idx];
Util::normalize (currLdMsgs_[idx]);
}
double
BpNode::getBeliefChange (void)
{
double change = 0.0;
if (oldBeliefs_.size() == 0) {
oldBeliefs_ = getBeliefs();
change = 9999999999.0;
} else {
ParamSet currentBeliefs = getBeliefs();
for (int xi = 0; xi < ds_; xi++) {
change += abs (currentBeliefs[xi] - oldBeliefs_[xi]);
}
oldBeliefs_ = currentBeliefs;
}
return change;
}
void
BpNode::updatePiResidual (const BayesNode* destination)
{
int idx = getIndex (destination);
Util::normalize (nextPiMsgs_[idx]);
//piResiduals_[idx] = Util::getL1dist (
// currPiMsgs_[idx], nextPiMsgs_[idx]);
piResiduals_[idx] = Util::getMaxNorm (
currPiMsgs_[idx], nextPiMsgs_[idx]);
}
void
BpNode::updateLambdaResidual (const BayesNode* source)
{
int idx = getIndex (source);
Util::normalize (nextLdMsgs_[idx]);
//ldResiduals_[idx] = Util::getL1dist (
// currLdMsgs_[idx], nextLdMsgs_[idx]);
ldResiduals_[idx] = Util::getMaxNorm (
currLdMsgs_[idx], nextLdMsgs_[idx]);
}
void
BpNode::clearPiResidual (const BayesNode* destination)
{
piResiduals_[getIndex(destination)] = 0;
}
void
BpNode::clearLambdaResidual (const BayesNode* source)
{
ldResiduals_[getIndex(source)] = 0;
}
bool
BpNode::hasReceivedChildInfluence (void) const
{
// if all lambda values are equal, then neither
// this node neither its descendents have evidence,
// we can use this to don't send lambda messages his parents
bool childInfluenced = false;
for (int xi = 1; xi < ds_; xi++) {
if (ldVals_[xi] != ldVals_[0]) {
childInfluenced = true;
break;
}
}
return childInfluenced;
}

View File

@ -1,99 +0,0 @@
#ifndef BP_BPNODE_H
#define BP_BPNODE_H
#include <vector>
#include <map>
#include <string>
#include <unordered_map>
#include "BayesNode.h"
#include "Shared.h"
using namespace std;
class BpNode
{
public:
BpNode (int);
BpNode (BayesNode*);
ParamSet getBeliefs (void) const;
double getPiValue (int) const;
void setPiValue (int, double);
double getLambdaValue (int) const;
void setLambdaValue (int, double);
ParamSet& getPiValues (void);
ParamSet& getLambdaValues (void);
double getPiMessageValue (const BayesNode*, int) const;
double getLambdaMessageValue (const BayesNode*, int) const;
const ParamSet& getPiMessage (const BayesNode*) const;
const ParamSet& getLambdaMessage (const BayesNode*) const;
ParamSet& piNextMessageReference (const BayesNode*);
ParamSet& lambdaNextMessageReference (const BayesNode*);
void updatePiMessage (const BayesNode*);
void updateLambdaMessage (const BayesNode*);
double getBeliefChange (void);
void updatePiResidual (const BayesNode*);
void updateLambdaResidual (const BayesNode*);
void clearPiResidual (const BayesNode*);
void clearLambdaResidual (const BayesNode*);
bool hasReceivedChildInfluence (void) const;
// inlines
double getPiResidual (const BayesNode*);
double getLambdaResidual (const BayesNode*);
int getIndex (const BayesNode*) const;
private:
DISALLOW_COPY_AND_ASSIGN (BpNode);
IndexMap indexMap_;
ParamSet piVals_; // pi values
ParamSet ldVals_; // lambda values
vector<ParamSet> currPiMsgs_; // current pi messages
vector<ParamSet> currLdMsgs_; // current lambda messages
vector<ParamSet> nextPiMsgs_;
vector<ParamSet> nextLdMsgs_;
ParamSet oldBeliefs_;
ParamSet piResiduals_;
ParamSet ldResiduals_;
int ds_;
const NodeSet* childs_;
static bool calculateMessageResidual_;
// static const double MAX_CHANGE_ = 10000000.0;
};
inline double
BpNode::getPiResidual (const BayesNode* destination)
{
return piResiduals_[getIndex(destination)];
}
inline double
BpNode::getLambdaResidual (const BayesNode* source)
{
return ldResiduals_[getIndex(source)];
}
inline int
BpNode::getIndex (const BayesNode* node) const
{
assert (node);
//assert (indexMap_.find(node->getVarId()) != indexMap_.end());
//return indexMap_.find(node->getVarId())->second;
for (unsigned i = 0; childs_->size(); i++) {
if ((*childs_)[i]->getVarId() == node->getVarId()) {
return i;
}
}
assert (false);
return -1;
}
#endif

View File

@ -0,0 +1,344 @@
#include "CFactorGraph.h"
#include "Factor.h"
#include "Distribution.h"
bool CFactorGraph::checkForIdenticalFactors_ = true;
CFactorGraph::CFactorGraph (const FactorGraph& fg)
{
groundFg_ = &fg;
freeColor_ = 0;
const FgVarSet& varNodes = fg.getVarNodes();
varSignatures_.reserve (varNodes.size());
for (unsigned i = 0; i < varNodes.size(); i++) {
unsigned c = (varNodes[i]->neighbors().size() * 2) + 1;
varSignatures_.push_back (Signature (c));
}
const FgFacSet& facNodes = fg.getFactorNodes();
factorSignatures_.reserve (facNodes.size());
for (unsigned i = 0; i < facNodes.size(); i++) {
unsigned c = facNodes[i]->neighbors().size() + 1;
factorSignatures_.push_back (Signature (c));
}
varColors_.resize (varNodes.size());
factorColors_.resize (facNodes.size());
setInitialColors();
createGroups();
}
CFactorGraph::~CFactorGraph (void)
{
for (unsigned i = 0; i < varClusters_.size(); i++) {
delete varClusters_[i];
}
for (unsigned i = 0; i < factorClusters_.size(); i++) {
delete factorClusters_[i];
}
}
void
CFactorGraph::setInitialColors (void)
{
// create the initial variable colors
VarColorMap colorMap;
const FgVarSet& varNodes = groundFg_->getVarNodes();
for (unsigned i = 0; i < varNodes.size(); i++) {
unsigned dsize = varNodes[i]->nrStates();
VarColorMap::iterator it = colorMap.find (dsize);
if (it == colorMap.end()) {
it = colorMap.insert (make_pair (
dsize, vector<Color> (dsize+1,-1))).first;
}
unsigned idx;
if (varNodes[i]->hasEvidence()) {
idx = varNodes[i]->getEvidence();
} else {
idx = dsize;
}
vector<Color>& stateColors = it->second;
if (stateColors[idx] == -1) {
stateColors[idx] = getFreeColor();
}
setColor (varNodes[i], stateColors[idx]);
}
const FgFacSet& facNodes = groundFg_->getFactorNodes();
if (checkForIdenticalFactors_) {
for (unsigned i = 0; i < facNodes.size() - 1; i++) {
// facNodes[i]->factor()->orderFactorVariables();
// FIXME
}
for (unsigned i = 0, s = facNodes.size(); i < s; i++) {
Distribution* dist1 = facNodes[i]->getDistribution();
for (unsigned j = 0; j < i; j++) {
Distribution* dist2 = facNodes[j]->getDistribution();
if (dist1 != dist2 && dist1->params == dist2->params) {
facNodes[i]->factor()->setDistribution (dist2);
// delete dist2;
break;
}
/*
if (ok) {
const FgVarSet& fiVars = factors[i]->getFgVarNodes();
const FgVarSet& fjVars = factors[j]->getFgVarNodes();
if (fiVars.size() != fjVars.size()) continue;
for (unsigned k = 0; k < fiVars.size(); k++) {
if (fiVars[k]->nrStates() != fjVars[k]->nrStates()) {
ok = false;
break;
}
}
}
*/
}
}
}
// create the initial factor colors
DistColorMap distColors;
for (unsigned i = 0; i < facNodes.size(); i++) {
const Distribution* dist = facNodes[i]->getDistribution();
DistColorMap::iterator it = distColors.find (dist);
if (it == distColors.end()) {
it = distColors.insert (make_pair (dist, getFreeColor())).first;
}
setColor (facNodes[i], it->second);
}
}
void
CFactorGraph::createGroups (void)
{
VarSignMap varGroups;
FacSignMap factorGroups;
unsigned nIters = 0;
bool groupsHaveChanged = true;
const FgVarSet& varNodes = groundFg_->getVarNodes();
const FgFacSet& facNodes = groundFg_->getFactorNodes();
while (groupsHaveChanged || nIters == 1) {
nIters ++;
unsigned prevFactorGroupsSize = factorGroups.size();
factorGroups.clear();
// set a new color to the factors with the same signature
for (unsigned i = 0; i < facNodes.size(); i++) {
const Signature& signature = getSignature (facNodes[i]);
FacSignMap::iterator it = factorGroups.find (signature);
if (it == factorGroups.end()) {
it = factorGroups.insert (make_pair (signature, FgFacSet())).first;
}
it->second.push_back (facNodes[i]);
}
for (FacSignMap::iterator it = factorGroups.begin();
it != factorGroups.end(); it++) {
Color newColor = getFreeColor();
FgFacSet& groupMembers = it->second;
for (unsigned i = 0; i < groupMembers.size(); i++) {
setColor (groupMembers[i], newColor);
}
}
// 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 Signature& signature = getSignature (varNodes[i]);
VarSignMap::iterator it = varGroups.find (signature);
if (it == varGroups.end()) {
it = varGroups.insert (make_pair (signature, FgVarSet())).first;
}
it->second.push_back (varNodes[i]);
}
for (VarSignMap::iterator it = varGroups.begin();
it != varGroups.end(); it++) {
Color newColor = getFreeColor();
FgVarSet& groupMembers = it->second;
for (unsigned i = 0; i < groupMembers.size(); i++) {
setColor (groupMembers[i], newColor);
}
}
groupsHaveChanged = prevVarGroupsSize != varGroups.size()
|| prevFactorGroupsSize != factorGroups.size();
}
//printGroups (varGroups, factorGroups);
createClusters (varGroups, factorGroups);
}
void
CFactorGraph::createClusters (const VarSignMap& varGroups,
const FacSignMap& factorGroups)
{
varClusters_.reserve (varGroups.size());
for (VarSignMap::const_iterator it = varGroups.begin();
it != varGroups.end(); it++) {
const FgVarSet& 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);
}
factorClusters_.reserve (factorGroups.size());
for (FacSignMap::const_iterator it = factorGroups.begin();
it != factorGroups.end(); it++) {
FgFacNode* groupFactor = it->second[0];
const FgVarSet& neighs = groupFactor->neighbors();
VarClusterSet 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);
}
factorClusters_.push_back (new FacCluster (it->second, varClusters));
}
}
const Signature&
CFactorGraph::getSignature (const FgVarNode* varNode)
{
Signature& sign = varSignatures_[varNode->getIndex()];
vector<Color>::iterator it = sign.colors.begin();
const FgFacSet& neighs = varNode->neighbors();
for (unsigned i = 0; i < neighs.size(); i++) {
*it = getColor (neighs[i]);
it ++;
*it = neighs[i]->factor()->getPositionOf (varNode->varId());
it ++;
}
*it = getColor (varNode);
return sign;
}
const Signature&
CFactorGraph::getSignature (const FgFacNode* facNode)
{
Signature& sign = factorSignatures_[facNode->getIndex()];
vector<Color>::iterator it = sign.colors.begin();
const FgVarSet& neighs = facNode->neighbors();
for (unsigned i = 0; i < neighs.size(); i++) {
*it = getColor (neighs[i]);
it ++;
}
*it = getColor (facNode);
return sign;
}
FactorGraph*
CFactorGraph::getCompressedFactorGraph (void)
{
FactorGraph* fg = new FactorGraph();
for (unsigned i = 0; i < varClusters_.size(); i++) {
FgVarNode* var = varClusters_[i]->getGroundFgVarNodes()[0];
FgVarNode* newVar = new FgVarNode (var);
varClusters_[i]->setRepresentativeVariable (newVar);
fg->addVariable (newVar);
}
for (unsigned i = 0; i < factorClusters_.size(); i++) {
const VarClusterSet& myVarClusters = factorClusters_[i]->getVarClusters();
VarNodes myGroundVars;
myGroundVars.reserve (myVarClusters.size());
for (unsigned j = 0; j < myVarClusters.size(); j++) {
FgVarNode* v = myVarClusters[j]->getRepresentativeVariable();
myGroundVars.push_back (v);
}
Factor* newFactor = new Factor (myGroundVars,
factorClusters_[i]->getGroundFactors()[0]->getDistribution());
FgFacNode* fn = new FgFacNode (newFactor);
factorClusters_[i]->setRepresentativeFactor (fn);
fg->addFactor (fn);
for (unsigned j = 0; j < myGroundVars.size(); j++) {
fg->addEdge (fn, static_cast<FgVarNode*> (myGroundVars[j]));
}
}
fg->setIndexes();
return fg;
}
unsigned
CFactorGraph::getGroundEdgeCount (const FacCluster* fc,
const VarCluster* vc) const
{
const FgFacSet& clusterGroundFactors = fc->getGroundFactors();
FgVarNode* varNode = vc->getGroundFgVarNodes()[0];
unsigned count = 0;
for (unsigned i = 0; i < clusterGroundFactors.size(); i++) {
if (clusterGroundFactors[i]->factor()->getPositionOf (varNode->varId()) != -1) {
count ++;
}
}
// CFgVarSet vars = vc->getGroundFgVarNodes();
// for (unsigned i = 1; i < vars.size(); i++) {
// FgVarNode* var = vc->getGroundFgVarNodes()[i];
// unsigned count2 = 0;
// for (unsigned i = 0; i < clusterGroundFactors.size(); i++) {
// if (clusterGroundFactors[i]->getPositionOf (var) != -1) {
// count2 ++;
// }
// }
// if (count != count2) { cout << "oops!" << endl; abort(); }
// }
return count;
}
void
CFactorGraph::printGroups (const VarSignMap& varGroups,
const FacSignMap& factorGroups) const
{
unsigned count = 1;
cout << "variable groups:" << endl;
for (VarSignMap::const_iterator it = varGroups.begin();
it != varGroups.end(); it++) {
const FgVarSet& 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 = factorGroups.begin();
it != factorGroups.end(); it++) {
const FgFacSet& 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,237 @@
#ifndef HORUS_CFACTORGRAPH_H
#define HORUS_CFACTORGRAPH_H
#include <unordered_map>
#include "FactorGraph.h"
#include "Factor.h"
#include "Shared.h"
class VarCluster;
class FacCluster;
class Distribution;
class Signature;
class SignatureHash;
typedef long Color;
typedef unordered_map<unsigned, vector<Color> > VarColorMap;
typedef unordered_map<const Distribution*, Color> DistColorMap;
typedef unordered_map<VarId, VarCluster*> VarId2VarCluster;
typedef vector<VarCluster*> VarClusterSet;
typedef vector<FacCluster*> FacClusterSet;
typedef unordered_map<Signature, FgVarSet, SignatureHash> VarSignMap;
typedef unordered_map<Signature, FgFacSet, SignatureHash> FacSignMap;
struct Signature {
Signature (unsigned size)
{
colors.resize (size);
}
bool operator< (const Signature& sig) const
{
if (colors.size() < sig.colors.size()) {
return true;
} else if (colors.size() > sig.colors.size()) {
return false;
} else {
for (unsigned i = 0; i < colors.size(); i++) {
if (colors[i] < sig.colors[i]) {
return true;
} else if (colors[i] > sig.colors[i]) {
return false;
}
}
}
return false;
}
bool operator== (const Signature& sig) const
{
if (colors.size() != sig.colors.size()) {
return false;
}
for (unsigned i = 0; i < colors.size(); i++) {
if (colors[i] != sig.colors[i]) {
return false;
}
}
return true;
}
vector<Color> colors;
};
struct SignatureHash {
size_t operator() (const Signature &sig) const
{
size_t val = hash<size_t>()(sig.colors.size());
for (unsigned i = 0; i < sig.colors.size(); i++) {
val ^= hash<size_t>()(sig.colors[i]);
}
return val;
}
};
class VarCluster
{
public:
VarCluster (const FgVarSet& vs)
{
for (unsigned i = 0; i < vs.size(); i++) {
groundVars_.push_back (vs[i]);
}
}
void addFacCluster (FacCluster* fc)
{
factorClusters_.push_back (fc);
}
const FacClusterSet& getFacClusters (void) const
{
return factorClusters_;
}
FgVarNode* getRepresentativeVariable (void) const { return representVar_; }
void setRepresentativeVariable (FgVarNode* v) { representVar_ = v; }
const FgVarSet& getGroundFgVarNodes (void) const { return groundVars_; }
private:
FgVarSet groundVars_;
FacClusterSet factorClusters_;
FgVarNode* representVar_;
};
class FacCluster
{
public:
FacCluster (const FgFacSet& groundFactors, const VarClusterSet& vcs)
{
groundFactors_ = groundFactors;
varClusters_ = vcs;
for (unsigned i = 0; i < varClusters_.size(); i++) {
varClusters_[i]->addFacCluster (this);
}
}
const VarClusterSet& getVarClusters (void) const
{
return varClusters_;
}
bool containsGround (const FgFacNode* fn)
{
for (unsigned i = 0; i < groundFactors_.size(); i++) {
if (groundFactors_[i] == fn) {
return true;
}
}
return false;
}
FgFacNode* getRepresentativeFactor (void) const
{
return representFactor_;
}
void setRepresentativeFactor (FgFacNode* fn)
{
representFactor_ = fn;
}
const FgFacSet& getGroundFactors (void) const
{
return groundFactors_;
}
private:
FgFacSet groundFactors_;
VarClusterSet varClusters_;
FgFacNode* representFactor_;
};
class CFactorGraph
{
public:
CFactorGraph (const FactorGraph&);
~CFactorGraph (void);
FactorGraph* getCompressedFactorGraph (void);
unsigned getGroundEdgeCount (const FacCluster*, const VarCluster*) const;
FgVarNode* getEquivalentVariable (VarId vid)
{
VarCluster* vc = vid2VarCluster_.find (vid)->second;
return vc->getRepresentativeVariable();
}
const VarClusterSet& getVariableClusters (void) { return varClusters_; }
const FacClusterSet& getFacClusters (void) { return factorClusters_; }
static void enableCheckForIdenticalFactors (void)
{
checkForIdenticalFactors_ = true;
}
static void disableCheckForIdenticalFactors (void)
{
checkForIdenticalFactors_ = false;
}
private:
void setInitialColors (void);
void createGroups (void);
void createClusters (const VarSignMap&, const FacSignMap&);
const Signature& getSignature (const FgVarNode*);
const Signature& getSignature (const FgFacNode*);
void printGroups (const VarSignMap&, const FacSignMap&) const;
Color getFreeColor (void) {
++ freeColor_;
return freeColor_ - 1;
}
Color getColor (const FgVarNode* vn) const
{
return varColors_[vn->getIndex()];
}
Color getColor (const FgFacNode* fn) const {
return factorColors_[fn->getIndex()];
}
void setColor (const FgVarNode* vn, Color c)
{
varColors_[vn->getIndex()] = c;
}
void setColor (const FgFacNode* fn, Color c)
{
factorColors_[fn->getIndex()] = c;
}
VarCluster* getVariableCluster (VarId vid) const
{
return vid2VarCluster_.find (vid)->second;
}
Color freeColor_;
vector<Color> varColors_;
vector<Color> factorColors_;
vector<Signature> varSignatures_;
vector<Signature> factorSignatures_;
VarClusterSet varClusters_;
FacClusterSet factorClusters_;
VarId2VarCluster vid2VarCluster_;
const FactorGraph* groundFg_;
bool static checkForIdenticalFactors_;
};
#endif // HORUS_CFACTORGRAPH_H

View File

@ -0,0 +1,263 @@
#include "CbpSolver.h"
CbpSolver::~CbpSolver (void)
{
delete lfg_;
delete factorGraph_;
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
links_.clear();
}
ParamSet
CbpSolver::getPosterioriOf (VarId vid)
{
FgVarNode* var = lfg_->getEquivalentVariable (vid);
ParamSet probs;
if (var->hasEvidence()) {
probs.resize (var->nrStates(), Util::noEvidence());
probs[var->getEvidence()] = Util::withEvidence();
} else {
probs.resize (var->nrStates(), Util::multIdenty());
const SpLinkSet& links = ninf(var)->getLinks();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < links.size(); i++) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links[i]);
Util::multiply (probs, l->getPoweredMessage());
}
Util::normalize (probs);
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < links.size(); i++) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links[i]);
Util::add (probs, l->getPoweredMessage());
}
Util::normalize (probs);
Util::fromLog (probs);
}
}
return probs;
}
ParamSet
CbpSolver::getJointDistributionOf (const VarIdSet& jointVarIds)
{
unsigned msgSize = 1;
vector<unsigned> dsizes (jointVarIds.size());
for (unsigned i = 0; i < jointVarIds.size(); i++) {
dsizes[i] = lfg_->getEquivalentVariable (jointVarIds[i])->nrStates();
msgSize *= dsizes[i];
}
unsigned reps = 1;
ParamSet jointDist (msgSize, Util::multIdenty());
for (int i = jointVarIds.size() - 1 ; i >= 0; i--) {
Util::multiply (jointDist, getPosterioriOf (jointVarIds[i]), reps);
reps *= dsizes[i];
}
return jointDist;
}
void
CbpSolver::initializeSolver (void)
{
unsigned nGroundVars, nGroundFacs, nWithoutNeighs;
if (COLLECT_STATISTICS) {
nGroundVars = factorGraph_->getVarNodes().size();
nGroundFacs = factorGraph_->getFactorNodes().size();
const FgVarSet& vars = factorGraph_->getVarNodes();
nWithoutNeighs = 0;
for (unsigned i = 0; i < vars.size(); i++) {
const FgFacSet& factors = vars[i]->neighbors();
if (factors.size() == 1 && factors[0]->neighbors().size() == 1) {
nWithoutNeighs ++;
}
}
}
lfg_ = new CFactorGraph (*factorGraph_);
// cout << "Uncompressed Factor Graph" << endl;
// factorGraph_->printGraphicalModel();
// factorGraph_->exportToGraphViz ("uncompressed_fg.dot");
factorGraph_ = lfg_->getCompressedFactorGraph();
if (COLLECT_STATISTICS) {
unsigned nClusterVars = factorGraph_->getVarNodes().size();
unsigned nClusterFacs = factorGraph_->getFactorNodes().size();
Statistics::updateCompressingStatistics (nGroundVars, nGroundFacs,
nClusterVars, nClusterFacs,
nWithoutNeighs);
}
// cout << "Compressed Factor Graph" << endl;
// factorGraph_->printGraphicalModel();
// factorGraph_->exportToGraphViz ("compressed_fg.dot");
// abort();
FgBpSolver::initializeSolver();
}
void
CbpSolver::createLinks (void)
{
const FacClusterSet fcs = lfg_->getFacClusters();
for (unsigned i = 0; i < fcs.size(); i++) {
const VarClusterSet vcs = fcs[i]->getVarClusters();
for (unsigned j = 0; j < vcs.size(); j++) {
unsigned c = lfg_->getGroundEdgeCount (fcs[i], vcs[j]);
links_.push_back (new CbpSolverLink (fcs[i]->getRepresentativeFactor(),
vcs[j]->getRepresentativeVariable(), c));
}
}
return;
}
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 (DL >= 2 && DL < 5) {
cout << "calculating " << links_[i]->toString() << endl;
}
}
return;
}
for (unsigned c = 0; c < links_.size(); c++) {
if (DL >= 2) {
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 (DL >= 2) {
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 FgFacSet& 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 (DL >= 2 && DL < 5) {
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 (DL >= 2 && DL < 5) {
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]);
}
}
}
}
ParamSet
CbpSolver::getVar2FactorMsg (const SpLink* link) const
{
ParamSet msg;
const FgVarNode* src = link->getVariable();
const FgFacNode* dst = link->getFactor();
const CbpSolverLink* l = static_cast<const CbpSolverLink*> (link);
if (src->hasEvidence()) {
msg.resize (src->nrStates(), Util::noEvidence());
double value = link->getMessage()[src->getEvidence()];
msg[src->getEvidence()] = Util::pow (value, l->getNumberOfEdges() - 1);
} else {
msg = link->getMessage();
Util::pow (msg, l->getNumberOfEdges() - 1);
}
if (DL >= 5) {
cout << " " << "init: " << Util::parametersToString (msg) << endl;
}
const SpLinkSet& links = ninf(src)->getLinks();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dst) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links[i]);
Util::multiply (msg, l->getPoweredMessage());
if (DL >= 5) {
cout << " msg from " << l->getFactor()->getLabel() << ": " ;
cout << Util::parametersToString (l->getPoweredMessage()) << endl;
}
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dst) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links[i]);
Util::add (msg, l->getPoweredMessage());
}
}
}
if (DL >= 5) {
cout << " result = " << Util::parametersToString (msg) << endl;
}
return msg;
}
void
CbpSolver::printLinkInformation (void) const
{
for (unsigned i = 0; i < links_.size(); i++) {
CbpSolverLink* l = static_cast<CbpSolverLink*> (links_[i]);
cout << l->toString() << ":" << endl;
cout << " curr msg = " ;
cout << Util::parametersToString (l->getMessage()) << endl;
cout << " next msg = " ;
cout << Util::parametersToString (l->getNextMessage()) << endl;
cout << " powered = " ;
cout << Util::parametersToString (l->getPoweredMessage()) << endl;
cout << " residual = " << l->getResidual() << endl;
}
}

View File

@ -0,0 +1,58 @@
#ifndef HORUS_CBP_H
#define HORUS_CBP_H
#include "FgBpSolver.h"
#include "CFactorGraph.h"
class Factor;
class CbpSolverLink : public SpLink
{
public:
CbpSolverLink (FgFacNode* fn, FgVarNode* vn, unsigned c) : SpLink (fn, vn)
{
edgeCount_ = c;
poweredMsg_.resize (vn->nrStates(), Util::one());
}
void updateMessage (void)
{
poweredMsg_ = *nextMsg_;
swap (currMsg_, nextMsg_);
msgSended_ = true;
Util::pow (poweredMsg_, edgeCount_);
}
unsigned getNumberOfEdges (void) const { return edgeCount_; }
const ParamSet& getPoweredMessage (void) const { return poweredMsg_; }
private:
ParamSet poweredMsg_;
unsigned edgeCount_;
};
class CbpSolver : public FgBpSolver
{
public:
CbpSolver (FactorGraph& fg) : FgBpSolver (fg) { }
~CbpSolver (void);
ParamSet getPosterioriOf (VarId);
ParamSet getJointDistributionOf (const VarIdSet&);
private:
void initializeSolver (void);
void createLinks (void);
void maxResidualSchedule (void);
ParamSet getVar2FactorMsg (const SpLink*) const;
void printLinkInformation (void) const;
CFactorGraph* lfg_;
};
#endif // HORUS_CBP_H

View File

@ -1,198 +0,0 @@
#include "CountingBP.h"
CountingBP::~CountingBP (void)
{
delete lfg_;
delete fg_;
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
links_.clear();
}
ParamSet
CountingBP::getPosterioriOf (Vid vid) const
{
FgVarNode* var = lfg_->getEquivalentVariable (vid);
ParamSet probs;
if (var->hasEvidence()) {
probs.resize (var->getDomainSize(), 0.0);
probs[var->getEvidence()] = 1.0;
} else {
probs.resize (var->getDomainSize(), 1.0);
CLinkSet links = varsI_[var->getIndex()]->getLinks();
for (unsigned i = 0; i < links.size(); i++) {
ParamSet msg = links[i]->getMessage();
CountingBPLink* l = static_cast<CountingBPLink*> (links[i]);
Util::pow (msg, l->getNumberOfEdges());
for (unsigned j = 0; j < msg.size(); j++) {
probs[j] *= msg[j];
}
}
Util::normalize (probs);
}
return probs;
}
void
CountingBP::initializeSolver (void)
{
lfg_ = new LiftedFG (*fg_);
unsigned nUncVars = fg_->getFgVarNodes().size();
unsigned nUncFactors = fg_->getFactors().size();
CFgVarSet vars = fg_->getFgVarNodes();
unsigned nNeighborLessVars = 0;
for (unsigned i = 0; i < vars.size(); i++) {
CFactorSet factors = vars[i]->getFactors();
if (factors.size() == 1 && factors[0]->getFgVarNodes().size() == 1) {
nNeighborLessVars ++;
}
}
// cout << "UNCOMPRESSED FACTOR GRAPH" << endl;
// fg_->printGraphicalModel();
fg_->exportToDotFormat ("uncompress.dot");
FactorGraph *temp;
temp = fg_;
fg_ = lfg_->getCompressedFactorGraph();
unsigned nCompVars = fg_->getFgVarNodes().size();
unsigned nCompFactors = fg_->getFactors().size();
Statistics::updateCompressingStats (nUncVars,
nUncFactors,
nCompVars,
nCompFactors,
nNeighborLessVars);
cout << "COMPRESSED FACTOR GRAPH" << endl;
fg_->printGraphicalModel();
//fg_->exportToDotFormat ("compress.dot");
SPSolver::initializeSolver();
}
void
CountingBP::createLinks (void)
{
const FactorClusterSet fcs = lfg_->getFactorClusters();
for (unsigned i = 0; i < fcs.size(); i++) {
const VarClusterSet vcs = fcs[i]->getVarClusters();
for (unsigned j = 0; j < vcs.size(); j++) {
unsigned c = lfg_->getGroundEdgeCount (fcs[i], vcs[j]);
links_.push_back (
new CountingBPLink (fcs[i]->getRepresentativeFactor(),
vcs[j]->getRepresentativeVariable(), c));
//cout << (links_.back())->toString() << " edge count =" << c << endl;
}
}
return;
}
void
CountingBP::deleteJunction (Factor* f, FgVarNode*)
{
f->freeDistribution();
}
void
CountingBP::maxResidualSchedule (void)
{
if (nIter_ == 1) {
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->setNextMessage (getFactor2VarMsg (links_[i]));
SortedOrder::iterator it = sortedOrder_.insert (links_[i]);
linkMap_.insert (make_pair (links_[i], it));
if (DL >= 2 && DL < 5) {
cout << "calculating " << links_[i]->toString() << endl;
}
}
return;
}
for (unsigned c = 0; c < links_.size(); c++) {
if (DL >= 2) {
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();
Link* link = *it;
if (DL >= 2) {
cout << "updating " << (*sortedOrder_.begin())->toString() << endl;
}
if (link->getResidual() < SolverOptions::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
CFactorSet factorNeighbors = link->getVariable()->getFactors();
for (unsigned i = 0; i < factorNeighbors.size(); i++) {
CLinkSet links = factorsI_[factorNeighbors[i]->getIndex()]->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (links[j]->getVariable() != link->getVariable()) { //FIXMEFIXME
if (DL >= 2 && DL < 5) {
cout << " calculating " << links[j]->toString() << endl;
}
links[j]->setNextMessage (getFactor2VarMsg (links[j]));
LinkMap::iterator iter = linkMap_.find (links[j]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (links[j]);
}
}
}
}
}
ParamSet
CountingBP::getVar2FactorMsg (const Link* link) const
{
const FgVarNode* src = link->getVariable();
const Factor* dest = link->getFactor();
ParamSet msg;
if (src->hasEvidence()) {
cout << "has evidence" << endl;
msg.resize (src->getDomainSize(), 0.0);
msg[src->getEvidence()] = link->getMessage()[src->getEvidence()];
cout << "-> " << link->getVariable()->getLabel() << " " << link->getFactor()->getLabel() << endl;
cout << "-> p2s " << Util::parametersToString (msg) << endl;
} else {
msg = link->getMessage();
}
const CountingBPLink* l = static_cast<const CountingBPLink*> (link);
Util::pow (msg, l->getNumberOfEdges() - 1);
CLinkSet links = varsI_[src->getIndex()]->getLinks();
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dest) {
ParamSet msgFromFactor = links[i]->getMessage();
CountingBPLink* l = static_cast<CountingBPLink*> (links[i]);
Util::pow (msgFromFactor, l->getNumberOfEdges());
for (unsigned j = 0; j < msgFromFactor.size(); j++) {
msg[j] *= msgFromFactor[j];
}
}
}
return msg;
}

View File

@ -1,45 +0,0 @@
#ifndef BP_COUNTING_BP_H
#define BP_COUNTING_BP_H
#include "SPSolver.h"
#include "LiftedFG.h"
class Factor;
class FgVarNode;
class CountingBPLink : public Link
{
public:
CountingBPLink (Factor* f, FgVarNode* v, unsigned c) : Link (f, v)
{
edgeCount_ = c;
}
unsigned getNumberOfEdges (void) const { return edgeCount_; }
private:
unsigned edgeCount_;
};
class CountingBP : public SPSolver
{
public:
CountingBP (FactorGraph& fg) : SPSolver (fg) { }
~CountingBP (void);
ParamSet getPosterioriOf (Vid) const;
private:
void initializeSolver (void);
void createLinks (void);
void deleteJunction (Factor*, FgVarNode*);
void maxResidualSchedule (void);
ParamSet getVar2FactorMsg (const Link*) const;
LiftedFG* lfg_;
};
#endif // BP_COUNTING_BP_H

View File

@ -1,5 +1,5 @@
#ifndef BP_CPT_ENTRY_H
#define BP_CPT_ENTRY_H
#ifndef HORUS_CPTENTRY_H
#define HORUS_CPTENTRY_H
#include <vector>
@ -39,5 +39,5 @@ class CptEntry
DConf conf_;
};
#endif //BP_CPT_ENTRY_H
#endif // HORUS_CPTENTRY_H

View File

@ -1,40 +0,0 @@
#include <vector>
#include <string>
#include <Distribution.h>
Distribution::Distribution (int id,
double* params,
int nParams,
vector<string> domain)
{
this->id = id;
this->params = params;
this->nParams = nParams;
this->domain = domain;
}
Distribution::Distribution (double* params,
int nParams,
vector<string> domain)
{
this->id = -1;
this->params = params;
this->nParams = nParams;
this->domain = domain;
}
/*
Distribution::~Distribution()
{
delete params;
for (unsigned int i = 0; i < cptEntries.size(); i++) {
delete cptEntries[i];
}
}
*/

View File

@ -1,5 +1,5 @@
#ifndef BP_DISTRIBUTION_H
#define BP_DISTRIBUTION_H
#ifndef HORUS_DISTRIBUTION_H
#define HORUS_DISTRIBUTION_H
#include <vector>
@ -11,18 +11,16 @@ using namespace std;
struct Distribution
{
public:
Distribution (unsigned id, bool shared = false)
Distribution (unsigned id)
{
this->id = id;
this->params = params;
this->shared = shared;
}
Distribution (const ParamSet& params, bool shared = false)
Distribution (const ParamSet& params, unsigned id = -1)
{
this->id = -1;
this->id = id;
this->params = params;
this->shared = shared;
}
void updateParameters (const ParamSet& params)
@ -33,11 +31,10 @@ struct Distribution
unsigned id;
ParamSet params;
vector<CptEntry> entries;
bool shared;
private:
DISALLOW_COPY_AND_ASSIGN (Distribution);
};
#endif //BP_DISTRIBUTION_H
#endif // HORUS_DISTRIBUTION_H

View File

@ -0,0 +1,322 @@
#include <limits>
#include "ElimGraph.h"
#include "BayesNet.h"
ElimHeuristic ElimGraph::elimHeuristic_ = MIN_NEIGHBORS;
ElimGraph::ElimGraph (const BayesNet& bayesNet)
{
const BnNodeSet& bnNodes = bayesNet.getBayesNodes();
for (unsigned i = 0; i < bnNodes.size(); i++) {
if (bnNodes[i]->hasEvidence() == false) {
addNode (new EgNode (bnNodes[i]));
}
}
for (unsigned i = 0; i < bnNodes.size(); i++) {
if (bnNodes[i]->hasEvidence() == false) {
EgNode* n = getEgNode (bnNodes[i]->varId());
const BnNodeSet& childs = bnNodes[i]->getChilds();
for (unsigned j = 0; j < childs.size(); j++) {
if (childs[j]->hasEvidence() == false) {
addEdge (n, getEgNode (childs[j]->varId()));
}
}
}
}
for (unsigned i = 0; i < bnNodes.size(); i++) {
vector<EgNode*> neighs;
const vector<BayesNode*>& parents = bnNodes[i]->getParents();
for (unsigned i = 0; i < parents.size(); i++) {
if (parents[i]->hasEvidence() == false) {
neighs.push_back (getEgNode (parents[i]->varId()));
}
}
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]);
}
}
}
}
}
setIndexes();
}
ElimGraph::~ElimGraph (void)
{
for (unsigned i = 0; i < nodes_.size(); i++) {
delete nodes_[i];
}
}
void
ElimGraph::addNode (EgNode* n)
{
nodes_.push_back (n);
vid2nodes_.insert (make_pair (n->varId(), n));
}
EgNode*
ElimGraph::getEgNode (VarId vid) const
{
unordered_map<VarId,EgNode*>::const_iterator it = vid2nodes_.find (vid);
if (it == vid2nodes_.end()) {
return 0;
} else {
return it->second;
}
}
VarIdSet
ElimGraph::getEliminatingOrder (const VarIdSet& exclude)
{
VarIdSet elimOrder;
marked_.resize (nodes_.size(), false);
for (unsigned i = 0; i < exclude.size(); i++) {
EgNode* node = getEgNode (exclude[i]);
assert (node);
marked_[*node] = true;
}
unsigned nVarsToEliminate = nodes_.size() - exclude.size();
for (unsigned i = 0; i < nVarsToEliminate; i++) {
EgNode* node = getLowestCostNode();
marked_[*node] = true;
elimOrder.push_back (node->varId());
connectAllNeighbors (node);
}
return elimOrder;
}
EgNode*
ElimGraph::getLowestCostNode (void) const
{
EgNode* bestNode = 0;
unsigned minCost = std::numeric_limits<unsigned>::max();
for (unsigned i = 0; i < nodes_.size(); i++) {
if (marked_[i]) continue;
unsigned cost = 0;
switch (elimHeuristic_) {
case MIN_NEIGHBORS:
cost = getNeighborsCost (nodes_[i]);
break;
case MIN_WEIGHT:
cost = getWeightCost (nodes_[i]);
break;
case MIN_FILL:
cost = getFillCost (nodes_[i]);
break;
case WEIGHTED_MIN_FILL:
cost = getWeightedFillCost (nodes_[i]);
break;
default:
assert (false);
}
if (cost < minCost) {
bestNode = nodes_[i];
minCost = cost;
}
}
assert (bestNode);
return bestNode;
}
unsigned
ElimGraph::getNeighborsCost (const EgNode* n) const
{
unsigned cost = 0;
const vector<EgNode*>& neighs = n->neighbors();
for (unsigned i = 0; i < neighs.size(); i++) {
if (marked_[*neighs[i]] == false) {
cost ++;
}
}
return cost;
}
unsigned
ElimGraph::getWeightCost (const EgNode* n) const
{
unsigned cost = 1;
const vector<EgNode*>& neighs = n->neighbors();
for (unsigned i = 0; i < neighs.size(); i++) {
if (marked_[*neighs[i]] == false) {
cost *= neighs[i]->nrStates();
}
}
return cost;
}
unsigned
ElimGraph::getFillCost (const EgNode* n) const
{
unsigned cost = 0;
const vector<EgNode*>& neighs = n->neighbors();
if (neighs.size() > 0) {
for (unsigned i = 0; i < neighs.size() - 1; i++) {
if (marked_[*neighs[i]] == true) continue;
for (unsigned j = i+1; j < neighs.size(); j++) {
if (marked_[*neighs[j]] == true) continue;
if (!neighbors (neighs[i], neighs[j])) {
cost ++;
}
}
}
}
return cost;
}
unsigned
ElimGraph::getWeightedFillCost (const EgNode* n) const
{
unsigned cost = 0;
const vector<EgNode*>& neighs = n->neighbors();
if (neighs.size() > 0) {
for (unsigned i = 0; i < neighs.size() - 1; i++) {
if (marked_[*neighs[i]] == true) continue;
for (unsigned j = i+1; j < neighs.size(); j++) {
if (marked_[*neighs[j]] == true) continue;
if (!neighbors (neighs[i], neighs[j])) {
cost += neighs[i]->nrStates() * neighs[j]->nrStates();
}
}
}
}
return cost;
}
void
ElimGraph::connectAllNeighbors (const EgNode* n)
{
const vector<EgNode*>& neighs = n->neighbors();
if (neighs.size() > 0) {
for (unsigned i = 0; i < neighs.size() - 1; i++) {
if (marked_[*neighs[i]] == true) continue;
for (unsigned j = i+1; j < neighs.size(); j++) {
if (marked_[*neighs[j]] == true) continue;
if (!neighbors (neighs[i], neighs[j])) {
addEdge (neighs[i], neighs[j]);
}
}
}
}
}
bool
ElimGraph::neighbors (const EgNode* n1, const EgNode* n2) const
{
const vector<EgNode*>& neighs = n1->neighbors();
for (unsigned i = 0; i < neighs.size(); i++) {
if (neighs[i] == n2) {
return true;
}
}
return false;
}
void
ElimGraph::setIndexes (void)
{
for (unsigned i = 0; i < nodes_.size(); i++) {
nodes_[i]->setIndex (i);
}
}
void
ElimGraph::printGraphicalModel (void) const
{
for (unsigned i = 0; i < nodes_.size(); i++) {
cout << "node " << nodes_[i]->label() << " neighs:" ;
vector<EgNode*> 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 VarIdSet& 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() << '"' ;
if (nodes_[i]->hasEvidence()) {
out << " [style=filled, fillcolor=yellow]" << endl;
} else {
out << 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++) {
vector<EgNode*> 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();
}

View File

@ -0,0 +1,76 @@
#ifndef HORUS_ELIMGRAPH_H
#define HORUS_ELIMGRAPH_H
#include "unordered_map"
#include "FactorGraph.h"
#include "Shared.h"
using namespace std;
enum ElimHeuristic
{
MIN_NEIGHBORS,
MIN_WEIGHT,
MIN_FILL,
WEIGHTED_MIN_FILL
};
class EgNode : public VarNode {
public:
EgNode (VarNode* var) : VarNode (var) { }
void addNeighbor (EgNode* n)
{
neighs_.push_back (n);
}
const vector<EgNode*>& neighbors (void) const { return neighs_; }
private:
vector<EgNode*> neighs_;
};
class ElimGraph
{
public:
ElimGraph (const BayesNet&);
~ElimGraph (void);
void addEdge (EgNode* n1, EgNode* n2)
{
assert (n1 != n2);
n1->addNeighbor (n2);
n2->addNeighbor (n1);
}
void addNode (EgNode*);
EgNode* getEgNode (VarId) const;
VarIdSet getEliminatingOrder (const VarIdSet&);
void printGraphicalModel (void) const;
void exportToGraphViz (const char*, bool = true,
const VarIdSet& = VarIdSet()) const;
void setIndexes();
static void setEliminationHeuristic (ElimHeuristic h)
{
elimHeuristic_ = h;
}
private:
EgNode* getLowestCostNode (void) const;
unsigned getNeighborsCost (const EgNode*) const;
unsigned getWeightCost (const EgNode*) const;
unsigned getFillCost (const EgNode*) const;
unsigned getWeightedFillCost (const EgNode*) const;
void connectAllNeighbors (const EgNode*);
bool neighbors (const EgNode*, const EgNode*) const;
vector<EgNode*> nodes_;
vector<bool> marked_;
unordered_map<VarId,EgNode*> vid2nodes_;
static ElimHeuristic elimHeuristic_;
};
#endif // HORUS_ELIMGRAPH_H

View File

@ -1,33 +1,38 @@
#include <cstdlib>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <sstream>
#include "Factor.h"
#include "FgVarNode.h"
#include "StatesIndexer.h"
Factor::Factor (const Factor& g)
{
copyFactor (g);
copyFromFactor (g);
}
Factor::Factor (FgVarNode* var)
Factor::Factor (VarId vid, unsigned nStates)
{
Factor (FgVarSet() = {var});
varids_.push_back (vid);
ranges_.push_back (nStates);
dist_ = new Distribution (ParamSet (nStates, 1.0));
}
Factor::Factor (const FgVarSet& vars)
Factor::Factor (const VarNodes& vars)
{
vars_ = vars;
int nParams = 1;
for (unsigned i = 0; i < vars_.size(); i++) {
nParams *= vars_[i]->getDomainSize();
for (unsigned i = 0; i < vars.size(); i++) {
varids_.push_back (vars[i]->varId());
ranges_.push_back (vars[i]->nrStates());
nParams *= vars[i]->nrStates();
}
// create a uniform distribution
double val = 1.0 / nParams;
@ -36,29 +41,44 @@ Factor::Factor (const FgVarSet& vars)
Factor::Factor (FgVarNode* var,
const ParamSet& params)
Factor::Factor (VarId vid, unsigned nStates, const ParamSet& params)
{
vars_.push_back (var);
varids_.push_back (vid);
ranges_.push_back (nStates);
dist_ = new Distribution (params);
}
Factor::Factor (FgVarSet& vars,
Distribution* dist)
Factor::Factor (VarNodes& vars, Distribution* dist)
{
vars_ = vars;
for (unsigned i = 0; i < vars.size(); i++) {
varids_.push_back (vars[i]->varId());
ranges_.push_back (vars[i]->nrStates());
}
dist_ = dist;
}
Factor::Factor (const FgVarSet& vars,
Factor::Factor (const VarNodes& vars, const ParamSet& params)
{
for (unsigned i = 0; i < vars.size(); i++) {
varids_.push_back (vars[i]->varId());
ranges_.push_back (vars[i]->nrStates());
}
dist_ = new Distribution (params);
}
Factor::Factor (const VarIdSet& vids,
const Ranges& ranges,
const ParamSet& params)
{
vars_ = vars;
dist_ = new Distribution (params);
varids_ = vids;
ranges_ = ranges;
dist_ = new Distribution (params);
}
@ -73,9 +93,10 @@ Factor::setParameters (const ParamSet& params)
void
Factor::copyFactor (const Factor& g)
Factor::copyFromFactor (const Factor& g)
{
vars_ = g.getFgVarNodes();
varids_ = g.getVarIds();
ranges_ = g.getRanges();
dist_ = new Distribution (g.getDistribution()->params);
}
@ -84,50 +105,43 @@ Factor::copyFactor (const Factor& g)
void
Factor::multiplyByFactor (const Factor& g, const vector<CptEntry>* entries)
{
if (vars_.size() == 0) {
copyFactor (g);
if (varids_.size() == 0) {
copyFromFactor (g);
return;
}
const FgVarSet& gVs = g.getFgVarNodes();
const ParamSet& gPs = g.getParameters();
const VarIdSet& gvarids = g.getVarIds();
const Ranges& granges = g.getRanges();
const ParamSet& gparams = g.getParameters();
bool factorsAreEqual = true;
if (gVs.size() == vars_.size()) {
for (unsigned i = 0; i < vars_.size(); i++) {
if (gVs[i] != vars_[i]) {
factorsAreEqual = false;
break;
}
}
} else {
factorsAreEqual = false;
}
if (factorsAreEqual) {
if (varids_ == gvarids) {
// optimization: if the factors contain the same set of variables,
// we can do 1 to 1 operations on the parameteres
for (unsigned i = 0; i < dist_->params.size(); i++) {
dist_->params[i] *= gPs[i];
// we can do a 1 to 1 operation on the parameters
switch (NSPACE) {
case NumberSpace::NORMAL:
Util::multiply (dist_->params, gparams);
break;
case NumberSpace::LOGARITHM:
Util::add (dist_->params, gparams);
}
} else {
bool hasCommonVars = false;
vector<unsigned> gVsIndexes;
for (unsigned i = 0; i < gVs.size(); i++) {
int idx = getIndexOf (gVs[i]);
if (idx == -1) {
insertVariable (gVs[i]);
gVsIndexes.push_back (vars_.size() - 1);
vector<unsigned> gvarpos;
for (unsigned i = 0; i < gvarids.size(); i++) {
int pos = getPositionOf (gvarids[i]);
if (pos == -1) {
insertVariable (gvarids[i], granges[i]);
gvarpos.push_back (varids_.size() - 1);
} else {
hasCommonVars = true;
gVsIndexes.push_back (idx);
gvarpos.push_back (pos);
}
}
if (hasCommonVars) {
vector<unsigned> gVsOffsets (gVs.size());
gVsOffsets[gVs.size() - 1] = 1;
for (int i = gVs.size() - 2; i >= 0; i--) {
gVsOffsets[i] = gVsOffsets[i + 1] * gVs[i + 1]->getDomainSize();
vector<unsigned> gvaroffsets (gvarids.size());
gvaroffsets[gvarids.size() - 1] = 1;
for (int i = gvarids.size() - 2; i >= 0; i--) {
gvaroffsets[i] = gvaroffsets[i + 1] * granges[i + 1];
}
if (entries == 0) {
@ -137,50 +151,88 @@ Factor::multiplyByFactor (const Factor& g, const vector<CptEntry>* entries)
for (unsigned i = 0; i < entries->size(); i++) {
unsigned idx = 0;
const DConf& conf = (*entries)[i].getDomainConfiguration();
for (unsigned j = 0; j < gVsIndexes.size(); j++) {
idx += gVsOffsets[j] * conf[ gVsIndexes[j] ];
for (unsigned j = 0; j < gvarpos.size(); j++) {
idx += gvaroffsets[j] * conf[ gvarpos[j] ];
}
switch (NSPACE) {
case NumberSpace::NORMAL:
dist_->params[i] *= gparams[idx];
break;
case NumberSpace::LOGARITHM:
dist_->params[i] += gparams[idx];
}
dist_->params[i] = dist_->params[i] * gPs[idx];
}
} else {
// optimization: if the original factors doesn't have common variables,
// we don't need to marry the states of the common variables
unsigned count = 0;
for (unsigned i = 0; i < dist_->params.size(); i++) {
dist_->params[i] *= gPs[count];
switch (NSPACE) {
case NumberSpace::NORMAL:
dist_->params[i] *= gparams[count];
break;
case NumberSpace::LOGARITHM:
dist_->params[i] += gparams[count];
}
count ++;
if (count >= gPs.size()) {
if (count >= gparams.size()) {
count = 0;
}
}
}
}
dist_->entries.clear();
}
void
Factor::insertVariable (FgVarNode* var)
Factor::insertVariable (VarId vid, unsigned nStates)
{
assert (getIndexOf (var) == -1);
assert (getPositionOf (vid) == -1);
ParamSet newPs;
newPs.reserve (dist_->params.size() * var->getDomainSize());
newPs.reserve (dist_->params.size() * nStates);
for (unsigned i = 0; i < dist_->params.size(); i++) {
for (unsigned j = 0; j < var->getDomainSize(); j++) {
for (unsigned j = 0; j < nStates; j++) {
newPs.push_back (dist_->params[i]);
}
}
vars_.push_back (var);
varids_.push_back (vid);
ranges_.push_back (nStates);
dist_->updateParameters (newPs);
dist_->entries.clear();
}
void
Factor::removeVariable (const FgVarNode* var)
Factor::removeAllVariablesExcept (VarId vid)
{
int varIndex = getIndexOf (var);
assert (varIndex >= 0 && varIndex < (int)vars_.size());
assert (getPositionOf (vid) != -1);
while (varids_.back() != vid) {
removeLastVariable();
}
while (varids_.front() != vid) {
removeFirstVariable();
}
}
void
Factor::removeVariable (VarId vid)
{
int pos = getPositionOf (vid);
assert (pos != -1);
if (vid == varids_.back()) {
removeLastVariable(); // optimization
return;
}
if (vid == varids_.front()) {
removeFirstVariable(); // optimization
return;
}
// number of parameters separating a different state of `var',
// with the states of the remaining variables fixed
@ -190,36 +242,36 @@ Factor::removeVariable (const FgVarNode* var)
// on the left of `var', with the states of the remaining vars fixed
unsigned leftVarOffset = 1;
for (int i = vars_.size() - 1; i > varIndex; i--) {
varOffset *= vars_[i]->getDomainSize();
leftVarOffset *= vars_[i]->getDomainSize();
for (int i = varids_.size() - 1; i > pos; i--) {
varOffset *= ranges_[i];
leftVarOffset *= ranges_[i];
}
leftVarOffset *= vars_[varIndex]->getDomainSize();
leftVarOffset *= ranges_[pos];
unsigned offset = 0;
unsigned count1 = 0;
unsigned count2 = 0;
unsigned newPsSize = dist_->params.size() / vars_[varIndex]->getDomainSize();
unsigned newPsSize = dist_->params.size() / ranges_[pos];
ParamSet newPs;
newPs.reserve (newPsSize);
// stringstream ss;
// ss << "marginalizing " << vars_[varIndex]->getLabel();
// ss << " from factor " << getLabel() << endl;
while (newPs.size() < newPsSize) {
// ss << " sum = ";
double sum = 0.0;
for (unsigned i = 0; i < vars_[varIndex]->getDomainSize(); i++) {
// if (i != 0) ss << " + ";
// ss << dist_->params[offset];
sum += dist_->params[offset];
double sum = Util::addIdenty();
for (unsigned i = 0; i < ranges_[pos]; i++) {
switch (NSPACE) {
case NumberSpace::NORMAL:
sum += dist_->params[offset];
break;
case NumberSpace::LOGARITHM:
Util::logSum (sum, dist_->params[offset]);
}
offset += varOffset;
}
newPs.push_back (sum);
count1 ++;
if (varIndex == (int)vars_.size() - 1) {
offset = count1 * vars_[varIndex]->getDomainSize();
if (pos == (int)varids_.size() - 1) {
offset = count1 * ranges_[pos];
} else {
if (((offset - varOffset + 1) % leftVarOffset) == 0) {
count1 = 0;
@ -227,11 +279,200 @@ Factor::removeVariable (const FgVarNode* var)
}
offset = (leftVarOffset * count2) + count1;
}
// ss << " = " << sum << endl;
}
// cout << ss.str() << endl;
vars_.erase (vars_.begin() + varIndex);
varids_.erase (varids_.begin() + pos);
ranges_.erase (ranges_.begin() + pos);
dist_->updateParameters (newPs);
dist_->entries.clear();
}
void
Factor::removeFirstVariable (void)
{
ParamSet& params = dist_->params;
unsigned nStates = ranges_.front();
unsigned sep = params.size() / nStates;
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = sep; i < params.size(); i++) {
params[i % sep] += params[i];
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = sep; i < params.size(); i++) {
Util::logSum (params[i % sep], params[i]);
}
}
params.resize (sep);
varids_.erase (varids_.begin());
ranges_.erase (ranges_.begin());
dist_->entries.clear();
}
void
Factor::removeLastVariable (void)
{
ParamSet& params = dist_->params;
unsigned nStates = ranges_.back();
unsigned idx1 = 0;
unsigned idx2 = 0;
switch (NSPACE) {
case NumberSpace::NORMAL:
while (idx1 < params.size()) {
params[idx2] = params[idx1];
idx1 ++;
for (unsigned j = 1; j < nStates; j++) {
params[idx2] += params[idx1];
idx1 ++;
}
idx2 ++;
}
break;
case NumberSpace::LOGARITHM:
while (idx1 < params.size()) {
params[idx2] = params[idx1];
idx1 ++;
for (unsigned j = 1; j < nStates; j++) {
Util::logSum (params[idx2], params[idx1]);
idx1 ++;
}
idx2 ++;
}
}
params.resize (idx2);
varids_.pop_back();
ranges_.pop_back();
dist_->entries.clear();
}
void
Factor::orderVariables (void)
{
VarIdSet sortedVarIds = varids_;
sort (sortedVarIds.begin(), sortedVarIds.end());
orderVariables (sortedVarIds);
}
void
Factor::orderVariables (const VarIdSet& newVarIdOrder)
{
assert (newVarIdOrder.size() == varids_.size());
if (newVarIdOrder == varids_) {
return;
}
Ranges newRangeOrder;
for (unsigned i = 0; i < newVarIdOrder.size(); i++) {
unsigned pos = getPositionOf (newVarIdOrder[i]);
newRangeOrder.push_back (ranges_[pos]);
}
vector<unsigned> positions;
for (unsigned i = 0; i < newVarIdOrder.size(); i++) {
positions.push_back (getPositionOf (newVarIdOrder[i]));
}
unsigned N = ranges_.size();
ParamSet newPs (dist_->params.size());
for (unsigned i = 0; i < dist_->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]];
}
newPs[new_li] = dist_->params[i];
}
varids_ = newVarIdOrder;
ranges_ = newRangeOrder;
dist_->params = newPs;
dist_->entries.clear();
}
void
Factor::removeInconsistentEntries (VarId vid, unsigned evidence)
{
int pos = getPositionOf (vid);
assert (pos != -1);
ParamSet newPs;
newPs.reserve (dist_->params.size() / ranges_[pos]);
StatesIndexer idx (ranges_);
for (unsigned i = 0; i < evidence; i++) {
idx.incrementState (pos);
}
while (idx.valid()) {
newPs.push_back (dist_->params[idx.getLinearIndex()]);
idx.nextSameState (pos);
}
varids_.erase (varids_.begin() + pos);
ranges_.erase (ranges_.begin() + pos);
dist_->updateParameters (newPs);
dist_->entries.clear();
}
string
Factor::getLabel (void) const
{
stringstream ss;
ss << "f(" ;
for (unsigned i = 0; i < varids_.size(); i++) {
if (i != 0) ss << "," ;
ss << VarNode (varids_[i], ranges_[i]).label();
}
ss << ")" ;
return ss.str();
}
void
Factor::printFactor (void) const
{
VarNodes vars;
for (unsigned i = 0; i < varids_.size(); i++) {
vars.push_back (new VarNode (varids_[i], ranges_[i]));
}
vector<string> jointStrings = Util::getJointStateStrings (vars);
for (unsigned i = 0; i < dist_->params.size(); i++) {
cout << "f(" << jointStrings[i] << ")" ;
cout << " = " << dist_->params[i] << endl;
}
for (unsigned i = 0; i < vars.size(); i++) {
delete vars[i];
}
}
int
Factor::getPositionOf (VarId vid) const
{
for (unsigned i = 0; i < varids_.size(); i++) {
if (varids_[i] == vid) {
return i;
}
}
return -1;
}
@ -242,21 +483,20 @@ Factor::getCptEntries (void) const
if (dist_->entries.size() == 0) {
vector<DConf> confs (dist_->params.size());
for (unsigned i = 0; i < dist_->params.size(); i++) {
confs[i].resize (vars_.size());
confs[i].resize (varids_.size());
}
unsigned nReps = 1;
for (int i = vars_.size() - 1; i >= 0; i--) {
for (int i = varids_.size() - 1; i >= 0; i--) {
unsigned index = 0;
while (index < dist_->params.size()) {
for (unsigned j = 0; j < vars_[i]->getDomainSize(); j++) {
for (unsigned j = 0; j < ranges_[i]; j++) {
for (unsigned r = 0; r < nReps; r++) {
confs[index][i] = j;
confs[index][i] = j;
index++;
}
}
}
nReps *= vars_[i]->getDomainSize();
nReps *= ranges_[i];
}
dist_->entries.clear();
dist_->entries.reserve (dist_->params.size());
@ -267,53 +507,3 @@ Factor::getCptEntries (void) const
return dist_->entries;
}
string
Factor::getLabel (void) const
{
stringstream ss;
ss << "Φ(" ;
for (unsigned i = 0; i < vars_.size(); i++) {
if (i != 0) ss << "," ;
ss << vars_[i]->getLabel();
}
ss << ")" ;
return ss.str();
}
void
Factor::printFactor (void)
{
stringstream ss;
ss << getLabel() << endl;
ss << "--------------------" << endl;
VarSet vs;
for (unsigned i = 0; i < vars_.size(); i++) {
vs.push_back (vars_[i]);
}
vector<string> domainConfs = Util::getInstantiations (vs);
const vector<CptEntry>& entries = getCptEntries();
for (unsigned i = 0; i < entries.size(); i++) {
ss << "Φ(" << domainConfs[i] << ")" ;
unsigned idx = entries[i].getParameterIndex();
ss << " = " << dist_->params[idx] << endl;
}
cout << ss.str();
}
int
Factor::getIndexOf (const FgVarNode* var) const
{
for (unsigned i = 0; i < vars_.size(); i++) {
if (vars_[i] == var) {
return i;
}
}
return -1;
}

View File

@ -1,48 +1,69 @@
#ifndef BP_FACTOR_H
#define BP_FACTOR_H
#ifndef HORUS_FACTOR_H
#define HORUS_FACTOR_H
#include <vector>
#include "Distribution.h"
#include "CptEntry.h"
#include "VarNode.h"
using namespace std;
class FgVarNode;
class Distribution;
class Factor
{
public:
Factor (void) { }
Factor (const Factor&);
Factor (FgVarNode*);
Factor (CFgVarSet);
Factor (FgVarNode*, const ParamSet&);
Factor (FgVarSet&, Distribution*);
Factor (CFgVarSet, CParamSet);
Factor (VarId, unsigned);
Factor (const VarNodes&);
Factor (VarId, unsigned, const ParamSet&);
Factor (VarNodes&, Distribution*);
Factor (const VarNodes&, const ParamSet&);
Factor (const VarIdSet&, const Ranges&, const ParamSet&);
void setParameters (CParamSet);
void copyFactor (const Factor& f);
void multiplyByFactor (const Factor& f, const vector<CptEntry>* = 0);
void insertVariable (FgVarNode* index);
void removeVariable (const FgVarNode* var);
const vector<CptEntry>& getCptEntries (void) const;
void setParameters (const ParamSet&);
void copyFromFactor (const Factor& f);
void multiplyByFactor (const Factor&, const vector<CptEntry>* = 0);
void insertVariable (VarId, unsigned);
void removeAllVariablesExcept (VarId);
void removeVariable (VarId);
void removeFirstVariable (void);
void removeLastVariable (void);
void orderVariables (void);
void orderVariables (const VarIdSet&);
void removeInconsistentEntries (VarId, unsigned);
string getLabel (void) const;
void printFactor (void);
void printFactor (void) const;
int getPositionOf (VarId) const;
const vector<CptEntry>& getCptEntries (void) const;
CFgVarSet getFgVarNodes (void) const { return vars_; }
CParamSet getParameters (void) const { return dist_->params; }
Distribution* getDistribution (void) const { return dist_; }
unsigned getIndex (void) const { return index_; }
void setIndex (unsigned index) { index_ = index; }
void freeDistribution (void) { delete dist_; dist_ = 0;}
int getIndexOf (const FgVarNode*) const;
const VarIdSet& getVarIds (void) const { return varids_; }
const Ranges& getRanges (void) const { return ranges_; }
const ParamSet& getParameters (void) const { return dist_->params; }
Distribution* getDistribution (void) const { return dist_; }
unsigned nrVariables (void) const { return varids_.size(); }
unsigned nrParameters() const { return dist_->params.size(); }
void setDistribution (Distribution* dist)
{
dist_ = dist;
}
void freeDistribution (void)
{
delete dist_;
dist_ = 0;
}
private:
FgVarSet vars_;
Distribution* dist_;
unsigned index_;
VarIdSet varids_;
Ranges ranges_;
Distribution* dist_;
};
#endif //BP_FACTOR_H
#endif // HORUS_FACTOR_H

View File

@ -1,20 +1,50 @@
#include <cstdlib>
#include <vector>
#include <set>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include "FactorGraph.h"
#include "FgVarNode.h"
#include "Factor.h"
#include "BayesNet.h"
FactorGraph::FactorGraph (const char* fileName)
FactorGraph::FactorGraph (const BayesNet& bn)
{
ifstream is (fileName);
const BnNodeSet& nodes = bn.getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
FgVarNode* varNode = new FgVarNode (nodes[i]);
addVariable (varNode);
}
for (unsigned i = 0; i < nodes.size(); i++) {
const BnNodeSet& parents = nodes[i]->getParents();
if (!(nodes[i]->hasEvidence() && parents.size() == 0)) {
VarNodes neighs;
neighs.push_back (varNodes_[nodes[i]->getIndex()]);
for (unsigned j = 0; j < parents.size(); j++) {
neighs.push_back (varNodes_[parents[j]->getIndex()]);
}
FgFacNode* fn = new FgFacNode (
new Factor (neighs, nodes[i]->getDistribution()));
addFactor (fn);
for (unsigned j = 0; j < neighs.size(); j++) {
addEdge (fn, static_cast<FgVarNode*> (neighs[j]));
}
}
}
setIndexes();
}
void
FactorGraph::readFromUaiFormat (const char* fileName)
{
ifstream is (fileName);
if (!is.is_open()) {
cerr << "error: cannot read from file " + std::string (fileName) << endl;
abort();
@ -29,90 +59,159 @@ FactorGraph::FactorGraph (const char* fileName)
}
while (is.peek() == '#' || is.peek() == '\n') getline (is, line);
int nVars;
unsigned nVars;
is >> nVars;
while (is.peek() == '#' || is.peek() == '\n') getline (is, line);
vector<int> domainSizes (nVars);
for (int i = 0; i < nVars; i++) {
int ds;
for (unsigned i = 0; i < nVars; i++) {
unsigned ds;
is >> ds;
domainSizes[i] = ds;
}
while (is.peek() == '#' || is.peek() == '\n') getline (is, line);
for (int i = 0; i < nVars; i++) {
for (unsigned i = 0; i < nVars; i++) {
addVariable (new FgVarNode (i, domainSizes[i]));
}
int nFactors;
unsigned nFactors;
is >> nFactors;
for (int i = 0; i < nFactors; i++) {
for (unsigned i = 0; i < nFactors; i++) {
while (is.peek() == '#' || is.peek() == '\n') getline (is, line);
int nFactorVars;
unsigned nFactorVars;
is >> nFactorVars;
FgVarSet factorVars;
for (int j = 0; j < nFactorVars; j++) {
int vid;
VarNodes neighs;
for (unsigned j = 0; j < nFactorVars; j++) {
unsigned vid;
is >> vid;
FgVarNode* var = getFgVarNode (vid);
if (!var) {
FgVarNode* neigh = getFgVarNode (vid);
if (!neigh) {
cerr << "error: invalid variable identifier (" << vid << ")" << endl;
abort();
}
factorVars.push_back (var);
neighs.push_back (neigh);
}
Factor* f = new Factor (factorVars);
factors_.push_back (f);
for (unsigned j = 0; j < factorVars.size(); j++) {
factorVars[j]->addFactor (f);
FgFacNode* fn = new FgFacNode (new Factor (neighs));
addFactor (fn);
for (unsigned j = 0; j < neighs.size(); j++) {
addEdge (fn, static_cast<FgVarNode*> (neighs[j]));
}
}
for (int i = 0; i < nFactors; i++) {
for (unsigned i = 0; i < nFactors; i++) {
while (is.peek() == '#' || is.peek() == '\n') getline (is, line);
int nParams;
unsigned nParams;
is >> nParams;
if (facNodes_[i]->getParameters().size() != nParams) {
cerr << "error: invalid number of parameters for factor " ;
cerr << facNodes_[i]->getLabel() ;
cerr << ", expected: " << facNodes_[i]->getParameters().size();
cerr << ", given: " << nParams << endl;
abort();
}
ParamSet params (nParams);
for (int j = 0; j < nParams; j++) {
for (unsigned j = 0; j < nParams; j++) {
double param;
is >> param;
params[j] = param;
}
factors_[i]->setParameters (params);
if (NSPACE == NumberSpace::LOGARITHM) {
Util::toLog (params);
}
facNodes_[i]->factor()->setParameters (params);
}
is.close();
for (unsigned i = 0; i < varNodes_.size(); i++) {
varNodes_[i]->setIndex (i);
}
setIndexes();
}
FactorGraph::FactorGraph (const BayesNet& bn)
void
FactorGraph::readFromLibDaiFormat (const char* fileName)
{
const BnNodeSet& nodes = bn.getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
FgVarNode* varNode = new FgVarNode (nodes[i]);
varNode->setIndex (i);
addVariable (varNode);
ifstream is (fileName);
if (!is.is_open()) {
cerr << "error: cannot read from file " + std::string (fileName) << endl;
abort();
}
for (unsigned i = 0; i < nodes.size(); i++) {
const BnNodeSet& parents = nodes[i]->getParents();
if (!(nodes[i]->hasEvidence() && parents.size() == 0)) {
FgVarSet factorVars = { varNodes_[nodes[i]->getIndex()] };
for (unsigned j = 0; j < parents.size(); j++) {
factorVars.push_back (varNodes_[parents[j]->getIndex()]);
}
Factor* f = new Factor (factorVars, nodes[i]->getDistribution());
factors_.push_back (f);
for (unsigned j = 0; j < factorVars.size(); j++) {
factorVars[j]->addFactor (f);
string line;
unsigned nFactors;
while ((is.peek()) == '#') getline (is, line);
is >> nFactors;
if (is.fail()) {
cerr << "error: cannot read the number of factors" << endl;
abort();
}
getline (is, line);
if (is.fail() || line.size() > 0) {
cerr << "error: cannot read the number of factors" << endl;
abort();
}
for (unsigned i = 0; i < nFactors; i++) {
unsigned nVars;
while ((is.peek()) == '#') getline (is, line);
is >> nVars;
VarIdSet vids;
for (unsigned j = 0; j < nVars; j++) {
VarId vid;
while ((is.peek()) == '#') getline (is, line);
is >> vid;
vids.push_back (vid);
}
VarNodes neighs;
unsigned nParams = 1;
for (unsigned j = 0; j < nVars; j++) {
unsigned dsize;
while ((is.peek()) == '#') getline (is, line);
is >> dsize;
FgVarNode* var = getFgVarNode (vids[j]);
if (var == 0) {
var = new FgVarNode (vids[j], dsize);
addVariable (var);
} else {
if (var->nrStates() != dsize) {
cerr << "error: variable `" << vids[j] << "' appears in two or " ;
cerr << "more factors with different domain sizes" << endl;
}
}
neighs.push_back (var);
nParams *= var->nrStates();
}
ParamSet params (nParams, 0);
unsigned nNonzeros;
while ((is.peek()) == '#')
getline (is, line);
is >> nNonzeros;
for (unsigned j = 0; j < nNonzeros; j++) {
unsigned index;
Param val;
while ((is.peek()) == '#') getline (is, line);
is >> index;
while ((is.peek()) == '#') getline (is, line);
is >> val;
params[index] = val;
}
reverse (neighs.begin(), neighs.end());
if (NSPACE == NumberSpace::LOGARITHM) {
Util::toLog (params);
}
FgFacNode* fn = new FgFacNode (new Factor (neighs, params));
addFactor (fn);
for (unsigned j = 0; j < neighs.size(); j++) {
addEdge (fn, static_cast<FgVarNode*> (neighs[j]));
}
}
is.close();
setIndexes();
}
@ -122,82 +221,63 @@ FactorGraph::~FactorGraph (void)
for (unsigned i = 0; i < varNodes_.size(); i++) {
delete varNodes_[i];
}
for (unsigned i = 0; i < factors_.size(); i++) {
delete factors_[i];
for (unsigned i = 0; i < facNodes_.size(); i++) {
delete facNodes_[i];
}
}
void
FactorGraph::addVariable (FgVarNode* varNode)
FactorGraph::addVariable (FgVarNode* vn)
{
varNodes_.push_back (varNode);
varNode->setIndex (varNodes_.size() - 1);
indexMap_.insert (make_pair (varNode->getVarId(), varNodes_.size() - 1));
varNodes_.push_back (vn);
vn->setIndex (varNodes_.size() - 1);
indexMap_.insert (make_pair (vn->varId(), varNodes_.size() - 1));
}
void
FactorGraph::removeVariable (const FgVarNode* var)
FactorGraph::addFactor (FgFacNode* fn)
{
if (varNodes_[varNodes_.size() - 1] == var) {
varNodes_.pop_back();
} else {
for (unsigned i = 0; i < varNodes_.size(); i++) {
if (varNodes_[i] == var) {
varNodes_.erase (varNodes_.begin() + i);
return;
}
}
assert (false);
}
indexMap_.erase (indexMap_.find (var->getVarId()));
facNodes_.push_back (fn);
fn->setIndex (facNodes_.size() - 1);
}
void
FactorGraph::addEdge (FgVarNode* vn, FgFacNode* fn)
{
vn->addNeighbor (fn);
fn->addNeighbor (vn);
}
void
FactorGraph::addFactor (Factor* f)
FactorGraph::addEdge (FgFacNode* fn, FgVarNode* vn)
{
factors_.push_back (f);
const FgVarSet& factorVars = f->getFgVarNodes();
for (unsigned i = 0; i < factorVars.size(); i++) {
factorVars[i]->addFactor (f);
}
fn->addNeighbor (vn);
vn->addNeighbor (fn);
}
void
FactorGraph::removeFactor (const Factor* f)
VarNode*
FactorGraph::getVariableNode (VarId vid) const
{
const FgVarSet& factorVars = f->getFgVarNodes();
for (unsigned i = 0; i < factorVars.size(); i++) {
if (factorVars[i]) {
factorVars[i]->removeFactor (f);
}
}
if (factors_[factors_.size() - 1] == f) {
factors_.pop_back();
} else {
for (unsigned i = 0; i < factors_.size(); i++) {
if (factors_[i] == f) {
factors_.erase (factors_.begin() + i);
return;
}
}
assert (false);
}
FgVarNode* vn = getFgVarNode (vid);
assert (vn);
return vn;
}
VarSet
FactorGraph::getVariables (void) const
VarNodes
FactorGraph::getVariableNodes (void) const
{
VarSet vars;
VarNodes vars;
for (unsigned i = 0; i < varNodes_.size(); i++) {
vars.push_back (varNodes_[i]);
}
@ -206,10 +286,10 @@ FactorGraph::getVariables (void) const
Variable*
FactorGraph::getVariable (Vid vid) const
bool
FactorGraph::isTree (void) const
{
return getFgVarNode (vid);
return !containsCycle();
}
@ -220,8 +300,8 @@ FactorGraph::setIndexes (void)
for (unsigned i = 0; i < varNodes_.size(); i++) {
varNodes_[i]->setIndex (i);
}
for (unsigned i = 0; i < factors_.size(); i++) {
factors_[i]->setIndex (i);
for (unsigned i = 0; i < facNodes_.size(); i++) {
facNodes_[i]->setIndex (i);
}
}
@ -231,8 +311,8 @@ void
FactorGraph::freeDistributions (void)
{
set<Distribution*> dists;
for (unsigned i = 0; i < factors_.size(); i++) {
dists.insert (factors_[i]->getDistribution());
for (unsigned i = 0; i < facNodes_.size(); i++) {
dists.insert (facNodes_[i]->factor()->getDistribution());
}
for (set<Distribution*>::iterator it = dists.begin();
it != dists.end(); it++) {
@ -246,19 +326,18 @@ void
FactorGraph::printGraphicalModel (void) const
{
for (unsigned i = 0; i < varNodes_.size(); i++) {
cout << "variable number " << varNodes_[i]->getIndex() << endl;
cout << "Id = " << varNodes_[i]->getVarId() << endl;
cout << "Label = " << varNodes_[i]->getLabel() << endl;
cout << "Domain size = " << varNodes_[i]->getDomainSize() << endl;
cout << "VarId = " << varNodes_[i]->varId() << endl;
cout << "Label = " << varNodes_[i]->label() << endl;
cout << "Nr States = " << varNodes_[i]->nrStates() << endl;
cout << "Evidence = " << varNodes_[i]->getEvidence() << endl;
cout << "Factors = " ;
for (unsigned j = 0; j < varNodes_[i]->getFactors().size(); j++) {
cout << varNodes_[i]->getFactors()[j]->getLabel() << " " ;
for (unsigned j = 0; j < varNodes_[i]->neighbors().size(); j++) {
cout << varNodes_[i]->neighbors()[j]->getLabel() << " " ;
}
cout << endl << endl;
}
for (unsigned i = 0; i < factors_.size(); i++) {
factors_[i]->printFactor();
for (unsigned i = 0; i < facNodes_.size(); i++) {
facNodes_[i]->factor()->printFactor();
cout << endl;
}
}
@ -266,7 +345,7 @@ FactorGraph::printGraphicalModel (void) const
void
FactorGraph::exportToDotFormat (const char* fileName) const
FactorGraph::exportToGraphViz (const char* fileName) const
{
ofstream out (fileName);
if (!out.is_open()) {
@ -279,24 +358,23 @@ FactorGraph::exportToDotFormat (const char* fileName) const
for (unsigned i = 0; i < varNodes_.size(); i++) {
if (varNodes_[i]->hasEvidence()) {
out << '"' << varNodes_[i]->getLabel() << '"' ;
out << '"' << varNodes_[i]->label() << '"' ;
out << " [style=filled, fillcolor=yellow]" << endl;
}
}
for (unsigned i = 0; i < factors_.size(); i++) {
out << '"' << factors_[i]->getLabel() << '"' ;
out << " [label=\"" << factors_[i]->getLabel() << "\\n(";
out << factors_[i]->getDistribution()->id << ")" << "\"" ;
out << ", shape=box]" << 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 < factors_.size(); i++) {
CFgVarSet myVars = factors_[i]->getFgVarNodes();
for (unsigned i = 0; i < facNodes_.size(); i++) {
const FgVarSet& myVars = facNodes_[i]->neighbors();
for (unsigned j = 0; j < myVars.size(); j++) {
out << '"' << factors_[i]->getLabel() << '"' ;
out << '"' << facNodes_[i]->getLabel() << '"' ;
out << " -- " ;
out << '"' << myVars[j]->getLabel() << '"' << endl;
out << '"' << myVars[j]->label() << '"' << endl;
}
}
@ -319,13 +397,13 @@ FactorGraph::exportToUaiFormat (const char* fileName) const
out << "MARKOV" << endl;
out << varNodes_.size() << endl;
for (unsigned i = 0; i < varNodes_.size(); i++) {
out << varNodes_[i]->getDomainSize() << " " ;
out << varNodes_[i]->nrStates() << " " ;
}
out << endl;
out << factors_.size() << endl;
for (unsigned i = 0; i < factors_.size(); i++) {
CFgVarSet factorVars = factors_[i]->getFgVarNodes();
out << facNodes_.size() << endl;
for (unsigned i = 0; i < facNodes_.size(); i++) {
const FgVarSet& factorVars = facNodes_[i]->neighbors();
out << factorVars.size();
for (unsigned j = 0; j < factorVars.size(); j++) {
out << " " << factorVars[j]->getIndex();
@ -333,8 +411,8 @@ FactorGraph::exportToUaiFormat (const char* fileName) const
out << endl;
}
for (unsigned i = 0; i < factors_.size(); i++) {
CParamSet params = factors_[i]->getParameters();
for (unsigned i = 0; i < facNodes_.size(); i++) {
const ParamSet& params = facNodes_[i]->getParameters();
out << endl << params.size() << endl << " " ;
for (unsigned j = 0; j < params.size(); j++) {
out << params[j] << " " ;
@ -345,3 +423,102 @@ FactorGraph::exportToUaiFormat (const char* fileName) const
out.close();
}
void
FactorGraph::exportToLibDaiFormat (const char* fileName) const
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "FactorGraph::exportToLibDaiFormat()" << endl;
abort();
}
out << facNodes_.size() << endl << endl;
for (unsigned i = 0; i < facNodes_.size(); i++) {
const FgVarSet& 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]->nrStates() << " " ;
}
out << endl;
const ParamSet& params = facNodes_[i]->factor()->getParameters();
out << params.size() << endl;
for (unsigned j = 0; j < params.size(); j++) {
out << j << " " << params[j] << endl;
}
out << endl;
}
out.close();
}
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 FgVarNode* v,
const FgFacNode* p,
vector<bool>& visitedVars,
vector<bool>& visitedFactors) const
{
visitedVars[v->getIndex()] = true;
const FgFacSet& 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 FgFacNode* v,
const FgVarNode* p,
vector<bool>& visitedVars,
vector<bool>& visitedFactors) const
{
visitedFactors[v->getIndex()] = true;
const FgVarSet& 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

@ -1,41 +1,116 @@
#ifndef BP_FACTOR_GRAPH_H
#define BP_FACTOR_GRAPH_H
#ifndef HORUS_FACTORGRAPH_H
#define HORUS_FACTORGRAPH_H
#include <vector>
#include "GraphicalModel.h"
#include "Shared.h"
#include "Distribution.h"
#include "Factor.h"
using namespace std;
class FgVarNode;
class Factor;
class BayesNet;
class FgFacNode;
class FgVarNode : public VarNode
{
public:
FgVarNode (VarId varId, unsigned nrStates) : VarNode (varId, nrStates) { }
FgVarNode (const VarNode* v) : VarNode (v) { }
void addNeighbor (FgFacNode* fn)
{
neighs_.push_back (fn);
}
const vector<FgFacNode*>& neighbors (void) const
{
return neighs_;
}
private:
DISALLOW_COPY_AND_ASSIGN (FgVarNode);
// members
vector<FgFacNode*> neighs_;
};
class FgFacNode
{
public:
FgFacNode (Factor* factor)
{
factor_ = factor;
index_ = -1;
}
Factor* factor() const
{
return factor_;
}
void addNeighbor (FgVarNode* vn)
{
neighs_.push_back (vn);
}
const vector<FgVarNode*>& neighbors (void) const
{
return neighs_;
}
int getIndex (void) const
{
assert (index_ != -1);
return index_;
}
void setIndex (int index)
{
index_ = index;
}
Distribution* getDistribution (void)
{
return factor_->getDistribution();
}
const ParamSet& getParameters (void) const
{
return factor_->getParameters();
}
string getLabel (void)
{
return factor_->getLabel();
}
private:
DISALLOW_COPY_AND_ASSIGN (FgFacNode);
Factor* factor_;
int index_;
vector<FgVarNode*> neighs_;
};
class FactorGraph : public GraphicalModel
{
public:
FactorGraph (void) {};
FactorGraph (const char*);
FactorGraph (const BayesNet&);
~FactorGraph (void);
void readFromUaiFormat (const char*);
void readFromLibDaiFormat (const char*);
void addVariable (FgVarNode*);
void removeVariable (const FgVarNode*);
void addFactor (Factor*);
void removeFactor (const Factor*);
VarSet getVariables (void) const;
Variable* getVariable (unsigned) const;
void addFactor (FgFacNode*);
void addEdge (FgVarNode*, FgFacNode*);
void addEdge (FgFacNode*, FgVarNode*);
VarNode* getVariableNode (unsigned) const;
VarNodes getVariableNodes (void) const;
bool isTree (void) const;
void setIndexes (void);
void freeDistributions (void);
void printGraphicalModel (void) const;
void exportToDotFormat (const char*) const;
void exportToGraphViz (const char*) const;
void exportToUaiFormat (const char*) const;
const FgVarSet& getFgVarNodes (void) const { return varNodes_; }
const FactorSet& getFactors (void) const { return factors_; }
void exportToLibDaiFormat (const char*) const;
const FgVarSet& getVarNodes (void) const { return varNodes_; }
const FgFacSet& getFactorNodes (void) const { return facNodes_; }
FgVarNode* getFgVarNode (Vid vid) const
FgVarNode* getFgVarNode (VarId vid) const
{
IndexMap::const_iterator it = indexMap_.find (vid);
if (it == indexMap_.end()) {
@ -46,12 +121,20 @@ class FactorGraph : public GraphicalModel
}
private:
bool containsCycle (void) const;
bool containsCycle (const FgVarNode*, const FgFacNode*,
vector<bool>&, vector<bool>&) const;
bool containsCycle (const FgFacNode*, const FgVarNode*,
vector<bool>&, vector<bool>&) const;
DISALLOW_COPY_AND_ASSIGN (FactorGraph);
FgVarSet varNodes_;
FactorSet factors_;
IndexMap indexMap_;
FgVarSet varNodes_;
FgFacSet facNodes_;
typedef unordered_map<unsigned, unsigned> IndexMap;
IndexMap indexMap_;
};
#endif // BP_FACTOR_GRAPH_H
#endif // HORUS_FACTORGRAPH_H

View File

@ -0,0 +1,499 @@
#include <cassert>
#include <limits>
#include <algorithm>
#include <iostream>
#include "FgBpSolver.h"
#include "FactorGraph.h"
#include "Factor.h"
#include "Shared.h"
FgBpSolver::FgBpSolver (const FactorGraph& fg) : Solver (&fg)
{
factorGraph_ = &fg;
}
FgBpSolver::~FgBpSolver (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];
}
}
void
FgBpSolver::runSolver (void)
{
clock_t start;
if (COLLECT_STATISTICS) {
start = clock();
}
if (false) {
//if (!BpOptions::useAlwaysLoopySolver && factorGraph_->isTree()) {
runTreeSolver();
} else {
runLoopySolver();
if (DL >= 2) {
cout << endl;
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;
}
}
}
unsigned size = factorGraph_->getVarNodes().size();
if (COLLECT_STATISTICS) {
unsigned nIters = 0;
bool loopy = factorGraph_->isTree() == false;
if (loopy) nIters = nIters_;
double time = (double (clock() - start)) / CLOCKS_PER_SEC;
Statistics::updateStatistics (size, loopy, nIters, time);
}
if (EXPORT_TO_GRAPHVIZ && size > EXPORT_MINIMAL_SIZE) {
stringstream ss;
ss << Statistics::getSolvedNetworksCounting() << "." << size << ".dot" ;
factorGraph_->exportToGraphViz (ss.str().c_str());
}
}
ParamSet
FgBpSolver::getPosterioriOf (VarId vid)
{
assert (factorGraph_->getFgVarNode (vid));
FgVarNode* var = factorGraph_->getFgVarNode (vid);
ParamSet probs;
if (var->hasEvidence()) {
probs.resize (var->nrStates(), Util::noEvidence());
probs[var->getEvidence()] = Util::withEvidence();
} else {
probs.resize (var->nrStates(), Util::multIdenty());
const SpLinkSet& links = ninf(var)->getLinks();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < links.size(); i++) {
Util::multiply (probs, links[i]->getMessage());
}
Util::normalize (probs);
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < links.size(); i++) {
Util::add (probs, links[i]->getMessage());
}
Util::normalize (probs);
Util::fromLog (probs);
}
}
return probs;
}
ParamSet
FgBpSolver::getJointDistributionOf (const VarIdSet& jointVarIds)
{
unsigned msgSize = 1;
vector<unsigned> dsizes (jointVarIds.size());
for (unsigned i = 0; i < jointVarIds.size(); i++) {
dsizes[i] = factorGraph_->getFgVarNode (jointVarIds[i])->nrStates();
msgSize *= dsizes[i];
}
unsigned reps = 1;
ParamSet jointDist (msgSize, Util::multIdenty());
for (int i = jointVarIds.size() - 1 ; i >= 0; i--) {
Util::multiply (jointDist, getPosterioriOf (jointVarIds[i]), reps);
reps *= dsizes[i];
}
return jointDist;
}
void
FgBpSolver::runTreeSolver (void)
{
initializeSolver();
const FgFacSet& facNodes = factorGraph_->getFactorNodes();
bool finish = false;
while (!finish) {
finish = true;
for (unsigned i = 0; i < facNodes.size(); i++) {
const SpLinkSet& links = ninf (facNodes[i])->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (!links[j]->messageWasSended()) {
if (readyToSendMessage (links[j])) {
calculateAndUpdateMessage (links[j], false);
}
finish = false;
}
}
}
}
}
bool
FgBpSolver::readyToSendMessage (const SpLink* link) const
{
const FgVarSet& neighbors = link->getFactor()->neighbors();
for (unsigned i = 0; i < neighbors.size(); i++) {
if (neighbors[i] != link->getVariable()) {
const SpLinkSet& links = ninf (neighbors[i])->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (links[j]->getFactor() != link->getFactor() &&
!links[j]->messageWasSended()) {
return false;
}
}
}
}
return true;
}
void
FgBpSolver::runLoopySolver (void)
{
initializeSolver();
nIters_ = 0;
while (!converged() && nIters_ < BpOptions::maxIter) {
nIters_ ++;
if (DL >= 2) {
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
cout << " Iteration " << nIters_ << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
}
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 (DL >= 2) {
cout << endl;
}
}
}
void
FgBpSolver::initializeSolver (void)
{
const FgVarSet& varNodes = factorGraph_->getVarNodes();
for (unsigned i = 0; i < varsI_.size(); i++) {
delete varsI_[i];
}
varsI_.reserve (varNodes.size());
for (unsigned i = 0; i < varNodes.size(); i++) {
varsI_.push_back (new SPNodeInfo());
}
const FgFacSet& facNodes = factorGraph_->getFactorNodes();
for (unsigned i = 0; i < facsI_.size(); i++) {
delete facsI_[i];
}
facsI_.reserve (facNodes.size());
for (unsigned i = 0; i < facNodes.size(); i++) {
facsI_.push_back (new SPNodeInfo());
}
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
createLinks();
for (unsigned i = 0; i < links_.size(); i++) {
FgFacNode* src = links_[i]->getFactor();
FgVarNode* dst = links_[i]->getVariable();
ninf (dst)->addSpLink (links_[i]);
ninf (src)->addSpLink (links_[i]);
}
}
void
FgBpSolver::createLinks (void)
{
const FgFacSet& facNodes = factorGraph_->getFactorNodes();
for (unsigned i = 0; i < facNodes.size(); i++) {
const FgVarSet& neighbors = facNodes[i]->neighbors();
for (unsigned j = 0; j < neighbors.size(); j++) {
links_.push_back (new SpLink (facNodes[i], neighbors[j]));
}
}
}
bool
FgBpSolver::converged (void)
{
if (links_.size() == 0) {
return true;
}
if (nIters_ == 0 || nIters_ == 1) {
return false;
}
bool converged = true;
if (BpOptions::schedule == BpOptions::Schedule::MAX_RESIDUAL) {
Param 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 (DL >= 2) {
cout << links_[i]->toString() + " residual = " << residual << endl;
}
if (residual > BpOptions::accuracy) {
converged = false;
if (DL == 0) break;
}
}
}
return converged;
}
void
FgBpSolver::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 (DL >= 2) {
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 FgFacSet& 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 (DL >= 2) {
cout << "----------------------------------------" ;
cout << "----------------------------------------" << endl;
}
}
}
void
FgBpSolver::calculateFactor2VariableMsg (SpLink* link) const
{
const FgFacNode* src = link->getFactor();
const FgVarNode* 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()->nrStates();
}
unsigned repetitions = 1;
ParamSet msgProduct (msgSize, Util::multIdenty());
switch (NSPACE) {
case NumberSpace::NORMAL:
for (int i = links.size() - 1; i >= 0; i--) {
if (links[i]->getVariable() != dst) {
if (DL >= 5) {
cout << " message from " << links[i]->getVariable()->label();
cout << ": " << endl;
}
Util::multiply (msgProduct, getVar2FactorMsg (links[i]), repetitions);
repetitions *= links[i]->getVariable()->nrStates();
} else {
unsigned ds = links[i]->getVariable()->nrStates();
Util::multiply (msgProduct, ParamSet (ds, 1.0), repetitions);
repetitions *= ds;
}
}
break;
case NumberSpace::LOGARITHM:
for (int i = links.size() - 1; i >= 0; i--) {
if (links[i]->getVariable() != dst) {
Util::add (msgProduct, getVar2FactorMsg (links[i]), repetitions);
repetitions *= links[i]->getVariable()->nrStates();
} else {
unsigned ds = links[i]->getVariable()->nrStates();
Util::add (msgProduct, ParamSet (ds, 1.0), repetitions);
repetitions *= ds;
}
}
}
Factor result (src->factor()->getVarIds(),
src->factor()->getRanges(),
msgProduct);
result.multiplyByFactor (*(src->factor()));
if (DL >= 5) {
cout << " message product: " ;
cout << Util::parametersToString (msgProduct) << endl;
cout << " original factor: " ;
cout << Util::parametersToString (src->getParameters()) << endl;
cout << " factor product: " ;
cout << Util::parametersToString (result.getParameters()) << endl;
}
result.removeAllVariablesExcept (dst->varId());
if (DL >= 5) {
cout << " marginalized: " ;
cout << Util::parametersToString (result.getParameters()) << endl;
}
const ParamSet& resultParams = result.getParameters();
ParamSet& message = link->getNextMessage();
for (unsigned i = 0; i < resultParams.size(); i++) {
message[i] = resultParams[i];
}
Util::normalize (message);
if (DL >= 5) {
cout << " curr msg: " ;
cout << Util::parametersToString (link->getMessage()) << endl;
cout << " next msg: " ;
cout << Util::parametersToString (message) << endl;
}
result.freeDistribution();
}
ParamSet
FgBpSolver::getVar2FactorMsg (const SpLink* link) const
{
const FgVarNode* src = link->getVariable();
const FgFacNode* dst = link->getFactor();
ParamSet msg;
if (src->hasEvidence()) {
msg.resize (src->nrStates(), Util::noEvidence());
msg[src->getEvidence()] = Util::withEvidence();
if (DL >= 5) {
cout << Util::parametersToString (msg);
}
} else {
msg.resize (src->nrStates(), Util::one());
}
if (DL >= 5) {
cout << Util::parametersToString (msg);
}
const SpLinkSet& links = ninf (src)->getLinks();
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dst) {
Util::multiply (msg, links[i]->getMessage());
if (DL >= 5) {
cout << " x " << Util::parametersToString (links[i]->getMessage());
}
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dst) {
Util::add (msg, links[i]->getMessage());
}
}
}
if (DL >= 5) {
cout << " = " << Util::parametersToString (msg);
}
return msg;
}
void
FgBpSolver::printLinkInformation (void) const
{
for (unsigned i = 0; i < links_.size(); i++) {
SpLink* l = links_[i];
cout << l->toString() << ":" << endl;
cout << " curr msg = " ;
cout << Util::parametersToString (l->getMessage()) << endl;
cout << " next msg = " ;
cout << Util::parametersToString (l->getNextMessage()) << endl;
cout << " residual = " << l->getResidual() << endl;
}
}

View File

@ -0,0 +1,175 @@
#ifndef HORUS_FGBPSOLVER_H
#define HORUS_FGBPSOLVER_H
#include <set>
#include <vector>
#include <sstream>
#include "Solver.h"
#include "Factor.h"
#include "FactorGraph.h"
using namespace std;
class SpLink
{
public:
SpLink (FgFacNode* fn, FgVarNode* vn)
{
fac_ = fn;
var_ = vn;
v1_.resize (vn->nrStates(), Util::tl (1.0 / vn->nrStates()));
v2_.resize (vn->nrStates(), Util::tl (1.0 / vn->nrStates()));
currMsg_ = &v1_;
nextMsg_ = &v2_;
msgSended_ = false;
residual_ = 0.0;
}
virtual ~SpLink (void) {};
virtual void updateMessage (void)
{
swap (currMsg_, nextMsg_);
msgSended_ = true;
}
void updateResidual (void)
{
residual_ = Util::getMaxNorm (v1_, v2_);
}
string toString (void) const
{
stringstream ss;
ss << fac_->getLabel();
ss << " -- " ;
ss << var_->label();
return ss.str();
}
FgFacNode* getFactor (void) const { return fac_; }
FgVarNode* getVariable (void) const { return var_; }
const ParamSet& getMessage (void) const { return *currMsg_; }
ParamSet& getNextMessage (void) { return *nextMsg_; }
bool messageWasSended (void) const { return msgSended_; }
double getResidual (void) const { return residual_; }
void clearResidual (void) { residual_ = 0.0; }
protected:
FgFacNode* fac_;
FgVarNode* var_;
ParamSet v1_;
ParamSet v2_;
ParamSet* currMsg_;
ParamSet* 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 FgBpSolver : public Solver
{
public:
FgBpSolver (const FactorGraph&);
virtual ~FgBpSolver (void);
void runSolver (void);
virtual ParamSet getPosterioriOf (VarId);
virtual ParamSet getJointDistributionOf (const VarIdSet&);
protected:
virtual void initializeSolver (void);
virtual void createLinks (void);
virtual void maxResidualSchedule (void);
virtual void calculateFactor2VariableMsg (SpLink*) const;
virtual ParamSet getVar2FactorMsg (const SpLink*) const;
virtual void printLinkInformation (void) const;
void calculateAndUpdateMessage (SpLink* link, bool calcResidual = true)
{
if (DL >= 3) {
cout << "calculating & updating " << link->toString() << endl;
}
calculateFactor2VariableMsg (link);
if (calcResidual) {
link->updateResidual();
}
link->updateMessage();
}
void calculateMessage (SpLink* link, bool calcResidual = true)
{
if (DL >= 3) {
cout << "calculating " << link->toString() << endl;
}
calculateFactor2VariableMsg (link);
if (calcResidual) {
link->updateResidual();
}
}
void updateMessage (SpLink* link)
{
link->updateMessage();
if (DL >= 3) {
cout << "updating " << link->toString() << endl;
}
}
SPNodeInfo* ninf (const FgVarNode* var) const
{
return varsI_[var->getIndex()];
}
SPNodeInfo* ninf (const FgFacNode* fac) const
{
return facsI_[fac->getIndex()];
}
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_;
const FactorGraph* factorGraph_;
typedef multiset<SpLink*, CompareResidual> SortedOrder;
SortedOrder sortedOrder_;
typedef unordered_map<SpLink*, SortedOrder::iterator> SpLinkMap;
SpLinkMap linkMap_;
private:
void runTreeSolver (void);
bool readyToSendMessage (const SpLink*) const;
void runLoopySolver (void);
bool converged (void);
};
#endif // HORUS_FGBPSOLVER_H

View File

@ -1,43 +0,0 @@
#ifndef BP_FG_VAR_NODE_H
#define BP_FG_VAR_NODE_H
#include <vector>
#include "Variable.h"
#include "Shared.h"
using namespace std;
class Factor;
class FgVarNode : public Variable
{
public:
FgVarNode (unsigned vid, unsigned dsize) : Variable (vid, dsize) { }
FgVarNode (const Variable* v) : Variable (v) { }
void addFactor (Factor* f) { factors_.push_back (f); }
CFactorSet getFactors (void) const { return factors_; }
void removeFactor (const Factor* f)
{
if (factors_[factors_.size() -1] == f) {
factors_.pop_back();
} else {
for (unsigned i = 0; i < factors_.size(); i++) {
if (factors_[i] == f) {
factors_.erase (factors_.begin() + i);
return;
}
}
assert (false);
}
}
private:
DISALLOW_COPY_AND_ASSIGN (FgVarNode);
// members
FactorSet factors_;
};
#endif // BP_FG_VAR_NODE_H

View File

@ -1,18 +1,54 @@
#ifndef BP_GRAPHICAL_MODEL_H
#define BP_GRAPHICAL_MODEL_H
#ifndef HORUS_GRAPHICALMODEL_H
#define HORUS_GRAPHICALMODEL_H
#include "Variable.h"
#include "VarNode.h"
#include "Shared.h"
using namespace std;
using namespace std;
struct VariableInfo
{
VariableInfo (string l, const States& sts)
{
label = l;
states = sts;
}
string label;
States states;
};
class GraphicalModel
{
public:
virtual ~GraphicalModel (void) {};
virtual Variable* getVariable (Vid) const = 0;
virtual VarSet getVariables (void) const = 0;
virtual VarNode* getVariableNode (VarId) const = 0;
virtual VarNodes getVariableNodes (void) const = 0;
virtual void printGraphicalModel (void) const = 0;
static void addVariableInformation (VarId vid, string label,
const States& states)
{
assert (varsInfo_.find (vid) == varsInfo_.end());
varsInfo_.insert (make_pair (vid, VariableInfo (label, states)));
}
static VariableInfo getVariableInformation (VarId vid)
{
assert (varsInfo_.find (vid) != varsInfo_.end());
return varsInfo_.find (vid)->second;
}
static bool variablesHaveInformation (void)
{
return varsInfo_.size() != 0;
}
static void clearVariablesInformation (void)
{
varsInfo_.clear();
}
private:
static unordered_map<VarId,VariableInfo> varsInfo_;
};
#endif // BP_GRAPHICAL_MODEL_H
#endif // HORUS_GRAPHICALMODEL_H

View File

@ -5,15 +5,18 @@
#include "BayesNet.h"
#include "FactorGraph.h"
#include "SPSolver.h"
#include "BPSolver.h"
#include "CountingBP.h"
#include "VarElimSolver.h"
#include "BnBpSolver.h"
#include "FgBpSolver.h"
#include "CbpSolver.h"
#include "StatesIndexer.h"
using namespace std;
void BayesianNetwork (int, const char* []);
void markovNetwork (int, const char* []);
void runSolver (Solver*, const VarSet&);
void processArguments (BayesNet&, int, const char* []);
void processArguments (FactorGraph&, int, const char* []);
void runSolver (Solver*, const VarNodes&);
const string USAGE = "usage: \
./hcli FILE [VARIABLE | OBSERVED_VARIABLE=EVIDENCE]..." ;
@ -21,33 +24,7 @@ const string USAGE = "usage: \
int
main (int argc, const char* argv[])
{
/*
FactorGraph fg;
FgVarNode* varNode1 = new FgVarNode (0, 2);
FgVarNode* varNode2 = new FgVarNode (1, 2);
FgVarNode* varNode3 = new FgVarNode (2, 2);
fg.addVariable (varNode1);
fg.addVariable (varNode2);
fg.addVariable (varNode3);
Distribution* dist = new Distribution (ParamSet() = {1.2, 1.4, 2.0, 0.4});
fg.addFactor (new Factor (FgVarSet() = {varNode1, varNode2}, dist));
fg.addFactor (new Factor (FgVarSet() = {varNode3, varNode2}, dist));
//fg.printGraphicalModel();
//SPSolver sp (fg);
//sp.runSolver();
//sp.printAllPosterioris();
//ParamSet p = sp.getJointDistributionOf (VidSet() = {0, 1, 2});
//cout << Util::parametersToString (p) << endl;
CountingBP cbp (fg);
//cbp.runSolver();
//cbp.printAllPosterioris();
ParamSet p2 = cbp.getJointDistributionOf (VidSet() = {0, 1, 2});
cout << Util::parametersToString (p2) << endl;
fg.freeDistributions();
Statistics::printCompressingStats ("compressing.stats");
return 0;
*/
{
if (!argv[1]) {
cerr << "error: no graphical model specified" << endl;
cerr << USAGE << endl;
@ -56,12 +33,20 @@ main (int argc, const char* argv[])
const string& fileName = argv[1];
const string& extension = fileName.substr (fileName.find_last_of ('.') + 1);
if (extension == "xml") {
BayesianNetwork (argc, argv);
BayesNet bn;
bn.readFromBifFormat (argv[1]);
processArguments (bn, argc, argv);
} else if (extension == "uai") {
markovNetwork (argc, argv);
FactorGraph fg;
fg.readFromUaiFormat (argv[1]);
processArguments (fg, argc, argv);
} else if (extension == "fg") {
FactorGraph fg;
fg.readFromLibDaiFormat (argv[1]);
processArguments (fg, argc, argv);
} else {
cerr << "error: the graphical model must be defined either " ;
cerr << "in a xml file or uai file" << endl;
cerr << "in a xml, uai or libDAI file" << endl;
exit (0);
}
return 0;
@ -70,12 +55,9 @@ main (int argc, const char* argv[])
void
BayesianNetwork (int argc, const char* argv[])
processArguments (BayesNet& bn, int argc, const char* argv[])
{
BayesNet bn (argv[1]);
//bn.printGraphicalModel();
VarSet queryVars;
VarNodes queryVars;
for (int i = 2; i < argc; i++) {
const string& arg = argv[i];
if (arg.find ('=') == std::string::npos) {
@ -86,6 +68,7 @@ BayesianNetwork (int argc, const char* argv[])
cerr << "error: there isn't a variable labeled of " ;
cerr << "`" << arg << "'" ;
cerr << endl;
bn.freeDistributions();
exit (0);
}
} else {
@ -95,11 +78,13 @@ BayesianNetwork (int argc, const char* argv[])
if (label.empty()) {
cerr << "error: missing left argument" << endl;
cerr << USAGE << endl;
bn.freeDistributions();
exit (0);
}
if (state.empty()) {
cerr << "error: missing right argument" << endl;
cerr << USAGE << endl;
bn.freeDistributions();
exit (0);
}
BayesNode* node = bn.getBayesNode (label);
@ -109,42 +94,54 @@ BayesianNetwork (int argc, const char* argv[])
} else {
cerr << "error: `" << state << "' " ;
cerr << "is not a valid state for " ;
cerr << "`" << node->getLabel() << "'" ;
cerr << "`" << node->label() << "'" ;
cerr << endl;
bn.freeDistributions();
exit (0);
}
} else {
cerr << "error: there isn't a variable labeled of " ;
cerr << "`" << label << "'" ;
cerr << endl;
bn.freeDistributions();
exit (0);
}
}
}
Solver* solver;
if (SolverOptions::convertBn2Fg) {
FactorGraph* fg = new FactorGraph (bn);
fg->printGraphicalModel();
solver = new SPSolver (*fg);
runSolver (solver, queryVars);
delete fg;
} else {
solver = new BPSolver (bn);
runSolver (solver, queryVars);
Solver* solver = 0;
FactorGraph* fg = 0;
switch (InfAlgorithms::infAlgorithm) {
case InfAlgorithms::VE:
fg = new FactorGraph (bn);
solver = new VarElimSolver (*fg);
break;
case InfAlgorithms::BN_BP:
solver = new BnBpSolver (bn);
break;
case InfAlgorithms::FG_BP:
fg = new FactorGraph (bn);
fg->printGraphicalModel();
solver = new FgBpSolver (*fg);
break;
case InfAlgorithms::CBP:
fg = new FactorGraph (bn);
solver = new CbpSolver (*fg);
break;
default:
assert (false);
}
runSolver (solver, queryVars);
delete fg;
bn.freeDistributions();
}
void
markovNetwork (int argc, const char* argv[])
processArguments (FactorGraph& fg, int argc, const char* argv[])
{
FactorGraph fg (argv[1]);
//fg.printGraphicalModel();
VarSet queryVars;
VarNodes queryVars;
for (int i = 2; i < argc; i++) {
const string& arg = argv[i];
if (arg.find ('=') == std::string::npos) {
@ -152,19 +149,21 @@ markovNetwork (int argc, const char* argv[])
cerr << "error: `" << arg << "' " ;
cerr << "is not a valid variable id" ;
cerr << endl;
fg.freeDistributions();
exit (0);
}
Vid vid;
VarId vid;
stringstream ss;
ss << arg;
ss >> vid;
Variable* queryVar = fg.getFgVarNode (vid);
VarNode* queryVar = fg.getFgVarNode (vid);
if (queryVar) {
queryVars.push_back (queryVar);
} else {
cerr << "error: there isn't a variable with " ;
cerr << "`" << vid << "' as id" ;
cerr << endl;
fg.freeDistributions();
exit (0);
}
} else {
@ -172,53 +171,73 @@ markovNetwork (int argc, const char* argv[])
if (arg.substr (0, pos).empty()) {
cerr << "error: missing left argument" << endl;
cerr << USAGE << endl;
fg.freeDistributions();
exit (0);
}
if (arg.substr (pos + 1).empty()) {
cerr << "error: missing right argument" << endl;
cerr << USAGE << endl;
fg.freeDistributions();
exit (0);
}
if (!Util::isInteger (arg.substr (0, pos))) {
cerr << "error: `" << arg.substr (0, pos) << "' " ;
cerr << "is not a variable id" ;
cerr << endl;
fg.freeDistributions();
exit (0);
}
Vid vid;
VarId vid;
stringstream ss;
ss << arg.substr (0, pos);
ss >> vid;
Variable* var = fg.getFgVarNode (vid);
VarNode* var = fg.getFgVarNode (vid);
if (var) {
if (!Util::isInteger (arg.substr (pos + 1))) {
cerr << "error: `" << arg.substr (pos + 1) << "' " ;
cerr << "is not a state index" ;
cerr << endl;
fg.freeDistributions();
exit (0);
}
int stateIndex;
stringstream ss;
ss << arg.substr (pos + 1);
ss >> stateIndex;
if (var->isValidStateIndex (stateIndex)) {
if (var->isValidState (stateIndex)) {
var->setEvidence (stateIndex);
} else {
cerr << "error: `" << stateIndex << "' " ;
cerr << "is not a valid state index for variable " ;
cerr << "`" << var->getVarId() << "'" ;
cerr << "`" << var->varId() << "'" ;
cerr << endl;
fg.freeDistributions();
exit (0);
}
} else {
cerr << "error: there isn't a variable with " ;
cerr << "`" << vid << "' as id" ;
cerr << endl;
fg.freeDistributions();
exit (0);
}
}
}
Solver* solver = new SPSolver (fg);
Solver* solver = 0;
switch (InfAlgorithms::infAlgorithm) {
case InfAlgorithms::VE:
solver = new VarElimSolver (fg);
break;
case InfAlgorithms::BN_BP:
case InfAlgorithms::FG_BP:
solver = new FgBpSolver (fg);
break;
case InfAlgorithms::CBP:
solver = new CbpSolver (fg);
break;
default:
assert (false);
}
runSolver (solver, queryVars);
fg.freeDistributions();
}
@ -226,11 +245,11 @@ markovNetwork (int argc, const char* argv[])
void
runSolver (Solver* solver, const VarSet& queryVars)
runSolver (Solver* solver, const VarNodes& queryVars)
{
VidSet vids;
VarIdSet vids;
for (unsigned i = 0; i < queryVars.size(); i++) {
vids.push_back (queryVars[i]->getVarId());
vids.push_back (queryVars[i]->varId());
}
if (queryVars.size() == 0) {
solver->runSolver();
@ -239,6 +258,7 @@ runSolver (Solver* solver, const VarSet& queryVars)
solver->runSolver();
solver->printPosterioriOf (vids[0]);
} else {
solver->runSolver();
solver->printJointDistributionOf (vids);
}
delete solver;

View File

@ -8,9 +8,11 @@
#include "BayesNet.h"
#include "FactorGraph.h"
#include "BPSolver.h"
#include "SPSolver.h"
#include "CountingBP.h"
#include "VarElimSolver.h"
#include "BnBpSolver.h"
#include "FgBpSolver.h"
#include "CbpSolver.h"
#include "ElimGraph.h"
using namespace std;
@ -18,26 +20,27 @@ using namespace std;
int
createNetwork (void)
{
//Statistics::numCreatedNets ++;
//cout << "creating network number " << Statistics::numCreatedNets << endl;
Statistics::incrementPrimaryNetworksCounting();
// cout << "creating network number " ;
// cout << Statistics::getPrimaryNetworksCounting() << endl;
// if (Statistics::getPrimaryNetworksCounting() > 98) {
// Statistics::writeStatisticsToFile ("../../compressing.stats");
// }
BayesNet* bn = new BayesNet();
YAP_Term varList = YAP_ARG1;
BnNodeSet nodes;
vector<VarIdSet> parents;
while (varList != YAP_TermNil()) {
YAP_Term var = YAP_HeadOfTerm (varList);
Vid vid = (Vid) YAP_IntOfTerm (YAP_ArgOfTerm (1, var));
unsigned dsize = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (2, var));
int evidence = (int) YAP_IntOfTerm (YAP_ArgOfTerm (3, var));
YAP_Term parentL = YAP_ArgOfTerm (4, var);
unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (5, var));
BnNodeSet parents;
YAP_Term var = YAP_HeadOfTerm (varList);
VarId vid = (VarId) YAP_IntOfTerm (YAP_ArgOfTerm (1, var));
unsigned dsize = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (2, var));
int evidence = (int) YAP_IntOfTerm (YAP_ArgOfTerm (3, var));
YAP_Term parentL = YAP_ArgOfTerm (4, var);
unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (5, var));
parents.push_back (VarIdSet());
while (parentL != YAP_TermNil()) {
unsigned parentId = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (parentL));
BayesNode* parent = bn->getBayesNode (parentId);
if (!parent) {
parent = bn->addNode (parentId);
}
parents.push_back (parent);
parents.back().push_back (parentId);
parentL = YAP_TailOfTerm (parentL);
}
Distribution* dist = bn->getDistribution (distId);
@ -45,20 +48,19 @@ createNetwork (void)
dist = new Distribution (distId);
bn->addDistribution (dist);
}
BayesNode* node = bn->getBayesNode (vid);
if (node) {
node->setData (dsize, evidence, parents, dist);
} else {
bn->addNode (vid, dsize, evidence, parents, dist);
}
assert (bn->getBayesNode (vid) == 0);
nodes.push_back (bn->addNode (vid, dsize, evidence, dist));
varList = YAP_TailOfTerm (varList);
}
for (unsigned i = 0; i < nodes.size(); i++) {
BnNodeSet ps;
for (unsigned j = 0; j < parents[i].size(); j++) {
assert (bn->getBayesNode (parents[i][j]) != 0);
ps.push_back (bn->getBayesNode (parents[i][j]));
}
nodes[i]->setParents (ps);
}
bn->setIndexes();
// if (Statistics::numCreatedNets == 1688) {
// Statistics::writeStats();
// exit (0);
// }
YAP_Int p = (YAP_Int) (bn);
return YAP_Unify (YAP_MkIntTerm (p), YAP_ARG2);
}
@ -68,23 +70,22 @@ createNetwork (void)
int
setExtraVarsInfo (void)
{
BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1);
// BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1);
GraphicalModel::clearVariablesInformation();
YAP_Term varsInfoL = YAP_ARG2;
while (varsInfoL != YAP_TermNil()) {
YAP_Term head = YAP_HeadOfTerm (varsInfoL);
Vid vid = YAP_IntOfTerm (YAP_ArgOfTerm (1, head));
VarId vid = YAP_IntOfTerm (YAP_ArgOfTerm (1, head));
YAP_Atom label = YAP_AtomOfTerm (YAP_ArgOfTerm (2, head));
YAP_Term domainL = YAP_ArgOfTerm (3, head);
Domain domain;
while (domainL != YAP_TermNil()) {
YAP_Atom atom = YAP_AtomOfTerm (YAP_HeadOfTerm (domainL));
domain.push_back ((char*) YAP_AtomName (atom));
domainL = YAP_TailOfTerm (domainL);
YAP_Term statesL = YAP_ArgOfTerm (3, head);
States states;
while (statesL != YAP_TermNil()) {
YAP_Atom atom = YAP_AtomOfTerm (YAP_HeadOfTerm (statesL));
states.push_back ((char*) YAP_AtomName (atom));
statesL = YAP_TailOfTerm (statesL);
}
BayesNode* node = bn->getBayesNode (vid);
assert (node);
node->setLabel ((char*) YAP_AtomName (label));
node->setDomain (domain);
GraphicalModel::addVariableInformation (vid,
(char*) YAP_AtomName (label), states);
varsInfoL = YAP_TailOfTerm (varsInfoL);
}
return TRUE;
@ -106,12 +107,10 @@ setParameters (void)
params.push_back ((double) YAP_FloatOfTerm (YAP_HeadOfTerm (paramL)));
paramL = YAP_TailOfTerm (paramL);
}
bn->getDistribution(distId)->updateParameters(params);
if (Statistics::numCreatedNets == 4) {
cout << "dist " << distId << " parameters:" ;
cout << Util::parametersToString (params);
cout << endl;
if (NSPACE == NumberSpace::LOGARITHM) {
Util::toLog (params);
}
bn->getDistribution(distId)->updateParameters (params);
distList = YAP_TailOfTerm (distList);
}
return TRUE;
@ -124,113 +123,73 @@ runSolver (void)
{
BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1);
YAP_Term taskList = YAP_ARG2;
vector<VidSet> tasks;
VidSet marginalVids;
vector<VarIdSet> tasks;
std::set<VarId> vids;
while (taskList != YAP_TermNil()) {
if (YAP_IsPairTerm (YAP_HeadOfTerm (taskList))) {
VidSet jointVids;
tasks.push_back (VarIdSet());
YAP_Term jointList = YAP_HeadOfTerm (taskList);
while (jointList != YAP_TermNil()) {
Vid vid = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (jointList));
VarId vid = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (jointList));
assert (bn->getBayesNode (vid));
jointVids.push_back (vid);
tasks.back().push_back (vid);
vids.insert (vid);
jointList = YAP_TailOfTerm (jointList);
}
tasks.push_back (jointVids);
} else {
Vid vid = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (taskList));
VarId vid = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (taskList));
assert (bn->getBayesNode (vid));
tasks.push_back (VidSet() = {vid});
marginalVids.push_back (vid);
tasks.push_back (VarIdSet() = {vid});
vids.insert (vid);
}
taskList = YAP_TailOfTerm (taskList);
}
// cout << "inference tasks:" << endl;
// for (unsigned i = 0; i < tasks.size(); i++) {
// cout << "i" << ": " ;
// if (tasks[i].size() == 1) {
// cout << tasks[i][0] << endl;
// } else {
// for (unsigned j = 0; j < tasks[i].size(); j++) {
// cout << tasks[i][j] << " " ;
// }
// cout << endl;
// }
// }
Solver* solver = 0;
GraphicalModel* gm = 0;
VidSet vids;
const BnNodeSet& nodes = bn->getBayesNodes();
for (unsigned i = 0; i < nodes.size(); i++) {
vids.push_back (nodes[i]->getVarId());
}
if (marginalVids.size() != 0) {
bn->exportToDotFormat ("bn unbayes.dot");
BayesNet* mrn = bn->getMinimalRequesiteNetwork (marginalVids);
mrn->exportToDotFormat ("bn bayes.dot");
//BayesNet* mrn = bn->getMinimalRequesiteNetwork (vids);
if (SolverOptions::convertBn2Fg) {
gm = new FactorGraph (*mrn);
if (SolverOptions::compressFactorGraph) {
solver = new CountingBP (*static_cast<FactorGraph*> (gm));
} else {
solver = new SPSolver (*static_cast<FactorGraph*> (gm));
}
if (SolverOptions::runBayesBall) {
delete mrn;
}
} else {
gm = mrn;
solver = new BPSolver (*static_cast<BayesNet*> (gm));
Solver* bpSolver = 0;
GraphicalModel* graphicalModel = 0;
CFactorGraph::disableCheckForIdenticalFactors();
if (InfAlgorithms::infAlgorithm != InfAlgorithms::VE) {
BayesNet* mrn = bn->getMinimalRequesiteNetwork (
VarIdSet (vids.begin(), vids.end()));
if (InfAlgorithms::infAlgorithm == InfAlgorithms::BN_BP) {
graphicalModel = mrn;
bpSolver = new BnBpSolver (*static_cast<BayesNet*> (graphicalModel));
} else if (InfAlgorithms::infAlgorithm == InfAlgorithms::FG_BP) {
graphicalModel = new FactorGraph (*mrn);
bpSolver = new FgBpSolver (*static_cast<FactorGraph*> (graphicalModel));
delete mrn;
} else if (InfAlgorithms::infAlgorithm == InfAlgorithms::CBP) {
graphicalModel = new FactorGraph (*mrn);
bpSolver = new CbpSolver (*static_cast<FactorGraph*> (graphicalModel));
delete mrn;
}
solver->runSolver();
bpSolver->runSolver();
}
vector<ParamSet> results;
results.reserve (tasks.size());
results.reserve (tasks.size());
for (unsigned i = 0; i < tasks.size(); i++) {
if (tasks[i].size() == 1) {
results.push_back (solver->getPosterioriOf (tasks[i][0]));
//if (i == 1) exit (0);
if (InfAlgorithms::infAlgorithm == InfAlgorithms::VE) {
BayesNet* mrn = bn->getMinimalRequesiteNetwork (tasks[i]);
VarElimSolver* veSolver = new VarElimSolver (*mrn);
if (tasks[i].size() == 1) {
results.push_back (veSolver->getPosterioriOf (tasks[i][0]));
} else {
results.push_back (veSolver->getJointDistributionOf (tasks[i]));
}
delete mrn;
delete veSolver;
} else {
static int count = 0;
cout << "calculating joint... " << count ++ << endl;
//if (count == 5225) {
// Statistics::printCompressingStats ("compressing.stats");
//}
Solver* solver2 = 0;
GraphicalModel* gm2 = 0;
bn->exportToDotFormat ("joint.dot");
BayesNet* mrn2;
if (SolverOptions::runBayesBall) {
mrn2 = bn->getMinimalRequesiteNetwork (tasks[i]);
if (tasks[i].size() == 1) {
results.push_back (bpSolver->getPosterioriOf (tasks[i][0]));
} else {
mrn2 = bn;
results.push_back (bpSolver->getJointDistributionOf (tasks[i]));
}
if (SolverOptions::convertBn2Fg) {
gm2 = new FactorGraph (*mrn2);
if (SolverOptions::compressFactorGraph) {
solver2 = new CountingBP (*static_cast<FactorGraph*> (gm2));
} else {
solver2 = new SPSolver (*static_cast<FactorGraph*> (gm2));
}
if (SolverOptions::runBayesBall) {
delete mrn2;
}
} else {
gm2 = mrn2;
solver2 = new BPSolver (*static_cast<BayesNet*> (gm2));
}
results.push_back (solver2->getJointDistributionOf (tasks[i]));
delete solver2;
delete gm2;
}
}
delete solver;
delete gm;
delete bpSolver;
delete graphicalModel;
YAP_Term list = YAP_TermNil();
for (int i = results.size() - 1; i >= 0; i--) {
@ -251,10 +210,91 @@ runSolver (void)
int
setSolverParameter (void)
{
string key ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG1)));
if (key == "inf_alg") {
string value ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG2)));
if ( value == "ve") {
InfAlgorithms::infAlgorithm = InfAlgorithms::VE;
} else if (value == "bn_bp") {
InfAlgorithms::infAlgorithm = InfAlgorithms::BN_BP;
} else if (value == "fg_bp") {
InfAlgorithms::infAlgorithm = InfAlgorithms::FG_BP;
} else if (value == "cbp") {
InfAlgorithms::infAlgorithm = InfAlgorithms::CBP;
} else {
cerr << "warning: invalid value `" << value << "' " ;
cerr << "for `" << key << "'" << endl;
return FALSE;
}
} else if (key == "elim_heuristic") {
string value ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG2)));
if ( value == "min_neighbors") {
ElimGraph::setEliminationHeuristic (ElimHeuristic::MIN_NEIGHBORS);
} else if (value == "min_weight") {
ElimGraph::setEliminationHeuristic (ElimHeuristic::MIN_WEIGHT);
} else if (value == "min_fill") {
ElimGraph::setEliminationHeuristic (ElimHeuristic::MIN_FILL);
} else if (value == "weighted_min_fill") {
ElimGraph::setEliminationHeuristic (ElimHeuristic::WEIGHTED_MIN_FILL);
} else {
cerr << "warning: invalid value `" << value << "' " ;
cerr << "for `" << key << "'" << endl;
return FALSE;
}
} else if (key == "schedule") {
string value ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG2)));
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;
return FALSE;
}
} else if (key == "accuracy") {
BpOptions::accuracy = (double) YAP_FloatOfTerm (YAP_ARG2);
} else if (key == "max_iter") {
BpOptions::maxIter = (int) YAP_IntOfTerm (YAP_ARG2);
} else if (key == "always_loopy_solver") {
string value ((char*) YAP_AtomName (YAP_AtomOfTerm (YAP_ARG2)));
if (value == "true") {
BpOptions::useAlwaysLoopySolver = true;
} else if (value == "false") {
BpOptions::useAlwaysLoopySolver = false;
} else {
cerr << "warning: invalid value `" << value << "' " ;
cerr << "for `" << key << "'" << endl;
return FALSE;
}
} else {
cerr << "warning: invalid key `" << key << "'" << endl;
return FALSE;
}
return TRUE;
}
int useLogSpace (void)
{
NSPACE = NumberSpace::LOGARITHM;
return TRUE;
}
int
freeBayesNetwork (void)
{
//Statistics::printCompressingStats ("../../compressing.stats");
//Statistics::writeStatisticsToFile ("stats.txt");
BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1);
bn->freeDistributions();
delete bn;
@ -266,10 +306,12 @@ freeBayesNetwork (void)
extern "C" void
init_predicates (void)
{
YAP_UserCPredicate ("create_network", createNetwork, 2);
YAP_UserCPredicate ("set_extra_vars_info", setExtraVarsInfo, 2);
YAP_UserCPredicate ("set_parameters", setParameters, 2);
YAP_UserCPredicate ("run_solver", runSolver, 3);
YAP_UserCPredicate ("free_bayesian_network", freeBayesNetwork, 1);
YAP_UserCPredicate ("create_network", createNetwork, 2);
YAP_UserCPredicate ("set_extra_vars_info", setExtraVarsInfo, 2);
YAP_UserCPredicate ("set_parameters", setParameters, 2);
YAP_UserCPredicate ("run_solver", runSolver, 3);
YAP_UserCPredicate ("set_solver_parameter", setSolverParameter, 2);
YAP_UserCPredicate ("use_log_space", useLogSpace, 0);
YAP_UserCPredicate ("free_bayesian_network", freeBayesNetwork, 1);
}

View File

@ -1,278 +0,0 @@
#include "LiftedFG.h"
#include "FgVarNode.h"
#include "Factor.h"
#include "Distribution.h"
LiftedFG::LiftedFG (const FactorGraph& fg)
{
groundFg_ = &fg;
freeColor_ = 0;
const FgVarSet& varNodes = fg.getFgVarNodes();
const FactorSet& factors = fg.getFactors();
varColors_.resize (varNodes.size());
factorColors_.resize (factors.size());
for (unsigned i = 0; i < factors.size(); i++) {
factors[i]->setIndex (i);
}
// create the initial variable colors
VarColorMap colorMap;
for (unsigned i = 0; i < varNodes.size(); i++) {
unsigned dsize = varNodes[i]->getDomainSize();
VarColorMap::iterator it = colorMap.find (dsize);
if (it == colorMap.end()) {
it = colorMap.insert (make_pair (
dsize, vector<Color> (dsize + 1,-1))).first;
}
unsigned idx;
if (varNodes[i]->hasEvidence()) {
idx = varNodes[i]->getEvidence();
} else {
idx = dsize;
}
vector<Color>& stateColors = it->second;
if (stateColors[idx] == -1) {
stateColors[idx] = getFreeColor();
}
setColor (varNodes[i], stateColors[idx]);
}
// create the initial factor colors
DistColorMap distColors;
for (unsigned i = 0; i < factors.size(); i++) {
Distribution* dist = factors[i]->getDistribution();
DistColorMap::iterator it = distColors.find (dist);
if (it == distColors.end()) {
it = distColors.insert (make_pair (dist, getFreeColor())).first;
}
setColor (factors[i], it->second);
}
VarSignMap varGroups;
FactorSignMap factorGroups;
bool groupsHaveChanged = true;
unsigned nIter = 0;
while (groupsHaveChanged || nIter == 1) {
nIter ++;
if (Statistics::numCreatedNets == 4) {
cout << "--------------------------------------------" << endl;
cout << "Iteration " << nIter << endl;
cout << "--------------------------------------------" << endl;
}
unsigned prevFactorGroupsSize = factorGroups.size();
factorGroups.clear();
// set a new color to the factors with the same signature
for (unsigned i = 0; i < factors.size(); i++) {
const string& signatureId = getSignatureId (factors[i]);
// cout << factors[i]->getLabel() << " signature: " ;
// cout<< signatureId << endl;
FactorSignMap::iterator it = factorGroups.find (signatureId);
if (it == factorGroups.end()) {
it = factorGroups.insert (make_pair (signatureId, FactorSet())).first;
}
it->second.push_back (factors[i]);
}
if (nIter > 0)
for (FactorSignMap::iterator it = factorGroups.begin();
it != factorGroups.end(); it++) {
Color newColor = getFreeColor();
FactorSet& groupMembers = it->second;
for (unsigned i = 0; i < groupMembers.size(); i++) {
setColor (groupMembers[i], newColor);
}
}
// 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 string& signatureId = getSignatureId (varNodes[i]);
VarSignMap::iterator it = varGroups.find (signatureId);
// cout << varNodes[i]->getLabel() << " signature: " ;
// cout << signatureId << endl;
if (it == varGroups.end()) {
it = varGroups.insert (make_pair (signatureId, FgVarSet())).first;
}
it->second.push_back (varNodes[i]);
}
if (nIter > 0)
for (VarSignMap::iterator it = varGroups.begin();
it != varGroups.end(); it++) {
Color newColor = getFreeColor();
FgVarSet& groupMembers = it->second;
for (unsigned i = 0; i < groupMembers.size(); i++) {
setColor (groupMembers[i], newColor);
}
}
//if (nIter >= 3) cout << "bigger than three: " << nIter << endl;
groupsHaveChanged = prevVarGroupsSize != varGroups.size()
|| prevFactorGroupsSize != factorGroups.size();
}
printGroups (varGroups, factorGroups);
for (VarSignMap::iterator it = varGroups.begin();
it != varGroups.end(); it++) {
CFgVarSet vars = it->second;
VarCluster* vc = new VarCluster (vars);
for (unsigned i = 0; i < vars.size(); i++) {
vid2VarCluster_.insert (make_pair (vars[i]->getVarId(), vc));
}
varClusters_.push_back (vc);
}
for (FactorSignMap::iterator it = factorGroups.begin();
it != factorGroups.end(); it++) {
VarClusterSet varClusters;
Factor* groundFactor = it->second[0];
FgVarSet groundVars = groundFactor->getFgVarNodes();
for (unsigned i = 0; i < groundVars.size(); i++) {
Vid vid = groundVars[i]->getVarId();
varClusters.push_back (vid2VarCluster_.find (vid)->second);
}
factorClusters_.push_back (new FactorCluster (it->second, varClusters));
}
}
LiftedFG::~LiftedFG (void)
{
for (unsigned i = 0; i < varClusters_.size(); i++) {
delete varClusters_[i];
}
for (unsigned i = 0; i < factorClusters_.size(); i++) {
delete factorClusters_[i];
}
}
string
LiftedFG::getSignatureId (FgVarNode* var) const
{
stringstream ss;
CFactorSet myFactors = var->getFactors();
ss << myFactors.size();
for (unsigned i = 0; i < myFactors.size(); i++) {
ss << "." << getColor (myFactors[i]);
ss << "." << myFactors[i]->getIndexOf(var);
}
ss << "." << getColor (var);
return ss.str();
}
string
LiftedFG::getSignatureId (Factor* factor) const
{
stringstream ss;
CFgVarSet myVars = factor->getFgVarNodes();
ss << myVars.size();
for (unsigned i = 0; i < myVars.size(); i++) {
ss << "." << getColor (myVars[i]);
}
ss << "." << getColor (factor);
return ss.str();
}
FactorGraph*
LiftedFG::getCompressedFactorGraph (void)
{
FactorGraph* fg = new FactorGraph();
for (unsigned i = 0; i < varClusters_.size(); i++) {
FgVarNode* var = varClusters_[i]->getGroundFgVarNodes()[0];
FgVarNode* newVar = new FgVarNode (var);
newVar->setIndex (i);
varClusters_[i]->setRepresentativeVariable (newVar);
fg->addVariable (newVar);
}
for (unsigned i = 0; i < factorClusters_.size(); i++) {
FgVarSet myGroundVars;
const VarClusterSet& myVarClusters = factorClusters_[i]->getVarClusters();
for (unsigned j = 0; j < myVarClusters.size(); j++) {
myGroundVars.push_back (myVarClusters[j]->getRepresentativeVariable());
}
Factor* newFactor = new Factor (myGroundVars,
factorClusters_[i]->getGroundFactors()[0]->getDistribution());
factorClusters_[i]->setRepresentativeFactor (newFactor);
fg->addFactor (newFactor);
}
return fg;
}
unsigned
LiftedFG::getGroundEdgeCount (FactorCluster* fc, VarCluster* vc) const
{
CFactorSet clusterGroundFactors = fc->getGroundFactors();
FgVarNode* var = vc->getGroundFgVarNodes()[0];
unsigned count = 0;
for (unsigned i = 0; i < clusterGroundFactors.size(); i++) {
if (clusterGroundFactors[i]->getIndexOf (var) != -1) {
count ++;
}
}
/*
CFgVarSet vars = vc->getGroundFgVarNodes();
for (unsigned i = 1; i < vars.size(); i++) {
FgVarNode* var = vc->getGroundFgVarNodes()[i];
unsigned count2 = 0;
for (unsigned i = 0; i < clusterGroundFactors.size(); i++) {
if (clusterGroundFactors[i]->getIndexOf (var) != -1) {
count2 ++;
}
}
if (count != count2) { cout << "oops!" << endl; abort(); }
}
*/
return count;
}
void
LiftedFG::printGroups (const VarSignMap& varGroups,
const FactorSignMap& factorGroups) const
{
cout << "variable groups:" << endl;
unsigned count = 0;
for (VarSignMap::const_iterator it = varGroups.begin();
it != varGroups.end(); it++) {
const FgVarSet& groupMembers = it->second;
if (groupMembers.size() > 0) {
cout << ++count << ": " ;
//if (groupMembers.size() > 1) {
for (unsigned i = 0; i < groupMembers.size(); i++) {
cout << groupMembers[i]->getLabel() << " " ;
}
//}
cout << endl;
}
}
cout << endl;
cout << "factor groups:" << endl;
count = 0;
for (FactorSignMap::const_iterator it = factorGroups.begin();
it != factorGroups.end(); it++) {
const FactorSet& groupMembers = it->second;
if (groupMembers.size() > 0) {
cout << ++count << ": " ;
//if (groupMembers.size() > 1) {
for (unsigned i = 0; i < groupMembers.size(); i++) {
cout << groupMembers[i]->getLabel() << " " ;
}
//}
cout << endl;
}
}
}

View File

@ -1,152 +0,0 @@
#ifndef BP_LIFTED_FG_H
#define BP_LIFTED_FG_H
#include <unordered_map>
#include "FactorGraph.h"
#include "FgVarNode.h"
#include "Factor.h"
#include "Shared.h"
class VarCluster;
class FactorCluster;
class Distribution;
typedef long Color;
typedef vector<Color> Signature;
typedef vector<VarCluster*> VarClusterSet;
typedef vector<FactorCluster*> FactorClusterSet;
typedef map<string, FgVarSet> VarSignMap;
typedef map<string, FactorSet> FactorSignMap;
typedef map<unsigned, vector<Color> > VarColorMap;
typedef map<Distribution*, Color> DistColorMap;
typedef map<Vid, VarCluster*> Vid2VarCluster;
class VarCluster
{
public:
VarCluster (CFgVarSet vs)
{
for (unsigned i = 0; i < vs.size(); i++) {
groundVars_.push_back (vs[i]);
}
}
void addFactorCluster (FactorCluster* fc)
{
factorClusters_.push_back (fc);
}
const FactorClusterSet& getFactorClusters (void) const
{
return factorClusters_;
}
FgVarNode* getRepresentativeVariable (void) const { return representVar_; }
void setRepresentativeVariable (FgVarNode* v) { representVar_ = v; }
CFgVarSet getGroundFgVarNodes (void) const { return groundVars_; }
private:
FgVarSet groundVars_;
FactorClusterSet factorClusters_;
FgVarNode* representVar_;
};
class FactorCluster
{
public:
FactorCluster (CFactorSet groundFactors, const VarClusterSet& vcs)
{
groundFactors_ = groundFactors;
varClusters_ = vcs;
for (unsigned i = 0; i < varClusters_.size(); i++) {
varClusters_[i]->addFactorCluster (this);
}
}
const VarClusterSet& getVarClusters (void) const
{
return varClusters_;
}
bool containsGround (const Factor* f)
{
for (unsigned i = 0; i < groundFactors_.size(); i++) {
if (groundFactors_[i] == f) {
return true;
}
}
return false;
}
Factor* getRepresentativeFactor (void) const { return representFactor_; }
void setRepresentativeFactor (Factor* f) { representFactor_ = f; }
CFactorSet getGroundFactors (void) const { return groundFactors_; }
private:
FactorSet groundFactors_;
VarClusterSet varClusters_;
Factor* representFactor_;
};
class LiftedFG
{
public:
LiftedFG (const FactorGraph&);
~LiftedFG (void);
FactorGraph* getCompressedFactorGraph (void);
unsigned getGroundEdgeCount (FactorCluster*, VarCluster*) const;
void printGroups (const VarSignMap& varGroups,
const FactorSignMap& factorGroups) const;
FgVarNode* getEquivalentVariable (Vid vid)
{
VarCluster* vc = vid2VarCluster_.find (vid)->second;
return vc->getRepresentativeVariable();
}
const VarClusterSet& getVariableClusters (void) { return varClusters_; }
const FactorClusterSet& getFactorClusters (void) { return factorClusters_; }
private:
string getSignatureId (FgVarNode*) const;
string getSignatureId (Factor*) const;
Color getFreeColor (void) { return ++freeColor_ -1; }
Color getColor (FgVarNode* v) const { return varColors_[v->getIndex()]; }
Color getColor (Factor* f) const { return factorColors_[f->getIndex()]; }
void setColor (FgVarNode* v, Color c)
{
varColors_[v->getIndex()] = c;
}
void setColor (Factor* f, Color c)
{
factorColors_[f->getIndex()] = c;
}
VarCluster* getVariableCluster (Vid vid) const
{
return vid2VarCluster_.find (vid)->second;
}
Color freeColor_;
vector<Color> varColors_;
vector<Color> factorColors_;
VarClusterSet varClusters_;
FactorClusterSet factorClusters_;
Vid2VarCluster vid2VarCluster_;
const FactorGraph* groundFg_;
};
#endif // BP_LIFTED_FG_H

View File

@ -26,10 +26,7 @@ CXX=@CXX@
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
# profiling (callgrind)
#CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -g -DNDEBUG
#CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -g -O0 -Wextra
#
@ -49,33 +46,37 @@ CWD=$(PWD)
HEADERS = \
$(srcdir)/GraphicalModel.h \
$(srcdir)/Variable.h \
$(srcdir)/VarNode.h \
$(srcdir)/Distribution.h \
$(srcdir)/BayesNet.h \
$(srcdir)/BayesNode.h \
$(srcdir)/LiftedFG.h \
$(srcdir)/ElimGraph.h \
$(srcdir)/CFactorGraph.h \
$(srcdir)/CptEntry.h \
$(srcdir)/FactorGraph.h \
$(srcdir)/FgVarNode.h \
$(srcdir)/Factor.h \
$(srcdir)/Solver.h \
$(srcdir)/BPSolver.h \
$(srcdir)/BPNodeInfo.h \
$(srcdir)/SPSolver.h \
$(srcdir)/CountingBP.h \
$(srcdir)/VarElimSolver.h \
$(srcdir)/BnBpSolver.h \
$(srcdir)/FgBpSolver.h \
$(srcdir)/CbpSolver.h \
$(srcdir)/Shared.h \
$(srcdir)/StatesIndexer.h \
$(srcdir)/xmlParser/xmlParser.h
CPP_SOURCES = \
$(srcdir)/BayesNet.cpp \
$(srcdir)/BayesNode.cpp \
$(srcdir)/ElimGraph.cpp \
$(srcdir)/FactorGraph.cpp \
$(srcdir)/Factor.cpp \
$(srcdir)/LiftedFG.cpp \
$(srcdir)/BPSolver.cpp \
$(srcdir)/BPNodeInfo.cpp \
$(srcdir)/SPSolver.cpp \
$(srcdir)/CountingBP.cpp \
$(srcdir)/CFactorGraph.cpp \
$(srcdir)/VarNode.cpp \
$(srcdir)/Solver.cpp \
$(srcdir)/VarElimSolver.cpp \
$(srcdir)/BnBpSolver.cpp \
$(srcdir)/FgBpSolver.cpp \
$(srcdir)/CbpSolver.cpp \
$(srcdir)/Util.cpp \
$(srcdir)/HorusYap.cpp \
$(srcdir)/HorusCli.cpp \
@ -84,29 +85,35 @@ CPP_SOURCES = \
OBJS = \
BayesNet.o \
BayesNode.o \
ElimGraph.o \
FactorGraph.o \
Factor.o \
BPSolver.o \
BPNodeInfo.o \
SPSolver.o \
CFactorGraph.o \
VarNode.o \
Solver.o \
VarElimSolver.o \
BnBpSolver.o \
FgBpSolver.o \
CbpSolver.o \
Util.o \
LiftedFG.o \
CountingBP.o \
HorusYap.o
HCLI_OBJS = \
BayesNet.o \
BayesNode.o \
ElimGraph.o \
FactorGraph.o \
Factor.o \
BPSolver.o \
BPNodeInfo.o \
SPSolver.o \
CFactorGraph.o \
VarNode.o \
Solver.o \
VarElimSolver.o \
BnBpSolver.o \
FgBpSolver.o \
CbpSolver.o \
Util.o \
LiftedFG.o \
CountingBP.o \
HorusCli.o \
xmlParser/xmlParser.o
xmlParser/xmlParser.o \
HorusCli.o
SOBJS=horus.@SO@

View File

@ -1,470 +0,0 @@
#include <cassert>
#include <limits>
#include <iostream>
#include "SPSolver.h"
#include "FactorGraph.h"
#include "FgVarNode.h"
#include "Factor.h"
#include "Shared.h"
SPSolver::SPSolver (FactorGraph& fg) : Solver (&fg)
{
fg_ = &fg;
}
SPSolver::~SPSolver (void)
{
for (unsigned i = 0; i < varsI_.size(); i++) {
delete varsI_[i];
}
for (unsigned i = 0; i < factorsI_.size(); i++) {
delete factorsI_[i];
}
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
}
void
SPSolver::runTreeSolver (void)
{
CFactorSet factors = fg_->getFactors();
bool finish = false;
while (!finish) {
finish = true;
for (unsigned i = 0; i < factors.size(); i++) {
CLinkSet links = factorsI_[factors[i]->getIndex()]->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (!links[j]->messageWasSended()) {
if (readyToSendMessage(links[j])) {
links[j]->setNextMessage (getFactor2VarMsg (links[j]));
links[j]->updateMessage();
}
finish = false;
}
}
}
}
}
bool
SPSolver::readyToSendMessage (const Link* link) const
{
CFgVarSet factorVars = link->getFactor()->getFgVarNodes();
for (unsigned i = 0; i < factorVars.size(); i++) {
if (factorVars[i] != link->getVariable()) {
CLinkSet links = varsI_[factorVars[i]->getIndex()]->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (links[j]->getFactor() != link->getFactor() &&
!links[j]->messageWasSended()) {
return false;
}
}
}
}
return true;
}
void
SPSolver::runSolver (void)
{
initializeSolver();
runTreeSolver();
return;
nIter_ = 0;
while (!converged() && nIter_ < SolverOptions::maxIter) {
nIter_ ++;
if (DL >= 2) {
cout << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
cout << " Iteration " << nIter_ << endl;
cout << "****************************************" ;
cout << "****************************************" ;
cout << endl;
}
switch (SolverOptions::schedule) {
case SolverOptions::S_SEQ_RANDOM:
random_shuffle (links_.begin(), links_.end());
// no break
case SolverOptions::S_SEQ_FIXED:
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->setNextMessage (getFactor2VarMsg (links_[i]));
links_[i]->updateMessage();
}
break;
case SolverOptions::S_PARALLEL:
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->setNextMessage (getFactor2VarMsg (links_[i]));
}
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->updateMessage();
}
break;
case SolverOptions::S_MAX_RESIDUAL:
maxResidualSchedule();
break;
}
}
if (DL >= 2) {
cout << endl;
if (nIter_ < SolverOptions::maxIter) {
cout << "Loopy Sum-Product converged in " ;
cout << nIter_ << " iterations" << endl;
} else {
cout << "The maximum number of iterations was hit, terminating..." ;
cout << endl;
}
}
}
ParamSet
SPSolver::getPosterioriOf (Vid vid) const
{
assert (fg_->getFgVarNode (vid));
FgVarNode* var = fg_->getFgVarNode (vid);
ParamSet probs;
if (var->hasEvidence()) {
probs.resize (var->getDomainSize(), 0.0);
probs[var->getEvidence()] = 1.0;
} else {
probs.resize (var->getDomainSize(), 1.0);
CLinkSet links = varsI_[var->getIndex()]->getLinks();
for (unsigned i = 0; i < links.size(); i++) {
CParamSet msg = links[i]->getMessage();
for (unsigned j = 0; j < msg.size(); j++) {
probs[j] *= msg[j];
}
}
Util::normalize (probs);
}
return probs;
}
ParamSet
SPSolver::getJointDistributionOf (const VidSet& jointVids)
{
FgVarSet jointVars;
unsigned dsize = 1;
for (unsigned i = 0; i < jointVids.size(); i++) {
FgVarNode* varNode = fg_->getFgVarNode (jointVids[i]);
dsize *= varNode->getDomainSize();
jointVars.push_back (varNode);
}
unsigned maxVid = std::numeric_limits<unsigned>::max();
FgVarNode* junctionVar = new FgVarNode (maxVid, dsize);
FgVarSet factorVars = { junctionVar };
for (unsigned i = 0; i < jointVars.size(); i++) {
factorVars.push_back (jointVars[i]);
}
unsigned nParams = dsize * dsize;
ParamSet params (nParams);
for (unsigned i = 0; i < nParams; i++) {
unsigned row = i / dsize;
unsigned col = i % dsize;
if (row == col) {
params[i] = 1;
} else {
params[i] = 0;
}
}
Distribution* dist = new Distribution (params, maxVid);
Factor* newFactor = new Factor (factorVars, dist);
fg_->addVariable (junctionVar);
fg_->addFactor (newFactor);
runSolver();
ParamSet results = getPosterioriOf (maxVid);
deleteJunction (newFactor, junctionVar);
return results;
}
void
SPSolver::initializeSolver (void)
{
fg_->setIndexes();
CFgVarSet vars = fg_->getFgVarNodes();
for (unsigned i = 0; i < varsI_.size(); i++) {
delete varsI_[i];
}
varsI_.reserve (vars.size());
for (unsigned i = 0; i < vars.size(); i++) {
varsI_.push_back (new SPNodeInfo());
}
CFactorSet factors = fg_->getFactors();
for (unsigned i = 0; i < factorsI_.size(); i++) {
delete factorsI_[i];
}
factorsI_.reserve (factors.size());
for (unsigned i = 0; i < factors.size(); i++) {
factorsI_.push_back (new SPNodeInfo());
}
for (unsigned i = 0; i < links_.size(); i++) {
delete links_[i];
}
createLinks();
for (unsigned i = 0; i < links_.size(); i++) {
Factor* source = links_[i]->getFactor();
FgVarNode* dest = links_[i]->getVariable();
varsI_[dest->getIndex()]->addLink (links_[i]);
factorsI_[source->getIndex()]->addLink (links_[i]);
}
}
void
SPSolver::createLinks (void)
{
CFactorSet factors = fg_->getFactors();
for (unsigned i = 0; i < factors.size(); i++) {
CFgVarSet neighbors = factors[i]->getFgVarNodes();
for (unsigned j = 0; j < neighbors.size(); j++) {
links_.push_back (new Link (factors[i], neighbors[j]));
}
}
}
void
SPSolver::deleteJunction (Factor* f, FgVarNode* v)
{
fg_->removeFactor (f);
f->freeDistribution();
delete f;
fg_->removeVariable (v);
delete v;
}
bool
SPSolver::converged (void)
{
// this can happen if the graph is fully disconnected
if (links_.size() == 0) {
return true;
}
if (nIter_ == 0 || nIter_ == 1) {
return false;
}
bool converged = true;
if (SolverOptions::schedule == SolverOptions::S_MAX_RESIDUAL) {
Param maxResidual = (*(sortedOrder_.begin()))->getResidual();
if (maxResidual < SolverOptions::accuracy) {
converged = true;
} else {
converged = false;
}
} else {
for (unsigned i = 0; i < links_.size(); i++) {
double residual = links_[i]->getResidual();
if (DL >= 2) {
cout << links_[i]->toString() + " residual = " << residual << endl;
}
if (residual > SolverOptions::accuracy) {
converged = false;
if (DL == 0) break;
}
}
}
return converged;
}
void
SPSolver::maxResidualSchedule (void)
{
if (nIter_ == 1) {
for (unsigned i = 0; i < links_.size(); i++) {
links_[i]->setNextMessage (getFactor2VarMsg (links_[i]));
SortedOrder::iterator it = sortedOrder_.insert (links_[i]);
linkMap_.insert (make_pair (links_[i], it));
if (DL >= 2 && DL < 5) {
cout << "calculating " << links_[i]->toString() << endl;
}
}
return;
}
for (unsigned c = 0; c < links_.size(); c++) {
if (DL >= 2) {
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();
Link* link = *it;
if (DL >= 2) {
cout << "updating " << (*sortedOrder_.begin())->toString() << endl;
}
if (link->getResidual() < SolverOptions::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
CFactorSet factorNeighbors = link->getVariable()->getFactors();
for (unsigned i = 0; i < factorNeighbors.size(); i++) {
if (factorNeighbors[i] != link->getFactor()) {
CLinkSet links = factorsI_[factorNeighbors[i]->getIndex()]->getLinks();
for (unsigned j = 0; j < links.size(); j++) {
if (links[j]->getVariable() != link->getVariable()) {
if (DL >= 2 && DL < 5) {
cout << " calculating " << links[j]->toString() << endl;
}
links[j]->setNextMessage (getFactor2VarMsg (links[j]));
LinkMap::iterator iter = linkMap_.find (links[j]);
sortedOrder_.erase (iter->second);
iter->second = sortedOrder_.insert (links[j]);
}
}
}
}
}
}
ParamSet
SPSolver::getFactor2VarMsg (const Link* link) const
{
const Factor* src = link->getFactor();
const FgVarNode* dest = link->getVariable();
CFgVarSet neighbors = src->getFgVarNodes();
CLinkSet links = factorsI_[src->getIndex()]->getLinks();
// calculate the product of messages that were sent
// to factor `src', except from var `dest'
Factor result (*src);
Factor temp;
if (DL >= 5) {
cout << "calculating " ;
cout << src->getLabel() << " --> " << dest->getLabel();
cout << endl;
}
for (unsigned i = 0; i < neighbors.size(); i++) {
if (links[i]->getVariable() != dest) {
if (DL >= 5) {
cout << " message from " << links[i]->getVariable()->getLabel();
cout << ": " ;
ParamSet p = getVar2FactorMsg (links[i]);
cout << endl;
Factor temp2 (links[i]->getVariable(), p);
temp.multiplyByFactor (temp2);
temp2.freeDistribution();
} else {
Factor temp2 (links[i]->getVariable(), getVar2FactorMsg (links[i]));
temp.multiplyByFactor (temp2);
temp2.freeDistribution();
}
}
}
if (links.size() >= 2) {
result.multiplyByFactor (temp, &(src->getCptEntries()));
if (DL >= 5) {
cout << " message product: " ;
cout << Util::parametersToString (temp.getParameters()) << endl;
cout << " factor product: " ;
cout << Util::parametersToString (src->getParameters());
cout << " x " ;
cout << Util::parametersToString (temp.getParameters());
cout << " = " ;
cout << Util::parametersToString (result.getParameters()) << endl;
}
temp.freeDistribution();
}
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getVariable() != dest) {
result.removeVariable (links[i]->getVariable());
}
}
if (DL >= 5) {
cout << " final message: " ;
cout << Util::parametersToString (result.getParameters()) << endl << endl;
}
ParamSet msg = result.getParameters();
result.freeDistribution();
return msg;
}
ParamSet
SPSolver::getVar2FactorMsg (const Link* link) const
{
const FgVarNode* src = link->getVariable();
const Factor* dest = link->getFactor();
ParamSet msg;
if (src->hasEvidence()) {
msg.resize (src->getDomainSize(), 0.0);
msg[src->getEvidence()] = 1.0;
if (DL >= 5) {
cout << Util::parametersToString (msg);
}
} else {
msg.resize (src->getDomainSize(), 1.0);
}
if (DL >= 5) {
cout << Util::parametersToString (msg);
}
CLinkSet links = varsI_[src->getIndex()]->getLinks();
for (unsigned i = 0; i < links.size(); i++) {
if (links[i]->getFactor() != dest) {
CParamSet msgFromFactor = links[i]->getMessage();
for (unsigned j = 0; j < msgFromFactor.size(); j++) {
msg[j] *= msgFromFactor[j];
}
if (DL >= 5) {
cout << " x " << Util::parametersToString (msgFromFactor);
}
}
}
if (DL >= 5) {
cout << " = " << Util::parametersToString (msg);
}
return msg;
}

View File

@ -1,130 +0,0 @@
#ifndef BP_SP_SOLVER_H
#define BP_SP_SOLVER_H
#include <vector>
#include <set>
#include "Solver.h"
#include "FgVarNode.h"
#include "Factor.h"
using namespace std;
class FactorGraph;
class SPSolver;
class Link
{
public:
Link (Factor* f, FgVarNode* v)
{
factor_ = f;
var_ = v;
currMsg_.resize (v->getDomainSize(), 1);
nextMsg_.resize (v->getDomainSize(), 1);
msgSended_ = false;
residual_ = 0.0;
}
void setMessage (ParamSet msg)
{
Util::normalize (msg);
residual_ = Util::getMaxNorm (currMsg_, msg);
currMsg_ = msg;
}
void setNextMessage (CParamSet msg)
{
nextMsg_ = msg;
Util::normalize (nextMsg_);
residual_ = Util::getMaxNorm (currMsg_, nextMsg_);
}
void updateMessage (void)
{
currMsg_ = nextMsg_;
msgSended_ = true;
}
string toString (void) const
{
stringstream ss;
ss << factor_->getLabel();
ss << " -- " ;
ss << var_->getLabel();
return ss.str();
}
Factor* getFactor (void) const { return factor_; }
FgVarNode* getVariable (void) const { return var_; }
CParamSet getMessage (void) const { return currMsg_; }
bool messageWasSended (void) const { return msgSended_; }
double getResidual (void) const { return residual_; }
void clearResidual (void) { residual_ = 0.0; }
private:
Factor* factor_;
FgVarNode* var_;
ParamSet currMsg_;
ParamSet nextMsg_;
bool msgSended_;
double residual_;
};
class SPNodeInfo
{
public:
void addLink (Link* link) { links_.push_back (link); }
CLinkSet getLinks (void) { return links_; }
private:
LinkSet links_;
};
class SPSolver : public Solver
{
public:
SPSolver (FactorGraph&);
virtual ~SPSolver (void);
void runSolver (void);
virtual ParamSet getPosterioriOf (Vid) const;
ParamSet getJointDistributionOf (CVidSet);
protected:
virtual void initializeSolver (void);
void runTreeSolver (void);
bool readyToSendMessage (const Link*) const;
virtual void createLinks (void);
virtual void deleteJunction (Factor*, FgVarNode*);
bool converged (void);
virtual void maxResidualSchedule (void);
virtual ParamSet getFactor2VarMsg (const Link*) const;
virtual ParamSet getVar2FactorMsg (const Link*) const;
struct CompareResidual {
inline bool operator() (const Link* link1, const Link* link2)
{
return link1->getResidual() > link2->getResidual();
}
};
FactorGraph* fg_;
LinkSet links_;
vector<SPNodeInfo*> varsI_;
vector<SPNodeInfo*> factorsI_;
unsigned nIter_;
typedef multiset<Link*, CompareResidual> SortedOrder;
SortedOrder sortedOrder_;
typedef map<Link*, SortedOrder::iterator> LinkMap;
LinkMap linkMap_;
};
#endif // BP_SP_SOLVER_H

View File

@ -1,15 +1,15 @@
#ifndef BP_SHARED_H
#define BP_SHARED_H
#ifndef HORUS_SHARED_H
#define HORUS_SHARED_H
#include <cmath>
#include <cassert>
#include <limits>
#include <vector>
#include <map>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include <iomanip>
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
@ -17,34 +17,29 @@
using namespace std;
class Variable;
class VarNode;
class BayesNet;
class BayesNode;
class FgVarNode;
class Factor;
class Link;
class Edge;
class FgVarNode;
class FgFacNode;
class SpLink;
class BpLink;
typedef double Param;
typedef vector<Param> ParamSet;
typedef unsigned VarId;
typedef vector<VarId> VarIdSet;
typedef vector<VarNode*> VarNodes;
typedef vector<BayesNode*> BnNodeSet;
typedef vector<FgVarNode*> FgVarSet;
typedef vector<FgFacNode*> FgFacSet;
typedef vector<Factor*> FactorSet;
typedef vector<string> States;
typedef vector<unsigned> Ranges;
typedef vector<unsigned> DConf;
typedef pair<unsigned, unsigned> DConstraint;
typedef double Param;
typedef vector<Param> ParamSet;
typedef const ParamSet& CParamSet;
typedef unsigned Vid;
typedef vector<Vid> VidSet;
typedef const VidSet& CVidSet;
typedef vector<Variable*> VarSet;
typedef vector<BayesNode*> BnNodeSet;
typedef const BnNodeSet& CBnNodeSet;
typedef vector<FgVarNode*> FgVarSet;
typedef const FgVarSet& CFgVarSet;
typedef vector<Factor*> FactorSet;
typedef const FactorSet& CFactorSet;
typedef vector<Link*> LinkSet;
typedef const LinkSet& CLinkSet;
typedef vector<Edge*> EdgeSet;
typedef const EdgeSet& CEdgeSet;
typedef vector<string> Domain;
typedef vector<unsigned> DConf;
typedef pair<unsigned, unsigned> DConstraint;
typedef map<unsigned, unsigned> IndexMap;
// level of debug information
static const unsigned DL = 0;
@ -54,197 +49,260 @@ static const int NO_EVIDENCE = -1;
// number of digits to show when printing a parameter
static const unsigned PRECISION = 5;
static const bool EXPORT_TO_DOT = false;
static const unsigned EXPORT_MIN_SIZE = 30;
static const bool COLLECT_STATISTICS = false;
static const bool EXPORT_TO_GRAPHVIZ = false;
static const unsigned EXPORT_MINIMAL_SIZE = 100;
static const double INF = -numeric_limits<Param>::infinity();
namespace SolverOptions
{
enum Schedule
{
S_SEQ_FIXED,
S_SEQ_RANDOM,
S_PARALLEL,
S_MAX_RESIDUAL
namespace NumberSpace {
enum ns {
NORMAL,
LOGARITHM
};
};
extern NumberSpace::ns NSPACE;
namespace InfAlgorithms {
enum InfAlgs
{
VE, // variable elimination
BN_BP, // bayesian network belief propagation
FG_BP, // factor graph belief propagation
CBP // counting bp solver
};
extern InfAlgs infAlgorithm;
};
namespace BpOptions
{
enum Schedule {
SEQ_FIXED,
SEQ_RANDOM,
PARALLEL,
MAX_RESIDUAL
};
extern bool runBayesBall;
extern bool convertBn2Fg;
extern bool compressFactorGraph;
extern Schedule schedule;
extern double accuracy;
extern unsigned maxIter;
extern bool useAlwaysLoopySolver;
}
namespace Util
{
void normalize (ParamSet&);
void pow (ParamSet&, unsigned);
double getL1dist (CParamSet, CParamSet);
double getMaxNorm (CParamSet, CParamSet);
bool isInteger (const string&);
string parametersToString (CParamSet);
vector<DConf> getDomainConfigurations (const VarSet&);
vector<string> getInstantiations (const VarSet&);
void toLog (ParamSet&);
void fromLog (ParamSet&);
void normalize (ParamSet&);
void logSum (Param&, Param);
void multiply (ParamSet&, const ParamSet&);
void multiply (ParamSet&, const ParamSet&, unsigned);
void add (ParamSet&, const ParamSet&);
void add (ParamSet&, const ParamSet&, unsigned);
void pow (ParamSet&, unsigned);
Param pow (Param, unsigned);
double getL1Distance (const ParamSet&, const ParamSet&);
double getMaxNorm (const ParamSet&, const ParamSet&);
unsigned getNumberOfDigits (int);
bool isInteger (const string&);
string parametersToString (const ParamSet&, unsigned = PRECISION);
BayesNet* generateBayesianNetworkTreeWithLevel (unsigned);
vector<DConf> getDomainConfigurations (const VarNodes&);
vector<string> getJointStateStrings (const VarNodes&);
double tl (Param v);
double fl (Param v);
double multIdenty();
double addIdenty();
double withEvidence();
double noEvidence();
double one();
double zero();
};
inline void
Util::logSum (Param& x, Param y)
{
// x = log (exp (x) + exp (y)); return;
assert (isfinite (x) && finite (y));
// If one value is much smaller than the other, keep the larger value.
if (x < (y - log (1e200))) {
x = y;
return;
}
if (y < (x - log (1e200))) {
return;
}
double diff = x - y;
assert (isfinite (diff) && finite (x) && finite (y));
if (!isfinite (exp (diff))) { // difference is too large
x = x > y ? x : y;
} else { // otherwise return the sum.
x = y + log (static_cast<double>(1.0) + exp (diff));
}
}
inline void
Util::multiply (ParamSet& v1, const ParamSet& v2)
{
assert (v1.size() == v2.size());
for (unsigned i = 0; i < v1.size(); i++) {
v1[i] *= v2[i];
}
}
inline void
Util::multiply (ParamSet& v1, const ParamSet& 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 (ParamSet& v1, const ParamSet& v2)
{
assert (v1.size() == v2.size());
for (unsigned i = 0; i < v1.size(); i++) {
v1[i] += v2[i];
}
}
inline void
Util::add (ParamSet& v1, const ParamSet& 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 double
Util::tl (Param v)
{
return NSPACE == NumberSpace::NORMAL ? v : log(v);
}
inline double
Util::fl (Param v)
{
return NSPACE == NumberSpace::NORMAL ? v : exp(v);
}
inline double
Util::multIdenty() {
return NSPACE == NumberSpace::NORMAL ? 1.0 : 0.0;
}
inline double
Util::addIdenty()
{
return NSPACE == NumberSpace::NORMAL ? 0.0 : INF;
}
inline double
Util::withEvidence()
{
return NSPACE == NumberSpace::NORMAL ? 1.0 : 0.0;
}
inline double
Util::noEvidence() {
return NSPACE == NumberSpace::NORMAL ? 0.0 : INF;
}
inline double
Util::one()
{
return NSPACE == NumberSpace::NORMAL ? 1.0 : 0.0;
}
inline double
Util::zero() {
return NSPACE == NumberSpace::NORMAL ? 0.0 : INF;
}
struct NetInfo
{
NetInfo (void)
NetInfo (unsigned size, bool loopy, unsigned nIters, double time)
{
counting = 0;
nIters = 0;
solvingTime = 0.0;
this->size = size;
this->loopy = loopy;
this->nIters = nIters;
this->time = time;
}
unsigned counting;
double solvingTime;
unsigned size;
bool loopy;
unsigned nIters;
double time;
};
struct CompressInfo
{
CompressInfo (unsigned a, unsigned b, unsigned c,
unsigned d, unsigned e) {
nUncVars = a;
nUncFactors = b;
nCompVars = c;
nCompFactors = d;
nNeighborlessVars = e;
CompressInfo (unsigned a, unsigned b, unsigned c, unsigned d, unsigned e)
{
nGroundVars = a;
nGroundFactors = b;
nClusterVars = c;
nClusterFactors = d;
nWithoutNeighs = e;
}
unsigned nUncVars;
unsigned nUncFactors;
unsigned nCompVars;
unsigned nCompFactors;
unsigned nNeighborlessVars;
unsigned nGroundVars;
unsigned nGroundFactors;
unsigned nClusterVars;
unsigned nClusterFactors;
unsigned nWithoutNeighs;
};
typedef map<unsigned, NetInfo> StatisticMap;
class Statistics
{
public:
static void updateStats (unsigned size, unsigned nIters, double time)
{
StatisticMap::iterator it = stats_.find (size);
if (it == stats_.end()) {
it = (stats_.insert (make_pair (size, NetInfo()))).first;
} else {
it->second.counting ++;
it->second.nIters += nIters;
it->second.solvingTime += time;
totalOfIterations += nIters;
if (nIters > maxIterations) {
maxIterations = nIters;
}
}
}
static void updateCompressingStats (unsigned nUncVars,
unsigned nUncFactors,
unsigned nCompVars,
unsigned nCompFactors,
unsigned nNeighborlessVars) {
compressInfo_.push_back (CompressInfo (
nUncVars, nUncFactors, nCompVars, nCompFactors, nNeighborlessVars));
}
static void printCompressingStats (const char* fileName)
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "BayesNet::printCompressingStats()" << endl;
abort();
}
out << "--------------------------------------" ;
out << "--------------------------------------" << endl;
out << " Compression Stats" << endl;
out << "--------------------------------------" ;
out << "--------------------------------------" << endl;
out << left;
out << "Uncompress Compressed Uncompress Compressed Neighborless";
out << endl;
out << "Vars Vars Factors Factors Vars" ;
out << endl;
for (unsigned i = 0; i < compressInfo_.size(); i++) {
out << setw (13) << compressInfo_[i].nUncVars;
out << setw (13) << compressInfo_[i].nCompVars;
out << setw (13) << compressInfo_[i].nUncFactors;
out << setw (13) << compressInfo_[i].nCompFactors;
out << setw (13) << compressInfo_[i].nNeighborlessVars;
out << endl;
}
}
static unsigned getCounting (unsigned size)
{
StatisticMap::iterator it = stats_.find(size);
assert (it != stats_.end());
return it->second.counting;
}
static void writeStats (void)
{
ofstream out ("../../stats.txt");
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "Statistics::updateStats()" << endl;
abort();
}
unsigned avgIterations = 0;
if (numSolvedLoopyNets > 0) {
avgIterations = totalOfIterations / numSolvedLoopyNets;
}
double totalSolvingTime = 0.0;
for (StatisticMap::iterator it = stats_.begin();
it != stats_.end(); it++) {
totalSolvingTime += it->second.solvingTime;
}
out << "created networks: " << numCreatedNets << endl;
out << "solver runs on polytrees: " << numSolvedPolyTrees << endl;
out << "solver runs on loopy networks: " << numSolvedLoopyNets << endl;
out << " unconverged: " << numUnconvergedRuns << endl;
out << " max iterations: " << maxIterations << endl;
out << " average iterations: " << avgIterations << endl;
out << "total solving time " << totalSolvingTime << endl;
out << endl;
out << left << endl;
out << setw (15) << "Network Size" ;
out << setw (15) << "Counting" ;
out << setw (15) << "Solving Time" ;
out << setw (15) << "Average Time" ;
out << setw (15) << "#Iterations" ;
out << endl;
for (StatisticMap::iterator it = stats_.begin();
it != stats_.end(); it++) {
out << setw (15) << it->first;
out << setw (15) << it->second.counting;
out << setw (15) << it->second.solvingTime;
if (it->second.counting > 0) {
out << setw (15) << it->second.solvingTime / it->second.counting;
} else {
out << setw (15) << "0.0" ;
}
out << setw (15) << it->second.nIters;
out << endl;
}
out.close();
}
static unsigned numCreatedNets;
static unsigned numSolvedPolyTrees;
static unsigned numSolvedLoopyNets;
static unsigned numUnconvergedRuns;
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 writeStatisticsToFile (const char*);
static void updateCompressingStatistics (
unsigned, unsigned, unsigned, unsigned, unsigned);
private:
static StatisticMap stats_;
static unsigned maxIterations;
static unsigned totalOfIterations;
static string getStatisticString (void);
static vector<NetInfo> netInfo_;
static vector<CompressInfo> compressInfo_;
static unsigned primaryNetCount_;
};
#endif //BP_SHARED_H
#endif // HORUS_SHARED_H

View File

@ -0,0 +1,53 @@
#include "Solver.h"
void
Solver::printAllPosterioris (void)
{
const VarNodes& vars = gm_->getVariableNodes();
for (unsigned i = 0; i < vars.size(); i++) {
printPosterioriOf (vars[i]->varId());
cout << endl;
}
}
void
Solver::printPosterioriOf (VarId vid)
{
VarNode* var = gm_->getVariableNode (vid);
const ParamSet& posterioriDist = getPosterioriOf (vid);
const States& states = var->states();
for (unsigned i = 0; i < states.size(); i++) {
cout << "P(" << var->label() << "=" << states[i] << ") = " ;
cout << setprecision (PRECISION) << posterioriDist[i];
cout << endl;
}
cout << endl;
}
void
Solver::printJointDistributionOf (const VarIdSet& vids)
{
VarNodes vars;
VarIdSet vidsWithoutEvidence;
for (unsigned i = 0; i < vids.size(); i++) {
VarNode* var = gm_->getVariableNode (vids[i]);
if (var->hasEvidence() == false) {
vars.push_back (var);
vidsWithoutEvidence.push_back (vids[i]);
}
}
const ParamSet& jointDist = getJointDistributionOf (vidsWithoutEvidence);
vector<string> jointStrings = Util::getJointStateStrings (vars);
for (unsigned i = 0; i < jointDist.size(); i++) {
cout << "P(" << jointStrings[i] << ") = " ;
cout << setprecision (PRECISION) << jointDist[i];
cout << endl;
}
cout << endl;
}

View File

@ -1,10 +1,10 @@
#ifndef BP_SOLVER_H
#define BP_SOLVER_H
#ifndef HORUS_SOLVER_H
#define HORUS_SOLVER_H
#include <iomanip>
#include "GraphicalModel.h"
#include "Variable.h"
#include "VarNode.h"
using namespace std;
@ -15,66 +15,18 @@ class Solver
{
gm_ = gm;
}
virtual ~Solver() {} // to call subclass destructor
virtual void runSolver (void) = 0;
virtual ParamSet getPosterioriOf (Vid) const = 0;
virtual ParamSet getJointDistributionOf (const VidSet&) = 0;
void printAllPosterioris (void) const
{
VarSet vars = gm_->getVariables();
for (unsigned i = 0; i < vars.size(); i++) {
printPosterioriOf (vars[i]->getVarId());
}
}
void printPosterioriOf (Vid vid) const
{
Variable* var = gm_->getVariable (vid);
cout << endl;
cout << setw (20) << left << var->getLabel() << "posteriori" ;
cout << endl;
cout << "------------------------------" ;
cout << endl;
const Domain& domain = var->getDomain();
ParamSet results = getPosterioriOf (vid);
for (unsigned xi = 0; xi < var->getDomainSize(); xi++) {
cout << setw (20) << domain[xi];
cout << setprecision (PRECISION) << results[xi];
cout << endl;
}
cout << endl;
}
void printJointDistributionOf (const VidSet& vids)
{
const ParamSet& jointDist = getJointDistributionOf (vids);
cout << endl;
cout << "joint distribution of " ;
VarSet vars;
for (unsigned i = 0; i < vids.size() - 1; i++) {
Variable* var = gm_->getVariable (vids[i]);
cout << var->getLabel() << ", " ;
vars.push_back (var);
}
Variable* var = gm_->getVariable (vids[vids.size() - 1]);
cout << var->getLabel() ;
vars.push_back (var);
cout << endl;
cout << "------------------------------" ;
cout << endl;
const vector<string>& domainConfs = Util::getInstantiations (vars);
for (unsigned i = 0; i < jointDist.size(); i++) {
cout << left << setw (20) << domainConfs[i];
cout << setprecision (PRECISION) << jointDist[i];
cout << endl;
}
cout << endl;
}
virtual ~Solver() {} // to ensure that subclass destructor is called
virtual void runSolver (void) = 0;
virtual ParamSet getPosterioriOf (VarId) = 0;
virtual ParamSet getJointDistributionOf (const VarIdSet&) = 0;
void printAllPosterioris (void);
void printPosterioriOf (VarId vid);
void printJointDistributionOf (const VarIdSet& vids);
private:
const GraphicalModel* gm_;
};
#endif //BP_SOLVER_H
#endif // HORUS_SOLVER_H

View File

@ -0,0 +1,246 @@
#ifndef HORUS_STATESINDEXER_H
#define HORUS_STATESINDEXER_H
#include <iomanip>
class StatesIndexer {
public:
StatesIndexer (const Ranges& ranges)
{
maxIndex_ = 1;
states_.resize (ranges.size(), 0);
ranges_ = ranges;
for (unsigned i = 0; i < ranges.size(); i++) {
maxIndex_ *= ranges[i];
}
linearIndex_ = 0;
}
StatesIndexer (const VarNodes& vars)
{
maxIndex_ = 1;
states_.resize (vars.size(), 0);
ranges_.reserve (vars.size());
for (unsigned i = 0; i < vars.size(); i++) {
ranges_.push_back (vars[i]->nrStates());
maxIndex_ *= vars[i]->nrStates();
}
linearIndex_ = 0;
}
StatesIndexer& operator++ (void) {
for (int i = ranges_.size() - 1; i >= 0; i--) {
states_[i] ++;
if (states_[i] == (int)ranges_[i]) {
states_[i] = 0;
} else {
break;
}
}
linearIndex_ ++;
return *this;
}
StatesIndexer& operator-- (void) {
for (int i = ranges_.size() - 1; i >= 0; i--) {
states_[i] --;
if (states_[i] == -1) {
states_[i] = ranges_[i] - 1;
} else {
break;
}
}
linearIndex_ --;
return *this;
}
void incrementState (unsigned whichVar)
{
for (int i = whichVar; i >= 0; i--) {
states_[i] ++;
if (states_[i] == (int)ranges_[i] && i != 0) {
if (i == 0) {
linearIndex_ = maxIndex_;
} else {
states_[i] = 0;
}
} else {
linearIndex_ = getLinearIndexFromStates();
return;
}
}
}
void decrementState (unsigned whichVar)
{
for (int i = whichVar; i >= 0; i--) {
states_[i] --;
if (states_[i] == -1) {
if (i == 0) {
linearIndex_ = -1;
} else {
states_[i] = ranges_[i] - 1;
}
} else {
linearIndex_ = getLinearIndexFromStates();
return;
}
}
}
void nextSameState (unsigned whichVar)
{
for (int i = ranges_.size() - 1; i >= 0; i--) {
if (i != (int)whichVar) {
states_[i] ++;
if (states_[i] == (int)ranges_[i]) {
if (i == 0 || (i-1 == (int)whichVar && whichVar == 0)) {
linearIndex_ = maxIndex_;
} else {
states_[i] = 0;
}
} else {
linearIndex_ = getLinearIndexFromStates();
return;
}
}
}
}
void previousSameState (unsigned whichVar)
{
for (int i = ranges_.size() - 1; i >= 0; i--) {
if (i != (int)whichVar) {
states_[i] --;
if (states_[i] == - 1) {
if (i == 0 || (i-1 == (int)whichVar && whichVar == 0)) {
linearIndex_ = -1;
} else {
states_[i] = ranges_[i] - 1;
}
} else {
linearIndex_ = getLinearIndexFromStates();
return;
}
}
}
}
void moveToBegin (void)
{
std::fill (states_.begin(), states_.end(), 0);
linearIndex_ = 0;
}
void moveToEnd (void)
{
for (unsigned i = 0; i < states_.size(); i++) {
states_[i] = ranges_[i] - 1;
}
linearIndex_ = maxIndex_ - 1;
}
bool valid (void) const
{
return linearIndex_ >= 0 && linearIndex_ < (int)maxIndex_;
}
unsigned getLinearIndex (void) const
{
return linearIndex_;
}
const vector<int>& getStates (void) const
{
return states_;
}
unsigned operator[] (unsigned whichVar) const
{
assert (valid());
assert (whichVar < states_.size());
return states_[whichVar];
}
string toString (void) const
{
stringstream ss;
ss << "linear index=" << setw (3) << linearIndex_ << " " ;
ss << "states= [" << states_[0] ;
for (unsigned i = 1; i < states_.size(); i++) {
ss << ", " << states_[i];
}
ss << "]" ;
return ss.str();
}
private:
unsigned getLinearIndexFromStates (void)
{
unsigned prod = 1;
unsigned linearIndex = 0;
for (int i = states_.size() - 1; i >= 0; i--) {
linearIndex += states_[i] * prod;
prod *= ranges_[i];
}
return linearIndex;
}
int linearIndex_;
int maxIndex_;
vector<int> states_;
vector<unsigned> ranges_;
};
/*
FgVarNode* v1 = new FgVarNode (0, 4);
FgVarNode* v2 = new FgVarNode (1, 3);
FgVarNode* v3 = new FgVarNode (2, 2);
FgVarSet vars = {v1,v2,v3};
ParamSet params = {
0.2, 0.44, 0.1, 0.88, 0.22,0.62,0.32, 0.42, 0.11, 0.88, 0.8,0.5,
0.22, 0.4, 0.11, 0.8, 0.224,0.6,0.21, 0.44, 0.14, 0.68, 0.41,0.6
};
Factor f (vars,params);
StatesIndexer idx (vars);
while (idx.valid())
{
cout << idx.toString() << " p=" << params[idx.getLinearIndex()] << endl;
idx.incrementVariableState (0);
idx.nextSameState (1);
++idx;
}
cout << endl;
idx.moveToEnd();
while (idx.valid())
{
cout << idx.toString() << " p=" << params[idx.getLinearIndex()] << endl;
idx.decrementVariableState (0);
idx.previousSameState (1);
--idx;
}
*/
/*
FgVarNode* x0 = new FgVarNode (0, 2);
FgVarNode* x1 = new FgVarNode (1, 2);
FgVarNode* x2 = new FgVarNode (2, 2);
FgVarNode* x3 = new FgVarNode (2, 2);
FgVarNode* x4 = new FgVarNode (2, 2);
FgVarSet vars_ = {x0,x1,x2,x3,x4};
ParamSet params_ = {
0.2, 0.44, 0.1, 0.88, 0.11, 0.88, 0.8, 0.5,
0.2, 0.44, 0.1, 0.88, 0.11, 0.88, 0.8, 0.5,
0.2, 0.44, 0.1, 0.88, 0.11, 0.88, 0.8, 0.5,
0.2, 0.44, 0.1, 0.88, 0.11, 0.88, 0.8, 0.5
};
Factor ff (vars_,params_);
ff.printFactor();
*/
#endif // HORUS_STATESINDEXER_H

View File

@ -1,91 +1,191 @@
#include <sstream>
#include "Variable.h"
#include "BayesNet.h"
#include "VarNode.h"
#include "Shared.h"
#include "StatesIndexer.h"
namespace SolverOptions {
bool runBayesBall = false;
bool convertBn2Fg = true;
bool compressFactorGraph = true;
Schedule schedule = S_SEQ_FIXED;
//Schedule schedule = S_SEQ_RANDOM;
//Schedule schedule = S_PARALLEL;
//Schedule schedule = S_MAX_RESIDUAL;
double accuracy = 0.0001;
unsigned maxIter = 1000; //FIXME
namespace InfAlgorithms {
InfAlgs infAlgorithm = InfAlgorithms::VE;
//InfAlgs infAlgorithm = InfAlgorithms::BN_BP;
//InfAlgs infAlgorithm = InfAlgorithms::FG_BP;
//InfAlgs infAlgorithm = InfAlgorithms::CBP;
}
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;
bool useAlwaysLoopySolver = true;
}
unsigned Statistics::numCreatedNets = 0;
unsigned Statistics::numSolvedPolyTrees = 0;
unsigned Statistics::numSolvedLoopyNets = 0;
unsigned Statistics::numUnconvergedRuns = 0;
unsigned Statistics::maxIterations = 0;
unsigned Statistics::totalOfIterations = 0;
NumberSpace::ns NSPACE = NumberSpace::NORMAL;
unordered_map<VarId,VariableInfo> GraphicalModel::varsInfo_;
vector<NetInfo> Statistics::netInfo_;
vector<CompressInfo> Statistics::compressInfo_;
StatisticMap Statistics::stats_;
unsigned Statistics::primaryNetCount_;
namespace Util {
void
normalize (ParamSet& v)
toLog (ParamSet& v)
{
double sum = 0.0;
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;
v[i] = log (v[i]);
}
}
void
fromLog (ParamSet& v)
{
for (unsigned i = 0; i < v.size(); i++) {
v[i] = exp (v[i]);
}
}
void
normalize (ParamSet& v)
{
double sum;
switch (NSPACE) {
case NumberSpace::NORMAL:
sum = 0.0;
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;
}
break;
case NumberSpace::LOGARITHM:
sum = addIdenty();
for (unsigned i = 0; i < v.size(); i++) {
logSum (sum, v[i]);
}
assert (sum != -numeric_limits<Param>::infinity());
for (unsigned i = 0; i < v.size(); i++) {
v[i] -= sum;
}
}
}
void
pow (ParamSet& v, unsigned expoent)
{
for (unsigned i = 0; i < v.size(); i++) {
double value = 1;
for (unsigned j = 0; j < expoent; j++) {
value *= v[i];
}
v[i] = value;
if (expoent == 1) {
return; // optimization
}
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < v.size(); i++) {
double value = 1.0;
for (unsigned j = 0; j < expoent; j++) {
value *= v[i];
}
v[i] = value;
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < v.size(); i++) {
v[i] *= expoent;
}
}
}
Param
pow (Param p, unsigned expoent)
{
double value = 1.0;
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < expoent; i++) {
value *= p;
}
break;
case NumberSpace::LOGARITHM:
value = p * expoent;
}
return value;
}
double
getL1dist (const ParamSet& v1, const ParamSet& v2)
getL1Distance (const ParamSet& v1, const ParamSet& v2)
{
assert (v1.size() == v2.size());
double dist = 0.0;
for (unsigned i = 0; i < v1.size(); i++) {
dist += abs (v1[i] - v2[i]);
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < v1.size(); i++) {
dist += abs (v1[i] - v2[i]);
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < v1.size(); i++) {
dist += abs (exp(v1[i]) - exp(v2[i]));
}
}
return dist;
}
double
getMaxNorm (const ParamSet& v1, const ParamSet& v2)
{
assert (v1.size() == v2.size());
double max = 0.0;
for (unsigned i = 0; i < v1.size(); i++) {
double diff = abs (v1[i] - v2[i]);
if (diff > max) {
max = diff;
}
switch (NSPACE) {
case NumberSpace::NORMAL:
for (unsigned i = 0; i < v1.size(); i++) {
double diff = abs (v1[i] - v2[i]);
if (diff > max) {
max = diff;
}
}
break;
case NumberSpace::LOGARITHM:
for (unsigned i = 0; i < v1.size(); i++) {
double diff = abs (exp(v1[i]) - exp(v2[i]));
if (diff > max) {
max = diff;
}
}
}
return max;
}
unsigned
getNumberOfDigits (int number) {
unsigned count = 1;
while (number >= 10) {
number /= 10;
count ++;
}
return count;
}
bool
isInteger (const string& s)
{
@ -100,9 +200,10 @@ isInteger (const string& s)
string
parametersToString (CParamSet v)
parametersToString (const ParamSet& v, unsigned precision)
{
stringstream ss;
stringstream ss;
ss.precision (precision);
ss << "[" ;
for (unsigned i = 0; i < v.size() - 1; i++) {
ss << v[i] << ", " ;
@ -116,12 +217,44 @@ parametersToString (CParamSet v)
vector<DConf>
getDomainConfigurations (const VarSet& vars)
BayesNet*
generateBayesianNetworkTreeWithLevel (unsigned level)
{
BayesNet* bn = new BayesNet();
Distribution* dist = new Distribution (ParamSet() = {0.1, 0.5, 0.2, 0.7});
BayesNode* root = bn->addNode (0, 2, -1, BnNodeSet() = {},
new Distribution (ParamSet() = {0.1, 0.5}));
BnNodeSet prevLevel = { root };
BnNodeSet currLevel;
VarId vidCount = 1;
for (unsigned l = 1; l < level; l++) {
currLevel.clear();
for (unsigned i = 0; i < prevLevel.size(); i++) {
currLevel.push_back (
bn->addNode (vidCount, 2, -1, BnNodeSet() = {prevLevel[i]}, dist));
vidCount ++;
currLevel.push_back (
bn->addNode (vidCount, 2, -1, BnNodeSet() = {prevLevel[i]}, dist));
vidCount ++;
}
prevLevel = currLevel;
}
for (unsigned i = 0; i < prevLevel.size(); i++) {
prevLevel[i]->setEvidence (0);
}
bn->setIndexes();
return bn;
}
vector<DConf>
getDomainConfigurations (const VarNodes& vars)
{
// TODO this method must die
unsigned nConfs = 1;
for (unsigned i = 0; i < vars.size(); i++) {
nConfs *= vars[i]->getDomainSize();
nConfs *= vars[i]->nrStates();
}
vector<DConf> confs (nConfs);
@ -133,59 +266,213 @@ getDomainConfigurations (const VarSet& vars)
for (int i = vars.size() - 1; i >= 0; i--) {
unsigned index = 0;
while (index < nConfs) {
for (unsigned j = 0; j < vars[i]->getDomainSize(); j++) {
for (unsigned j = 0; j < vars[i]->nrStates(); j++) {
for (unsigned r = 0; r < nReps; r++) {
confs[index][i] = j;
index++;
}
}
}
nReps *= vars[i]->getDomainSize();
nReps *= vars[i]->nrStates();
}
return confs;
}
vector<string>
getInstantiations (const VarSet& vars)
getJointStateStrings (const VarNodes& vars)
{
//FIXME handle variables without domain
/*
char c = 'a' ;
const DConf& conf = entries[i].getDomainConfiguration();
for (unsigned j = 0; j < conf.size(); j++) {
if (j != 0) ss << "," ;
ss << c << conf[j] + 1;
c ++;
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;
}
*/
unsigned rowSize = 1;
for (unsigned i = 0; i < vars.size(); i++) {
rowSize *= vars[i]->getDomainSize();
return jointStrings;
}
}
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::writeStatisticsToFile (const char* fileName)
{
ofstream out (fileName);
if (!out.is_open()) {
cerr << "error: cannot open file to write at " ;
cerr << "Statistics::writeStatisticsToFile()" << endl;
abort();
}
out << getStatisticString();
out.close();
}
vector<string> headers (rowSize);
unsigned nReps = 1;
for (int i = vars.size() - 1; i >= 0; i--) {
Domain domain = vars[i]->getDomain();
unsigned index = 0;
while (index < rowSize) {
for (unsigned j = 0; j < vars[i]->getDomainSize(); j++) {
for (unsigned r = 0; r < nReps; r++) {
if (headers[index] != "") {
headers[index] = domain[j] + ", " + headers[index];
} else {
headers[index] = domain[j];
}
index++;
}
void
Statistics::updateCompressingStatistics (unsigned nGroundVars,
unsigned nGroundFactors,
unsigned nClusterVars,
unsigned nClusterFactors,
unsigned nWithoutNeighs) {
compressInfo_.push_back (CompressInfo (nGroundVars, nGroundFactors,
nClusterVars, nClusterFactors, nWithoutNeighs));
}
string
Statistics::getStatisticString (void)
{
stringstream ss2, ss3, ss4, ss1;
ss1 << "running mode: " ;
switch (InfAlgorithms::infAlgorithm) {
case InfAlgorithms::VE: ss1 << "ve" << endl; break;
case InfAlgorithms::BN_BP: ss1 << "bn_bp" << endl; break;
case InfAlgorithms::FG_BP: ss1 << "fg_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;
if (BpOptions::useAlwaysLoopySolver) {
ss1 << "always loopy solver: yes" << endl;
} else {
ss1 << "always loopy solver: no" << endl;
}
ss1 << endl << endl;
ss2 << "---------------------------------------------------" << endl;
ss2 << " Network information" << endl;
ss2 << "---------------------------------------------------" << endl;
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 ++;
}
}
nReps *= vars[i]->getDomainSize();
ss2 << setw (15) << netInfo_[i].time;
totalSolvingTime += netInfo_[i].time;
ss2 << endl;
}
return headers;
}
ss2 << endl << endl;
unsigned c1 = 0, c2 = 0, c3 = 0, c4 = 0;
if (compressInfo_.size() > 0) {
ss3 << "---------------------------------------------------" << endl;
ss3 << " Compression information" << endl;
ss3 << "---------------------------------------------------" << endl;
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].nGroundVars;
ss3 << setw (10) << compressInfo_[i].nClusterVars;
ss3 << setw (10) << compressInfo_[i].nGroundFactors;
ss3 << setw (10) << compressInfo_[i].nClusterFactors;
ss3 << setw (10) << compressInfo_[i].nWithoutNeighs;
ss3 << endl;
c1 += compressInfo_[i].nGroundVars - compressInfo_[i].nWithoutNeighs;
c2 += compressInfo_[i].nClusterVars;
c3 += compressInfo_[i].nGroundFactors - compressInfo_[i].nWithoutNeighs;
c4 += compressInfo_[i].nClusterFactors;
if (compressInfo_[i].nWithoutNeighs != 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();
}

View File

@ -0,0 +1,211 @@
#include <algorithm>
#include "VarElimSolver.h"
#include "ElimGraph.h"
#include "Factor.h"
VarElimSolver::VarElimSolver (const BayesNet& bn) : Solver (&bn)
{
bayesNet_ = &bn;
factorGraph_ = new FactorGraph (bn);
}
VarElimSolver::VarElimSolver (const FactorGraph& fg) : Solver (&fg)
{
bayesNet_ = 0;
factorGraph_ = &fg;
}
VarElimSolver::~VarElimSolver (void)
{
if (bayesNet_) {
delete factorGraph_;
}
}
ParamSet
VarElimSolver::getPosterioriOf (VarId vid)
{
FgVarNode* vn = factorGraph_->getFgVarNode (vid);
assert (vn);
if (vn->hasEvidence()) {
ParamSet params (vn->nrStates(), 0.0);
params[vn->getEvidence()] = 1.0;
return params;
}
return getJointDistributionOf (VarIdSet() = {vid});
}
ParamSet
VarElimSolver::getJointDistributionOf (const VarIdSet& vids)
{
factorList_.clear();
varFactors_.clear();
elimOrder_.clear();
createFactorList();
introduceEvidence();
chooseEliminationOrder (vids);
processFactorList (vids);
ParamSet params = factorList_.back()->getParameters();
factorList_.back()->freeDistribution();
delete factorList_.back();
Util::normalize (params);
return params;
}
void
VarElimSolver::createFactorList (void)
{
const FgFacSet& factorNodes = factorGraph_->getFactorNodes();
factorList_.reserve (factorNodes.size() * 2);
for (unsigned i = 0; i < factorNodes.size(); i++) {
factorList_.push_back (new Factor (*factorNodes[i]->factor()));
const FgVarSet& neighs = factorNodes[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::introduceEvidence (void)
{
const FgVarSet& varNodes = factorGraph_->getVarNodes();
for (unsigned i = 0; i < varNodes.size(); i++) {
if (varNodes[i]->hasEvidence()) {
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->nrVariables() == 1) {
factorList_[idxs[j]] = 0;
} else {
factorList_[idxs[j]]->removeInconsistentEntries (
varNodes[i]->varId(), varNodes[i]->getEvidence());
}
}
}
}
}
void
VarElimSolver::chooseEliminationOrder (const VarIdSet& vids)
{
if (bayesNet_) {
ElimGraph graph = ElimGraph (*bayesNet_);
elimOrder_ = graph.getEliminatingOrder (vids);
} else {
const FgVarSet& varNodes = factorGraph_->getVarNodes();
for (unsigned i = 0; i < varNodes.size(); i++) {
VarId vid = varNodes[i]->varId();
if (std::find (vids.begin(), vids.end(), vid) == vids.end()
&& !varNodes[i]->hasEvidence()) {
elimOrder_.push_back (vid);
}
}
}
}
void
VarElimSolver::processFactorList (const VarIdSet& vids)
{
for (unsigned i = 0; i < elimOrder_.size(); i++) {
// cout << "-----------------------------------------" << endl;
// cout << "Eliminating " << elimOrder_[i];
// cout << " in the following factors:" << endl;
// printActiveFactors();
eliminate (elimOrder_[i]);
}
Factor* thisIsTheEnd = new Factor();
for (unsigned i = 0; i < factorList_.size(); i++) {
if (factorList_[i]) {
thisIsTheEnd->multiplyByFactor (*factorList_[i]);
factorList_[i]->freeDistribution();
delete factorList_[i];
factorList_[i] = 0;
}
}
VarIdSet vidsWithoutEvidence;
for (unsigned i = 0; i < vids.size(); i++) {
if (factorGraph_->getFgVarNode (vids[i])->hasEvidence() == false) {
vidsWithoutEvidence.push_back (vids[i]);
}
}
thisIsTheEnd->orderVariables (vidsWithoutEvidence);
factorList_.push_back (thisIsTheEnd);
}
void
VarElimSolver::eliminate (VarId elimVar)
{
FgVarNode* vn = factorGraph_->getFgVarNode (elimVar);
Factor* result = 0;
vector<unsigned>& idxs = varFactors_.find (elimVar)->second;
//cout << "eliminating " << setw (5) << elimVar << ":" ;
for (unsigned i = 0; i < idxs.size(); i++) {
unsigned idx = idxs[i];
if (factorList_[idx]) {
if (result == 0) {
result = new Factor(*factorList_[idx]);
//cout << " " << factorList_[idx]->label();
} else {
result->multiplyByFactor (*factorList_[idx]);
//cout << " x " << factorList_[idx]->label();
}
factorList_[idx]->freeDistribution();
delete factorList_[idx];
factorList_[idx] = 0;
}
}
if (result != 0 && result->nrVariables() != 1) {
result->removeVariable (vn->varId());
factorList_.push_back (result);
// cout << endl <<" factor size=" << result->size() << endl;
const VarIdSet& resultVarIds = result->getVarIds();
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) {
factorList_[i]->printFactor();
cout << endl;
}
}
}

View File

@ -0,0 +1,41 @@
#ifndef HORUS_VARELIMSOLVER_H
#define HORUS_VARELIMSOLVER_H
#include "unordered_map"
#include "Solver.h"
#include "FactorGraph.h"
#include "BayesNet.h"
#include "Shared.h"
using namespace std;
class VarElimSolver : public Solver
{
public:
VarElimSolver (const BayesNet&);
VarElimSolver (const FactorGraph&);
~VarElimSolver (void);
void runSolver (void) { }
ParamSet getPosterioriOf (VarId);
ParamSet getJointDistributionOf (const VarIdSet&);
private:
void createFactorList (void);
void introduceEvidence (void);
void chooseEliminationOrder (const VarIdSet&);
void processFactorList (const VarIdSet&);
void eliminate (VarId);
void printActiveFactors (void);
const BayesNet* bayesNet_;
const FactorGraph* factorGraph_;
vector<Factor*> factorList_;
VarIdSet elimOrder_;
unordered_map<VarId, vector<unsigned>> varFactors_;
};
#endif // HORUS_VARELIMSOLVER_H

View File

@ -0,0 +1,100 @@
#include <algorithm>
#include <sstream>
#include "VarNode.h"
#include "GraphicalModel.h"
using namespace std;
VarNode::VarNode (const VarNode* v)
{
varId_ = v->varId();
nrStates_ = v->nrStates();
evidence_ = v->getEvidence();
index_ = std::numeric_limits<unsigned>::max();
}
VarNode::VarNode (VarId varId, unsigned nrStates, int evidence)
{
assert (nrStates != 0);
assert (evidence < (int) nrStates);
varId_ = varId;
nrStates_ = nrStates;
evidence_ = evidence;
index_ = std::numeric_limits<unsigned>::max();
}
bool
VarNode::isValidState (int stateIndex)
{
return stateIndex >= 0 && stateIndex < (int) nrStates_;
}
bool
VarNode::isValidState (const string& stateName)
{
States states = GraphicalModel::getVariableInformation (varId_).states;
return find (states.begin(), states.end(), stateName) != states.end();
}
void
VarNode::setEvidence (int ev)
{
assert (ev < (int) nrStates_);
evidence_ = ev;
}
void
VarNode::setEvidence (const string& ev)
{
States states = GraphicalModel::getVariableInformation (varId_).states;
for (unsigned i = 0; i < states.size(); i++) {
if (states[i] == ev) {
evidence_ = i;
return;
}
}
assert (false);
}
string
VarNode::label (void) const
{
if (GraphicalModel::variablesHaveInformation()) {
return GraphicalModel::getVariableInformation (varId_).label;
}
stringstream ss;
ss << "x" << varId_;
return ss.str();
}
States
VarNode::states (void) const
{
if (GraphicalModel::variablesHaveInformation()) {
return GraphicalModel::getVariableInformation (varId_).states;
}
States states;
for (unsigned i = 0; i < nrStates_; i++) {
stringstream ss;
ss << i ;
states.push_back (ss.str());
}
return states;
}

View File

@ -0,0 +1,52 @@
#ifndef HORUS_VARNODE_H
#define HORUS_VARNODE_H
#include "Shared.h"
using namespace std;
class VarNode
{
public:
VarNode (const VarNode*);
VarNode (VarId, unsigned, int = NO_EVIDENCE);
virtual ~VarNode (void) {};
bool isValidState (int);
bool isValidState (const string&);
void setEvidence (int);
void setEvidence (const string&);
string label (void) const;
States states (void) const;
unsigned varId (void) const { return varId_; }
unsigned nrStates (void) const { return nrStates_; }
bool hasEvidence (void) const { return evidence_ != NO_EVIDENCE; }
int getEvidence (void) const { return evidence_; }
unsigned getIndex (void) const { return index_; }
void setIndex (unsigned idx) { index_ = idx; }
operator unsigned () const { return index_; }
bool operator== (const VarNode& var) const
{
assert (!(varId_ == var.varId() && nrStates_ != var.nrStates()));
return varId_ == var.varId();
}
bool operator!= (const VarNode& var) const
{
assert (!(varId_ == var.varId() && nrStates_ != var.nrStates()));
return varId_ != var.varId();
}
private:
VarId varId_;
unsigned nrStates_;
int evidence_;
unsigned index_;
};
#endif // BP_VARNODE_H

View File

@ -1,172 +0,0 @@
#ifndef BP_VARIABLE_H
#define BP_VARIABLE_H
#include <algorithm>
#include <sstream>
#include "Shared.h"
using namespace std;
class Variable
{
public:
Variable (const Variable* v)
{
vid_ = v->getVarId();
dsize_ = v->getDomainSize();
if (v->hasDomain()) {
domain_ = v->getDomain();
dsize_ = domain_.size();
} else {
dsize_ = v->getDomainSize();
}
evidence_ = v->getEvidence();
if (v->hasLabel()) {
label_ = new string (v->getLabel());
} else {
label_ = 0;
}
}
Variable (Vid vid)
{
this->vid_ = vid;
this->dsize_ = 0;
this->evidence_ = NO_EVIDENCE;
this->label_ = 0;
}
Variable (Vid vid, unsigned dsize, int evidence = NO_EVIDENCE,
const string& lbl = string())
{
assert (dsize != 0);
assert (evidence < (int)dsize);
this->vid_ = vid;
this->dsize_ = dsize;
this->evidence_ = evidence;
if (!lbl.empty()) {
this->label_ = new string (lbl);
} else {
this->label_ = 0;
}
}
Variable (Vid vid, const Domain& domain, int evidence = NO_EVIDENCE,
const string& lbl = string())
{
assert (!domain.empty());
assert (evidence < (int)domain.size());
this->vid_ = vid;
this->dsize_ = domain.size();
this->domain_ = domain;
this->evidence_ = evidence;
if (!lbl.empty()) {
this->label_ = new string (lbl);
} else {
this->label_ = 0;
}
}
~Variable (void)
{
delete label_;
}
unsigned getVarId (void) const { return vid_; }
unsigned getIndex (void) const { return index_; }
void setIndex (unsigned idx) { index_ = idx; }
unsigned getDomainSize (void) const { return dsize_; }
bool hasEvidence (void) const { return evidence_ != NO_EVIDENCE; }
int getEvidence (void) const { return evidence_; }
bool hasDomain (void) const { return !domain_.empty(); }
bool hasLabel (void) const { return label_ != 0; }
bool isValidStateIndex (int index)
{
return index >= 0 && index < (int)dsize_;
}
bool isValidState (const string& state)
{
return find (domain_.begin(), domain_.end(), state) != domain_.end();
}
Domain getDomain (void) const
{
assert (dsize_ != 0);
if (domain_.size() == 0) {
Domain d;
for (unsigned i = 0; i < dsize_; i++) {
stringstream ss;
ss << "x" << i ;
d.push_back (ss.str());
}
return d;
} else {
return domain_;
}
}
void setDomainSize (unsigned dsize)
{
assert (dsize != 0);
dsize_ = dsize;
}
void setDomain (const Domain& domain)
{
assert (!domain.empty());
domain_ = domain;
dsize_ = domain.size();
}
void setEvidence (int ev)
{
assert (ev < dsize_);
evidence_ = ev;
}
void setEvidence (const string& ev)
{
assert (isValidState (ev));
for (unsigned i = 0; i < domain_.size(); i++) {
if (domain_[i] == ev) {
evidence_ = i;
}
}
}
void setLabel (const string& label)
{
label_ = new string (label);
}
string getLabel (void) const
{
if (label_ == 0) {
stringstream ss;
ss << "v" << vid_;
return ss.str();
} else {
return *label_;
}
}
private:
DISALLOW_COPY_AND_ASSIGN (Variable);
Vid vid_;
unsigned dsize_;
int evidence_;
Domain domain_;
string* label_;
unsigned index_;
};
#endif // BP_VARIABLE_H

View File

@ -1,147 +0,0 @@
/*
----------------------------------------------------------------
Notice that the following BSD-style license applies to this one
file (callgrind.h) only. The rest of Valgrind is licensed under the
terms of the GNU General Public License, version 2, unless
otherwise indicated. See the COPYING file in the source
distribution for details.
----------------------------------------------------------------
This file is part of callgrind, a valgrind tool for cache simulation
and call tree tracing.
Copyright (C) 2003-2010 Josef Weidendorfer. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
3. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
4. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------
Notice that the above BSD-style license applies to this one file
(callgrind.h) only. The entire rest of Valgrind is licensed under
the terms of the GNU General Public License, version 2. See the
COPYING file in the source distribution for details.
----------------------------------------------------------------
*/
#ifndef __CALLGRIND_H
#define __CALLGRIND_H
#include "valgrind.h"
/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
This enum comprises an ABI exported by Valgrind to programs
which use client requests. DO NOT CHANGE THE ORDER OF THESE
ENTRIES, NOR DELETE ANY -- add new ones at the end.
The identification ('C','T') for Callgrind has historical
reasons: it was called "Calltree" before. Besides, ('C','G') would
clash with cachegrind.
*/
typedef
enum {
VG_USERREQ__DUMP_STATS = VG_USERREQ_TOOL_BASE('C','T'),
VG_USERREQ__ZERO_STATS,
VG_USERREQ__TOGGLE_COLLECT,
VG_USERREQ__DUMP_STATS_AT,
VG_USERREQ__START_INSTRUMENTATION,
VG_USERREQ__STOP_INSTRUMENTATION
} Vg_CallgrindClientRequest;
/* Dump current state of cost centers, and zero them afterwards */
#define CALLGRIND_DUMP_STATS \
{unsigned int _qzz_res; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DUMP_STATS, \
0, 0, 0, 0, 0); \
}
/* Dump current state of cost centers, and zero them afterwards.
The argument is appended to a string stating the reason which triggered
the dump. This string is written as a description field into the
profile data dump. */
#define CALLGRIND_DUMP_STATS_AT(pos_str) \
{unsigned int _qzz_res; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DUMP_STATS_AT, \
pos_str, 0, 0, 0, 0); \
}
/* Zero cost centers */
#define CALLGRIND_ZERO_STATS \
{unsigned int _qzz_res; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__ZERO_STATS, \
0, 0, 0, 0, 0); \
}
/* Toggles collection state.
The collection state specifies whether the happening of events
should be noted or if they are to be ignored. Events are noted
by increment of counters in a cost center */
#define CALLGRIND_TOGGLE_COLLECT \
{unsigned int _qzz_res; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__TOGGLE_COLLECT, \
0, 0, 0, 0, 0); \
}
/* Start full callgrind instrumentation if not already switched on.
When cache simulation is done, it will flush the simulated cache;
this will lead to an artifical cache warmup phase afterwards with
cache misses which would not have happened in reality. */
#define CALLGRIND_START_INSTRUMENTATION \
{unsigned int _qzz_res; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__START_INSTRUMENTATION, \
0, 0, 0, 0, 0); \
}
/* Stop full callgrind instrumentation if not already switched off.
This flushes Valgrinds translation cache, and does no additional
instrumentation afterwards, which effectivly will run at the same
speed as the "none" tool (ie. at minimal slowdown).
Use this to bypass Callgrind aggregation for uninteresting code parts.
To start Callgrind in this mode to ignore the setup phase, use
the option "--instr-atstart=no". */
#define CALLGRIND_STOP_INSTRUMENTATION \
{unsigned int _qzz_res; \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__STOP_INSTRUMENTATION, \
0, 0, 0, 0, 0); \
}
#endif /* __CALLGRIND_H */

View File

@ -0,0 +1,14 @@
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

@ -1,53 +0,0 @@
:- use_module(library(clpbn)).
:- set_clpbn_flag(solver, bp).
%
% A E
% / \ /
% / \ /
% B C
% \ /
% \ /
% D
%
a(A) :-
a_table(ADist),
{ A = a with p([a1, a2], ADist) }.
b(B) :-
a(A),
b_table(BDist),
{ B = b with p([b1, b2], BDist, [A]) }.
c(C) :-
a(A),
c_table(CDist),
{ C = c with p([c1, c2], CDist, [A]) }.
d(D) :-
b(B),
c(C),
d_table(DDist),
{ D = d with p([d1, d2], DDist, [B, C]) }.
e(E) :-
e_table(EDist),
{ E = e with p([e1, e2], EDist) }.
a_table([0.005, 0.995]).
b_table([0.02, 0.97,
0.88, 0.03]).
c_table([0.55, 0.94,
0.45, 0.06]).
d_table([0.192, 0.98, 0.33, 0.013,
0.908, 0.02, 0.77, 0.987]).
e_table([0.055, 0.945]).

View File

@ -0,0 +1,60 @@
#!/bin/bash
cp ~/bin/yap ~/bin/town_comp
YAP=~/bin/town_comp
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=bp_compress.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
function run_solver
{
if [ $2 = bp ]
then
extra_flag1=clpbn_bp:set_solver_parameter\(run_mode,$4\)
extra_flag2=clpbn_bp:set_solver_parameter\(schedule,$5\)
extra_flag3=clpbn_bp:set_solver_parameter\(always_loopy_solver,$6\)
else
extra_flag1=true
extra_flag2=true
extra_flag3=true
fi
/usr/bin/time -o $OUT_FILE_NAME -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF >> $OUT_FILE_NAME 2>> ignore.$OUT_FILE_NAME
[$1].
clpbn:set_clpbn_flag(solver,$2),
clpbn_bp:use_log_space,
$extra_flag1, $extra_flag2, $extra_flag3,
run_query(_R),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~15+ ',[]),
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 town_1000 $1 town_1000 $3 $4 $5
run_solver town_5000 $1 town_5000 $3 $4 $5
run_solver town_10000 $1 town_10000 $3 $4 $5
run_solver town_50000 $1 town_50000 $3 $4 $5
run_solver town_100000 $1 town_100000 $3 $4 $5
run_solver town_500000 $1 town_500000 $3 $4 $5
run_solver town_1000000 $1 town_1000000 $3 $4 $5
run_solver town_2500000 $1 town_2500000 $3 $4 $5
run_solver town_5000000 $1 town_5000000 $3 $4 $5
run_solver town_7500000 $1 town_7500000 $3 $4 $5
run_solver town_10000000 $1 town_10000000 $3 $4 $5
}
run_solver town_10000 "bp(compress,seq_fixed)" town_10000 compress seq_fixed true
exit
##########
run_all_graphs bp "bp(compress,seq_fixed) " compress seq_fixed true

View File

@ -0,0 +1,51 @@
#!/bin/bash
YAP=~/bin/town_conv
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=bp_convert.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
function run_solver
{
if [ $2 = bp ]
then
extra_flag1=clpbn_bp:set_solver_parameter\(run_mode,$4\)
extra_flag2=clpbn_bp:set_solver_parameter\(schedule,$5\)
extra_flag3=clpbn_bp:set_solver_parameter\(always_loopy_solver,$6\)
else
extra_flag1=true
extra_flag2=true
extra_flag3=true
fi
/usr/bin/time -o $OUT_FILE_NAME -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF >> $OUT_FILE_NAME 2>> ignore.$OUT_FILE_NAME
[$1].
clpbn:set_clpbn_flag(solver,$2),
clpbn_bp:use_log_space,
$extra_flag1, $extra_flag2, $extra_flag3,
run_query(_R),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~15+ ',[]),
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 town_1000 $1 town_1000 $3 $4 $5
run_solver town_5000 $1 town_5000 $3 $4 $5
run_solver town_10000 $1 town_10000 $3 $4 $5
run_solver town_50000 $1 town_50000 $3 $4 $5
run_solver town_100000 $1 town_100000 $3 $4 $5
run_solver town_500000 $1 town_500000 $3 $4 $5
run_solver town_1000000 $1 town_1000000 $3 $4 $5
}
run_all_graphs bp "bp(convert,seq_fixed) " convert seq_fixed false

View File

@ -0,0 +1,50 @@
#!/bin/bash
YAP=~/bin/town_norm
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=bp_normal.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
function run_solver
{
if [ $2 = bp ]
then
extra_flag1=clpbn_bp:set_solver_parameter\(run_mode,$4\)
extra_flag2=clpbn_bp:set_solver_parameter\(schedule,$5\)
extra_flag3=clpbn_bp:set_solver_parameter\(always_loopy_solver,$6\)
else
extra_flag1=true
extra_flag2=true
extra_flag3=true
fi
/usr/bin/time -o $OUT_FILE_NAME -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF >> $OUT_FILE_NAME 2>> ignore.$OUT_FILE_NAME
[$1].
clpbn:set_clpbn_flag(solver,$2),
clpbn_bp:use_log_space,
$extra_flag1, $extra_flag2, $extra_flag3,
run_query(_R),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~15+ ',[]),
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 town_1000 $1 town_1000 $3 $4 $5
run_solver town_5000 $1 town_5000 $3 $4 $5
run_solver town_10000 $1 town_10000 $3 $4 $5
run_solver town_50000 $1 town_50000 $3 $4 $5
run_solver town_100000 $1 town_100000 $3 $4 $5
run_solver town_500000 $1 town_500000 $3 $4 $5
run_solver town_1000000 $1 town_1000000 $3 $4 $5
}
run_all_graphs bp "bp(normal,seq_fixed) " normal seq_fixed false

View File

@ -0,0 +1,51 @@
#!/bin/bash
YAP=~/bin/town_gibbs
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=gibbs.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
function run_solver
{
if [ $2 = bp ]
then
extra_flag1=clpbn_bp:set_solver_parameter\(run_mode,$4\)
extra_flag2=clpbn_bp:set_solver_parameter\(schedule,$5\)
extra_flag3=clpbn_bp:set_solver_parameter\(always_loopy_solver,$6\)
else
extra_flag1=true
extra_flag2=true
extra_flag3=true
fi
/usr/bin/time -o $OUT_FILE_NAME -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF >> $OUT_FILE_NAME 2>> ignore.$OUT_FILE_NAME
[$1].
clpbn:set_clpbn_flag(solver,$2),
clpbn_bp:use_log_space,
$extra_flag1, $extra_flag2, $extra_flag3,
run_query(_R),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~15+ ',[]),
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 town_1000 $1 town_1000 $3 $4 $5
run_solver town_5000 $1 town_5000 $3 $4 $5
run_solver town_10000 $1 town_10000 $3 $4 $5
run_solver town_50000 $1 town_50000 $3 $4 $5
run_solver town_100000 $1 town_100000 $3 $4 $5
run_solver town_500000 $1 town_500000 $3 $4 $5
run_solver town_1000000 $1 town_1000000 $3 $4 $5
}
run_all_graphs gibbs "gibbs "

View File

@ -0,0 +1,51 @@
#!/bin/bash
YAP=~/bin/town_jt
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=jt.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
function run_solver
{
if [ $2 = bp ]
then
extra_flag1=clpbn_bp:set_solver_parameter\(run_mode,$4\)
extra_flag2=clpbn_bp:set_solver_parameter\(schedule,$5\)
extra_flag3=clpbn_bp:set_solver_parameter\(always_loopy_solver,$6\)
else
extra_flag1=true
extra_flag2=true
extra_flag3=true
fi
/usr/bin/time -o $OUT_FILE_NAME -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF >> $OUT_FILE_NAME 2>> ignore.$OUT_FILE_NAME
[$1].
clpbn:set_clpbn_flag(solver,$2),
clpbn_bp:use_log_space,
$extra_flag1, $extra_flag2, $extra_flag3,
run_query(_R),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~15+ ',[]),
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 town_1000 $1 town_1000 $3 $4 $5
run_solver town_5000 $1 town_5000 $3 $4 $5
run_solver town_10000 $1 town_10000 $3 $4 $5
run_solver town_50000 $1 town_50000 $3 $4 $5
run_solver town_100000 $1 town_100000 $3 $4 $5
run_solver town_500000 $1 town_500000 $3 $4 $5
run_solver town_1000000 $1 town_1000000 $3 $4 $5
}
run_all_graphs jt "jt "

View File

@ -0,0 +1,51 @@
#!/bin/bash
YAP=~/bin/town_ve
#OUT_FILE_NAME=results`date "+ %H:%M:%S %d-%m-%Y"`.log
OUT_FILE_NAME=ve.log
rm -f $OUT_FILE_NAME
rm -f ignore.$OUT_FILE_NAME
function run_solver
{
if [ $2 = bp ]
then
extra_flag1=clpbn_bp:set_solver_parameter\(run_mode,$4\)
extra_flag2=clpbn_bp:set_solver_parameter\(schedule,$5\)
extra_flag3=clpbn_bp:set_solver_parameter\(always_loopy_solver,$6\)
else
extra_flag1=true
extra_flag2=true
extra_flag3=true
fi
/usr/bin/time -o $OUT_FILE_NAME -a -f "real:%E\tuser:%U\tsys:%S" $YAP << EOF >> $OUT_FILE_NAME 2>> ignore.$OUT_FILE_NAME
[$1].
clpbn:set_clpbn_flag(solver,$2),
clpbn_bp:use_log_space,
$extra_flag1, $extra_flag2, $extra_flag3,
run_query(_R),
open("$OUT_FILE_NAME", 'append',S),
format(S, '$3: ~15+ ',[]),
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 town_1000 $1 town_1000 $3 $4 $5
run_solver town_5000 $1 town_5000 $3 $4 $5
run_solver town_10000 $1 town_10000 $3 $4 $5
run_solver town_50000 $1 town_50000 $3 $4 $5
run_solver town_100000 $1 town_100000 $3 $4 $5
run_solver town_500000 $1 town_500000 $3 $4 $5
run_solver town_1000000 $1 town_1000000 $3 $4 $5
}
run_all_graphs ve "ve "

View File

@ -0,0 +1,65 @@
conservative_city(City, Cons) :-
cons_table(City, ConsDist),
{ Cons = conservative_city(City) with p([y,n], ConsDist) }.
gender(X, Gender) :-
gender_table(X, GenderDist),
{ Gender = gender(X) with p([m,f], GenderDist) }.
hair_color(X, Color) :-
lives(X, City),
conservative_city(City, Cons),
hair_color_table(X,ColorTable),
{ Color = hair_color(X) with
p([t,f], ColorTable,[Cons]) }.
car_color(X, Color) :-
hair_color(X, HColor),
car_color_table(X,CColorTable),
{ Color = car_color(X) with
p([t,f], CColorTable,[HColor]) }.
height(X, Height) :-
gender(X, Gender),
height_table(X,HeightTable),
{ Height = height(X) with
p([t,f], HeightTable,[Gender]) }.
shoe_size(X, Shoesize) :-
height(X, Height),
shoe_size_table(X,ShoesizeTable),
{ Shoesize = shoe_size(X) with
p([t,f], ShoesizeTable,[Height]) }.
guilty(X, Guilt) :-
guilty_table(X, GuiltDist),
{ Guilt = guilty(X) with p([y,n], GuiltDist) }.
descn(X, Descn) :-
car_color(X, Car),
hair_color(X, Hair),
height(X, Height),
guilty(X, Guilt),
descn_table(X, DescTable),
{ Descn = descn(X) with
p([t,f], DescTable,[Car,Hair,Height,Guilt]) }.
witness(City, Witness) :-
descn(joe, DescnJ),
descn(p2, Descn2),
wit_table(WitTable),
{ Witness = witness(City) with
p([t,f], WitTable,[DescnJ, Descn2]) }.
:- ensure_loaded(tables).

View File

@ -0,0 +1,46 @@
cons_table(amsterdam, [0.2, 0.8]) :- !.
cons_table(_, [0.8, 0.2]).
gender_table(_, [0.55, 0.44]).
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.33, 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.61, 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]).

View File

@ -0,0 +1,59 @@
#!/home/tgomes/bin/yap -L --
/*
Steps:
1. generate N facts lives(I, nyc), 0 <= I < N.
2. generate evidence on descn for N people, *** except for 1 ***
3. Run query ?- guilty(joe, Guilty), witness(joe, t), descn(2,t), descn(3, f), descn(4, f) ...
*/
:- initialization(main).
main :-
unix(argv([H])),
generate_town(H).
generate_town(N) :-
atomic_concat(['town_', N, '.yap'], FileName),
open(FileName, 'write', S),
write(S, ':- source.\n'),
write(S, ':- style_check(all).\n'),
write(S, ':- yap_flag(unknown,error).\n'),
write(S, ':- yap_flag(write_strings,on).\n'),
write(S, ':- use_module(library(clpbn)).\n'),
write(S, ':- set_clpbn_flag(solver, bp).\n'),
write(S, ':- [-schema].\n\n'),
write(S, 'lives(_joe, nyc).\n'),
atom_number(N, N2),
generate_people(S, N2, 2),
write(S, '\nrun_query(Guilty) :- \n'),
write(S, '\tguilty(joe, Guilty),\n'),
write(S, '\twitness(nyc, t),\n'),
write(S, '\trunall(X, ev(X)).\n\n\n'),
write(S, 'runall(G, Wrapper) :-\n'),
write(S, '\tfindall(G, Wrapper, L),\n'),
write(S, '\texecute_all(L).\n\n\n'),
write(S, 'execute_all([]).\n'),
write(S, 'execute_all(G.L) :-\n'),
write(S, '\tcall(G),\n'),
write(S, '\texecute_all(L).\n\n\n'),
generate_query(S, N2, 2),
close(S).
generate_people(_, N, Counting1) :- !.
generate_people(S, N, Counting) :-
format(S, 'lives(p~w, nyc).~n', [Counting]),
Counting1 is Counting + 1,
generate_people(S, N, Counting1).
generate_query(S, N, Counting) :-
Counting > N, !.
generate_query(S, N, Counting) :- !,
format(S, 'ev(descn(p~w, t)).~n', [Counting]),
Counting1 is Counting + 1,
generate_query(S, N, Counting1).

File diff suppressed because it is too large Load Diff