#include #include #include #include #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 queryVars; queryVars.push_back (queryVar); runSolver (queryVars); } void BpNetwork::runSolver (vector queryVars) { if (queryVars.size() > 1) { addJunctionNode (queryVars); } else { string varName = queryVars[0]->getVariableName(); queryNode_ = static_cast (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 (nodes_[i]); addEvidence (v); vector parents = cast (v->getParents()); for (unsigned int i = 0; i < parents.size(); i++) { if (!parents[i]->hasEvidence()) { sendLambdaMessage (v, parents[i]); } } vector 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 (nodes_[i])); } } runIterativeBpSolver(); } } void BpNetwork::printCurrentStatus (void) { for (unsigned int i = 0; i < nodes_.size(); i++) { printCurrentStatusOf (static_cast (nodes_[i])); } } void BpNetwork::printCurrentStatusOf (BpNode* x) { vector childs = cast (x->getChilds()); vector 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 (nodes_[i]); vector 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 BpNetwork::getBeliefs (void) { return getBeliefs (queryNode_); } vector BpNetwork::getBeliefs (BpNode* x) { double* beliefs = x->getBeliefs(); vector beliefsVec; for (int xi = 0; xi < x->getDomainSize(); xi++) { beliefsVec.push_back (beliefs[xi]); } return beliefsVec; } void BpNetwork::initializeSolver (vector 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 (nodes_[i]); node->allocateMemory(); } for (unsigned int i = 0; i < nodes_.size(); i++) { BpNode* x = static_cast (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 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 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 (nodes_[i]); x->normalizeMessages(); } printCurrentStatus(); vector 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 queryVars) { const string VAR_NAME = "_Jn"; int nStates = 1; vector parents; vector 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 (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 roots = cast (getRootNodes()); for (unsigned int i = 0; i < roots.size(); i++) { vector childs = cast (roots[i]->getChilds()); for (unsigned int j = 0; j < childs.size(); j++) { sendPiMessage (roots[i], static_cast (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 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 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 xParents = cast (x->getParents()); for (unsigned int i = 0; i < xParents.size(); i++) { if (!xParents[i]->hasEvidence()) { sendLambdaMessage (x, xParents[i]); } } vector 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 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 > constraints; vector 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 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 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 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 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 > constraints; constraints.push_back (make_pair (0, yi)); constraints.push_back (make_pair (parentIndex, xi)); vector 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 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(nodes_[i]); vector 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(nodes_[i]); vector 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(nodes_[i]); vector 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 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 (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(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 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 parents, double* params, int nParams, vector domain) { Distribution* dist = new Distribution (params, nParams, domain); BpNode* node = new BpNode (varName, parents, dist); dists_.push_back (dist); nodes_.push_back (node); } vector BpNetwork::cast (vector nodes) { vector castedNodes (nodes.size()); for (unsigned int i = 0; i < nodes.size(); i++) { castedNodes[i] = static_cast (nodes[i]); } return castedNodes; }