Files
mlpack/fastlib/trunk/contrib/tqlong/GraphicalModel/naive_inference.h
T

209 lines
7.0 KiB
C++

#ifndef NAIVE_INFERENCE_H
#define NAIVE_INFERENCE_H
#include "gm.h"
BEGIN_GRAPHICAL_MODEL_NAMESPACE;
/** Naive inference implementation, use for testing correctness of other inference algorithms.
* It calculates the belief of each variable node in the graph by summing up all possible
* products of factors in the graph.
* It may be slow but it is the exact inference algorithm.
*/
template <typename _F>
class NaiveInference
{
public:
typedef _F factor_type;
typedef FactorGraph<_F> graph_type;
typedef typename _F::const_iterator assignment_const_iterator;
typedef typename _F::factor_value_type factor_value_type;
typedef typename FactorGraph<_F>::vertex_type vertex_type;
typedef typename FactorGraph<_F>::vertex_vector_type vertex_vector_type;
typedef Map<Value, factor_value_type, ValueCompare> belief_type;
typedef Map<vertex_type, belief_type> belief_map_type;
public:
/** Constructor, preparing to make inference on a factor graph */
NaiveInference(const graph_type& graph);
/** The inference algorithm */
void run();
/** Return the result as a belief map (from variables to their beliefs) */
const belief_map_type& beliefs() const { return beliefs_; }
const graph_type& graph() const { return graph_; }
/** Return belief of certain variable */
const belief_type& belief(const vertex_type& v) const;
protected:
const graph_type& graph_;
/** To mark visited vertex and cluster index (connected component) of each factor */
Map<vertex_type, bool> visited_;
Map<int, vertex_vector_type> factorClusters_;
/** The result */
belief_map_type beliefs_;
/** The main calculation, summing up all possible products of factor */
void visitFactors(const vertex_vector_type& factors, unsigned int index, factor_value_type currentVal, const Assignment& currentAsgn);
/** Prepare the order of calculation by depth first search the graph */
void DFSvisit(const vertex_type& u, int cluster);
void DFSorder();
/** Initialize and normalize the beliefs */
void initBeliefs();
void normalizeBeliefs();
};
template <typename _F> NaiveInference<_F>::NaiveInference(const graph_type& graph)
: graph_(graph)
{
}
template <typename _F> void NaiveInference<_F>::run()
{
cout << "----------------------- Naive Inference ---------------------------------" << endl;
// preparing the order of calculation
DFSorder();
initBeliefs();
// visit the factors according to theirs connected components
typedef Map<int, vertex_vector_type> map_t;
BOOST_FOREACH(const typename map_t::value_type& p, factorClusters_)
{
const vertex_vector_type& factors = p.second;
visitFactors(factors, 0, factor_value_type(1.0), Assignment());
}
// normalize the results
normalizeBeliefs();
}
// Find the connected components of all factors by DFS
template <typename _F> void NaiveInference<_F>::DFSorder()
{
const vertex_vector_type& vertices = graph_.vertices();
BOOST_FOREACH (const vertex_type& u, vertices)
visited_[u] = false;
factorClusters_.clear();
int cluster = 0;
BOOST_FOREACH (const vertex_type& u, vertices)
if (!visited_[u])
{
DFSvisit(u, cluster);
cluster++;
}
}
template <typename _F> void NaiveInference<_F>::DFSvisit(const vertex_type& u, int cluster)
{
if (u->isFactor()) factorClusters_[cluster] << u;
visited_[u] = true;
const vertex_vector_type& nb = graph_.neighbors(u);
BOOST_FOREACH (const vertex_type& v, nb)
if (!visited_[v]) DFSvisit(v, cluster);
}
template <typename _F> void NaiveInference<_F>::visitFactors(const vertex_vector_type& factors, unsigned int index,
factor_value_type currentVal, const Assignment& currentAsgn)
{
if (index == factors.size()) // if we have the product of factors
{
// Update the belief of variables
BOOST_FOREACH(const Assignment::value_type& p, currentAsgn)
{
const Variable* var = p.first;
const Value& val = p.second;
const vertex_type& u = graph_.dataVertexMap().get((void*) var);
beliefs_[u][val] += currentVal; // add it to the belief of each variable in the assignment
}
// Update the mean value of factors
BOOST_FOREACH(const vertex_type& u, factors)
{
const factor_value_type& f_val = graph_.factor(u).get(currentAsgn); // u.factor
// currentVal is the product of all factors
beliefs_[u][0] += f_val*currentVal;
beliefs_[u][1] += currentVal;
}
return;
}
const factor_type& f = graph_.factor(factors[index]);
BOOST_FOREACH (const typename factor_type::value_type& p, f) // iterate through all assignment that agrees with the current assignment
{
const Assignment& a = p.first;
const factor_value_type& val = p.second;
if (!currentAsgn.agree(a)) continue; // only proceed if current assignmet agrees with new assignment
Assignment newAsgn(currentAsgn);
newAsgn.insert(a.begin(), a.end());
visitFactors(factors, index+1, currentVal*val, newAsgn);
}
}
// set the belief of all variables to zeros
template <typename _F> void NaiveInference<_F>::initBeliefs()
{
const vertex_vector_type& vertices = graph_.vertices();
BOOST_FOREACH (const vertex_type& u, vertices)
{
if (u->isVariable())
{
const Variable* var = (const Variable*) u->variable();
for (int val = 0; val < var->cardinality(); val++)
beliefs_[u][val] = factor_value_type(0.0);
}
else // u is a factor
{
beliefs_[u][0] = factor_value_type(0.0); // the sum of u.factor * (product of all factors)
beliefs_[u][1] = factor_value_type(0.0); // the sum of products of all factors
}
}
}
// normalize the beliefs
template <typename _F> void NaiveInference<_F>::normalizeBeliefs()
{
for (typename belief_map_type::iterator it = beliefs_.begin(); it != beliefs_.end(); it++)
{
const vertex_type& u = it->first;
belief_type& blf = (*it).second;
if (u->isVariable())
{
factor_value_type sum = factor_value_type(0.0);
for (typename belief_type::iterator bIt = blf.begin(); bIt != blf.end(); bIt++)
sum += (*bIt).second;
if (sum < factor_value_type(1e-15)) // sum is ZERO
{
for (typename belief_type::iterator bIt = blf.begin(); bIt != blf.end(); bIt++)
(*bIt).second = factor_value_type(1.0) / factor_value_type(blf.size());
}
else
{
for (typename belief_type::iterator bIt = blf.begin(); bIt != blf.end(); bIt++)
(*bIt).second /= sum;
}
}
else // u is a factor, divide blf[0] / blf[1] = sum ( product * factor ) / sum (product)
{
if (blf[1] < factor_value_type(1e-15))
blf[0] = factor_value_type(0.0);
else
blf[0] /= blf[1];
blf[1] = factor_value_type(1.0);
}
}
}
template <typename _F>
const typename NaiveInference<_F>::belief_type& NaiveInference<_F>::belief(const vertex_type& v) const
{
return beliefs_.get(v);
}
END_GRAPHICAL_MODEL_NAMESPACE;
#endif // NAIVE_INFERENCE_H