47#ifndef DOXYGEN_SHOULD_SKIP_THIS
53constexpr auto LBP_DEFAULT_MAXITER = 100;
54constexpr auto LBP_DEFAULT_EPSILON = 1e-8;
55constexpr auto LBP_DEFAULT_MIN_EPSILON_RATE = 1e-10;
56constexpr auto LBP_DEFAULT_PERIOD_SIZE = 1;
57constexpr auto LBP_DEFAULT_VERBOSITY =
false;
66 template <
typename GUM_SCALAR >
70 GUM_CONSTRUCTOR(LoopyBeliefPropagation)
72 this->setEpsilon(LBP_DEFAULT_EPSILON);
73 this->setMinEpsilonRate(LBP_DEFAULT_MIN_EPSILON_RATE);
74 this->setMaxIter(LBP_DEFAULT_MAXITER);
75 this->setVerbosity(LBP_DEFAULT_VERBOSITY);
76 this->setPeriodSize(LBP_DEFAULT_PERIOD_SIZE);
82 template <
typename GUM_SCALAR >
83 INLINE LoopyBeliefPropagation< GUM_SCALAR >::~LoopyBeliefPropagation() {
84 GUM_DESTRUCTOR(LoopyBeliefPropagation)
87 template <
typename GUM_SCALAR >
88 void LoopyBeliefPropagation< GUM_SCALAR >::_init_messages_() {
90 for (
const auto& tail: this->BN().nodes()) {
91 Tensor< GUM_SCALAR > p;
92 p.add(this->BN().variable(tail));
93 p.fill(
static_cast< GUM_SCALAR
>(1));
95 for (
const auto& head: this->BN().children(tail)) {
96 _messages_.insert(Arc(head, tail), p);
97 _messages_.insert(Arc(tail, head), p);
102 template <
typename GUM_SCALAR >
103 void LoopyBeliefPropagation< GUM_SCALAR >::updateOutdatedStructure_() {
107 template <
typename GUM_SCALAR >
108 Tensor< GUM_SCALAR > LoopyBeliefPropagation< GUM_SCALAR >::_computeProdPi_(NodeId X) {
109 const auto& varX = this->BN().variable(X);
111 auto piX = this->BN().cpt(X);
112 for (
const auto& U: this->BN().parents(X)) {
113 piX *= _messages_[Arc(U, X)];
115 piX = piX.sumIn({&varX});
120 template <
typename GUM_SCALAR >
121 Tensor< GUM_SCALAR > LoopyBeliefPropagation< GUM_SCALAR >::_computeProdPi_(NodeId X,
123 const auto& varX = this->BN().variable(X);
124 const auto& varExcept = this->BN().variable(except);
125 auto piXexcept = this->BN().cpt(X);
126 for (
const auto& U: this->BN().parents(X)) {
127 if (U != except) { piXexcept *= _messages_[Arc(U, X)]; }
129 piXexcept = piXexcept.sumIn({&varX, &varExcept});
133 template <
typename GUM_SCALAR >
134 Tensor< GUM_SCALAR > LoopyBeliefPropagation< GUM_SCALAR >::_computeProdLambda_(NodeId X) {
135 Tensor< GUM_SCALAR > lamX;
136 if (this->hasEvidence(X)) {
137 lamX = *(this->evidence()[X]);
139 lamX.add(this->BN().variable(X));
142 for (
const auto& Y: this->BN().children(X)) {
143 lamX *= _messages_[Arc(Y, X)];
149 template <
typename GUM_SCALAR >
150 Tensor< GUM_SCALAR > LoopyBeliefPropagation< GUM_SCALAR >::_computeProdLambda_(NodeId X,
152 Tensor< GUM_SCALAR > lamXexcept;
153 if (this->hasEvidence(X)) {
154 lamXexcept = *this->evidence()[X];
156 lamXexcept.add(this->BN().variable(X));
159 for (
const auto& Y: this->BN().children(X)) {
160 if (Y != except) { lamXexcept *= _messages_[Arc(Y, X)]; }
166 template <
typename GUM_SCALAR >
167 GUM_SCALAR LoopyBeliefPropagation< GUM_SCALAR >::_updateNodeMessage_(NodeId X) {
168 auto piX = _computeProdPi_(X);
169 auto lamX = _computeProdLambda_(X);
175 for (
const auto& U: this->BN().parents(X)) {
176 auto newLambda = (_computeProdPi_(X, U) * lamX).sumIn({&this->BN().variable(U)});
177 newLambda.normalize();
178 auto ekl =
static_cast< GUM_SCALAR
>(0);
180 ekl = _messages_[Arc(X, U)].KL(newLambda);
184 ekl = std::numeric_limits< GUM_SCALAR >::infinity();
190 _messages_.set(Arc(X, U), newLambda);
194 for (
const auto& Y: this->BN().children(X)) {
195 auto newPi = (piX * _computeProdLambda_(X, Y));
199 ekl = _messages_[Arc(X, Y)].KL(newPi);
203 ekl = std::numeric_limits< GUM_SCALAR >::infinity();
209 _messages_.set(Arc(X, Y), newPi);
215 template <
typename GUM_SCALAR >
216 INLINE
void LoopyBeliefPropagation< GUM_SCALAR >::_initStats_() {
218 for (
const auto& node: this->BN().topologicalOrder()) {
219 _updateNodeMessage_(node);
224 template <
typename GUM_SCALAR >
225 void LoopyBeliefPropagation< GUM_SCALAR >::makeInference_() {
227 this->initApproximationScheme();
229 std::vector< NodeId > shuffleIds;
230 for (
const auto& node: this->BN().nodes())
231 shuffleIds.push_back(node);
233 auto engine = std::default_random_engine{};
235 GUM_SCALAR error = 0.0;
237 std::shuffle(std::begin(shuffleIds), std::end(shuffleIds), engine);
238 this->updateApproximationScheme();
239 for (
const auto& node: shuffleIds) {
240 GUM_SCALAR e = _updateNodeMessage_(node);
241 if (e > error) error = e;
243 }
while (this->continueApproximationScheme(error));
247 template <
typename GUM_SCALAR >
248 INLINE
const Tensor< GUM_SCALAR >& LoopyBeliefPropagation< GUM_SCALAR >::posterior_(NodeId
id) {
249 auto p = _computeProdPi_(
id) * _computeProdLambda_(
id);
251 _posteriors_.set(
id, p);
253 return _posteriors_[id];
KL is the base class for KL computation betweens 2 BNs.
Exception : fatal (unknown ?) error.
Class representing the minimal interface for Bayesian network with no numerical data.
Exception: at least one argument passed to a function is not what was expected.
LoopyBeliefPropagation(const IBayesNet< GUM_SCALAR > *bn)
Default constructor.
#define GUM_ERROR(type, msg)
This file contains gibbs sampling (for BNs) class definitions.
gum is the global namespace for all aGrUM entities