[Frederik Eaton] Major cleanup of BBP and CBP code and documentation
[libdai.git] / src / bbp.cpp
1 /* Copyright (C) 2009 Frederik Eaton [frederik at ofb dot net]
2
3 This file is part of libDAI.
4
5 libDAI is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 libDAI is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libDAI; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20
21 #include <dai/bp.h>
22 #include <dai/bbp.h>
23 #include <dai/gibbs.h>
24 #include <dai/util.h>
25 #include <dai/bipgraph.h>
26
27 // for makeBBPPlot: {
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <iostream>
31 #include <fstream>
32 // }
33
34
35 namespace dai {
36
37
38 using namespace std;
39
40
41 typedef BipartiteGraph::Neighbor Neighbor;
42
43
44 Prob unnormAdjoint(const Prob &w, Real Z_w, const Prob &adj_w) {
45 assert(w.size()==adj_w.size());
46 Prob adj_w_unnorm(w.size(),0.0);
47 Real s=0.0;
48 for(size_t i=0; i<w.size(); i++) {
49 s += w[i]*adj_w[i];
50 }
51 for(size_t i=0; i<w.size(); i++) {
52 adj_w_unnorm[i] = (adj_w[i]-s)/Z_w;
53 }
54 return adj_w_unnorm;
55 }
56
57
58 size_t getFactorEntryForState(const FactorGraph &fg, size_t I, const vector<size_t>& state) {
59 size_t f_entry = 0;
60 for( int _j = fg.nbF(I).size() - 1; _j >= 0; _j-- ) {
61 // note that iterating over nbF(I) yields the same ordering
62 // of variables as iterating over factor(I).vars()
63 size_t j = fg.nbF(I)[_j];
64 f_entry *= fg.var(j).states();
65 f_entry += state[j];
66 }
67 return f_entry;
68 }
69
70
71 void initBBPCostFnAdj(BBP& bbp, const InfAlg &ia, bbp_cfn_t cfn_type, const vector<size_t>* stateP) {
72 const FactorGraph &fg = ia.fg();
73
74 switch((size_t)cfn_type) {
75 case bbp_cfn_t::cfn_bethe_ent: {
76 vector<Prob> b1_adj;
77 vector<Prob> b2_adj;
78 vector<Prob> psi1_adj;
79 vector<Prob> psi2_adj;
80 b1_adj.reserve(fg.nrVars());
81 psi1_adj.reserve(fg.nrVars());
82 b2_adj.reserve(fg.nrFactors());
83 psi2_adj.reserve(fg.nrFactors());
84 for(size_t i=0; i<fg.nrVars(); i++) {
85 size_t dim = fg.var(i).states();
86 int c = fg.nbV(i).size();
87 Prob p(dim,0.0);
88 for(size_t xi=0; xi<dim; xi++) {
89 p[xi] = (1-c)*(1+log(ia.beliefV(i)[xi]));
90 }
91 b1_adj.push_back(p);
92
93 for(size_t xi=0; xi<dim; xi++) {
94 p[xi] = -ia.beliefV(i)[xi];
95 }
96 psi1_adj.push_back(p);
97 }
98 for(size_t I=0; I<fg.nrFactors(); I++) {
99 size_t dim = fg.factor(I).states();
100 Prob p(dim,0.0);
101 for(size_t xI=0; xI<dim; xI++) {
102 p[xI] = 1 + log(ia.beliefF(I)[xI]/fg.factor(I).p()[xI]);
103 }
104 b2_adj.push_back(p);
105
106 for(size_t xI=0; xI<dim; xI++) {
107 p[xI] = -ia.beliefF(I)[xI]/fg.factor(I).p()[xI];
108 }
109 psi2_adj.push_back(p);
110 }
111 bbp.init(b1_adj, b2_adj, psi1_adj, psi2_adj);
112 break;
113 }
114 case bbp_cfn_t::cfn_factor_ent: {
115 vector<Prob> b2_adj;
116 b2_adj.reserve(fg.nrFactors());
117 for(size_t I=0; I<fg.nrFactors(); I++) {
118 size_t dim = fg.factor(I).states();
119 Prob p(dim,0.0);
120 for(size_t xI=0; xI<dim; xI++) {
121 double bIxI = ia.beliefF(I)[xI];
122 if(bIxI<1.0e-15) {
123 p[xI] = -1.0e10;
124 } else {
125 p[xI] = 1+log(bIxI);
126 }
127 }
128 b2_adj.push_back(p);
129 }
130 bbp.init(get_zero_adj_V(fg), b2_adj);
131 break;
132 }
133 case bbp_cfn_t::cfn_var_ent: {
134 vector<Prob> b1_adj;
135 b1_adj.reserve(fg.nrVars());
136 for(size_t i=0; i<fg.nrVars(); i++) {
137 size_t dim = fg.var(i).states();
138 Prob p(dim,0.0);
139 for(size_t xi=0; xi<fg.var(i).states(); xi++) {
140 double bixi = ia.beliefV(i)[xi];
141 if(bixi<1.0e-15) {
142 p[xi] = -1.0e10;
143 } else {
144 p[xi] = 1+log(bixi);
145 }
146 }
147 b1_adj.push_back(p);
148 }
149 bbp.init(b1_adj);
150 break;
151 }
152 case bbp_cfn_t::cfn_gibbs_b:
153 case bbp_cfn_t::cfn_gibbs_b2:
154 case bbp_cfn_t::cfn_gibbs_exp: {
155 // cost functions that use Gibbs sample, summing over variable
156 // marginals
157 vector<size_t> state;
158 if(stateP==NULL) {
159 state = getGibbsState(ia,2*ia.Iterations());
160 } else {
161 state = *stateP;
162 }
163 assert(state.size()==fg.nrVars());
164
165 vector<Prob> b1_adj;
166 b1_adj.reserve(fg.nrVars());
167 for(size_t i=0; i<state.size(); i++) {
168 size_t n = fg.var(i).states();
169 Prob delta(n,0.0);
170 assert(/*0<=state[i] &&*/ state[i] < n);
171 double b = ia.beliefV(i)[state[i]];
172 switch((size_t)cfn_type) {
173 case bbp_cfn_t::cfn_gibbs_b:
174 delta[state[i]] = 1.0; break;
175 case bbp_cfn_t::cfn_gibbs_b2:
176 delta[state[i]] = b; break;
177 case bbp_cfn_t::cfn_gibbs_exp:
178 delta[state[i]] = exp(b); break;
179 default: abort();
180 }
181 b1_adj.push_back(delta);
182 }
183 bbp.init(b1_adj);
184 break;
185 }
186 case bbp_cfn_t::cfn_gibbs_b_factor:
187 case bbp_cfn_t::cfn_gibbs_b2_factor:
188 case bbp_cfn_t::cfn_gibbs_exp_factor: {
189 // cost functions that use Gibbs sample, summing over factor
190 // marginals
191 vector<size_t> state;
192 if(stateP==NULL) {
193 state = getGibbsState(ia,2*ia.Iterations());
194 } else {
195 state = *stateP;
196 }
197 assert(state.size()==fg.nrVars());
198
199 vector<Prob> b2_adj;
200 b2_adj.reserve(fg.nrVars());
201 for(size_t I=0; I<fg.nrFactors(); I++) {
202 size_t n = fg.factor(I).states();
203 Prob delta(n,0.0);
204
205 size_t x_I = getFactorEntryForState(fg, I, state);
206 assert(/*0<=x_I &&*/ x_I < n);
207
208 double b = ia.beliefF(I)[x_I];
209 switch((size_t)cfn_type) {
210 case bbp_cfn_t::cfn_gibbs_b_factor:
211 delta[x_I] = 1.0; break;
212 case bbp_cfn_t::cfn_gibbs_b2_factor:
213 delta[x_I] = b; break;
214 case bbp_cfn_t::cfn_gibbs_exp_factor:
215 delta[x_I] = exp(b); break;
216 default: abort();
217 }
218 b2_adj.push_back(delta);
219 }
220 bbp.init(get_zero_adj_V(fg), b2_adj);
221 break;
222 }
223 default: abort();
224 }
225 }
226
227
228 Real getCostFn(const InfAlg &ia, bbp_cfn_t cfn_type, const vector<size_t> *stateP) {
229 double cf=0.0;
230 const FactorGraph &fg = ia.fg();
231
232 switch((size_t)cfn_type) {
233 case bbp_cfn_t::cfn_bethe_ent: // ignores state
234 cf = -ia.logZ();
235 break;
236 case bbp_cfn_t::cfn_var_ent: // ignores state
237 for(size_t i=0; i<fg.nrVars(); i++) {
238 cf += -ia.beliefV(i).entropy();
239 }
240 break;
241 case bbp_cfn_t::cfn_factor_ent: // ignores state
242 for(size_t I=0; I<fg.nrFactors(); I++) {
243 cf += -ia.beliefF(I).entropy();
244 }
245 break;
246 case bbp_cfn_t::cfn_gibbs_b:
247 case bbp_cfn_t::cfn_gibbs_b2:
248 case bbp_cfn_t::cfn_gibbs_exp: {
249 assert(stateP != NULL);
250 vector<size_t> state = *stateP;
251 assert(state.size()==fg.nrVars());
252 for(size_t i=0; i<fg.nrVars(); i++) {
253 double b = ia.beliefV(i)[state[i]];
254 switch((size_t)cfn_type) {
255 case bbp_cfn_t::cfn_gibbs_b: cf += b; break;
256 case bbp_cfn_t::cfn_gibbs_b2: cf += b*b/2; break;
257 case bbp_cfn_t::cfn_gibbs_exp: cf += exp(b); break;
258 default: abort();
259 }
260 }
261 break;
262 }
263 case bbp_cfn_t::cfn_gibbs_b_factor:
264 case bbp_cfn_t::cfn_gibbs_b2_factor:
265 case bbp_cfn_t::cfn_gibbs_exp_factor: {
266 assert(stateP != NULL);
267 vector<size_t> state = *stateP;
268 assert(state.size()==fg.nrVars());
269 for(size_t I=0; I<fg.nrFactors(); I++) {
270 size_t x_I = getFactorEntryForState(fg, I, state);
271 double b = ia.beliefF(I)[x_I];
272 switch((size_t)cfn_type) {
273 case bbp_cfn_t::cfn_gibbs_b_factor: cf += b; break;
274 case bbp_cfn_t::cfn_gibbs_b2_factor: cf += b*b/2; break;
275 case bbp_cfn_t::cfn_gibbs_exp_factor: cf += exp(b); break;
276 default: abort();
277 }
278 }
279 break;
280 }
281 default:
282 cerr << "Unknown cost function " << cfn_type << endl;
283 abort();
284 }
285 return cf;
286 }
287
288
289 vector<Prob> get_zero_adj_F(const FactorGraph& fg) {
290 vector<Prob> adj_2;
291 adj_2.reserve(fg.nrFactors());
292 for(size_t I=0; I<fg.nrFactors(); I++) {
293 adj_2.push_back(Prob(fg.factor(I).states(),Real(0.0)));
294 }
295 return adj_2;
296 }
297
298
299 vector<Prob> get_zero_adj_V(const FactorGraph& fg) {
300 vector<Prob> adj_1;
301 adj_1.reserve(fg.nrVars());
302 for(size_t i=0; i<fg.nrVars(); i++) {
303 adj_1.push_back(Prob(fg.var(i).states(),Real(0.0)));
304 }
305 return adj_1;
306 }
307
308
309 #define LOOP_ij(body) { \
310 size_t i_states = _fg->var(i).states(); \
311 size_t j_states = _fg->var(j).states(); \
312 if(_fg->var(i) > _fg->var(j)) { \
313 size_t xij=0; \
314 for(size_t xi=0; xi<i_states; xi++) { \
315 for(size_t xj=0; xj<j_states; xj++) { \
316 body; \
317 xij++; \
318 } \
319 } \
320 } else { \
321 size_t xij=0; \
322 for(size_t xj=0; xj<j_states; xj++) { \
323 for(size_t xi=0; xi<i_states; xi++) { \
324 body; \
325 xij++; \
326 } \
327 } \
328 } \
329 }
330
331
332 void BBP::RegenerateInds() {
333 // initialise _indices
334 // typedef std::vector<size_t> _ind_t;
335 // std::vector<std::vector<_ind_t> > _indices;
336 _indices.resize(_fg->nrVars());
337 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
338 _indices[i].reserve(_fg->nbV(i).size());
339 foreach(const Neighbor &I, _fg->nbV(i)) {
340 _ind_t index;
341 index.reserve(_fg->factor(I).states());
342 for(IndexFor k( _fg->var(i), _fg->factor(I).vars() ); k >= 0; ++k) {
343 index.push_back(k);
344 }
345 _indices[i].push_back(index);
346 }
347 }
348 }
349
350
351 void BBP::RegenerateT() {
352 // _T[i][_I]
353 _T.clear();
354 _T.resize(_fg->nrVars());
355 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
356 _T[i].resize(_fg->nbV(i).size());
357 foreach(const Neighbor &I, _fg->nbV(i)) {
358 Prob prod(_fg->var(i).states(),1.0);
359 foreach(const Neighbor &J, _fg->nbV(i)) {
360 if(size_t(J)!=size_t(I)) {
361 prod *= _bp_dual.msgM(i,J.iter);
362 }
363 }
364 _T[i][I.iter] = prod;
365 }
366 }
367 }
368
369
370 void BBP::RegenerateU() {
371 // _U[I][_i]
372 _U.clear();
373 _U.resize(_fg->nrFactors());
374 for( size_t I = 0; I < _fg->nrFactors(); I++ ) {
375 _U[I].resize(_fg->nbF(I).size());
376 foreach(const Neighbor &i, _fg->nbF(I)) {
377 Prob prod(_fg->factor(I).states(), 1.0);
378 foreach(const Neighbor &j, _fg->nbF(I)) {
379 if(size_t(i) != size_t(j)) {
380 Prob n_jI(_bp_dual.msgN(j, j.dual));
381 const _ind_t& ind = _index(j, j.dual);
382 // multiply prod by n_jI
383 for(size_t x_I = 0; x_I < prod.size(); x_I++)
384 prod[x_I] *= n_jI[ind[x_I]];
385 }
386 }
387 _U[I][i.iter] = prod;
388 }
389 }
390 }
391
392
393 void BBP::RegenerateS() {
394 // _S[i][_I][_j]
395 _S.clear();
396 _S.resize(_fg->nrVars());
397 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
398 _S[i].resize(_fg->nbV(i).size());
399 foreach(const Neighbor& I, _fg->nbV(i)) {
400 _S[i][I.iter].resize(_fg->nbF(I).size());
401 foreach(const Neighbor& j, _fg->nbF(I)) {
402 if(i != j) {
403 Factor prod(_fg->factor(I));
404 foreach(const Neighbor& k, _fg->nbF(I)) {
405 if(k!=i && size_t(k)!=size_t(j)) {
406 const _ind_t& ind = _index(k,k.dual);
407 Prob p(_bp_dual.msgN(k,k.dual));
408 for( size_t x_I = 0; x_I < prod.states(); x_I++ )
409 prod.p()[x_I] *= p[ind[x_I]];
410 }
411 }
412 // "Marginalize" onto i|j (unnormalized)
413 // XXX improve efficiency?
414 Prob marg;
415 marg = prod.marginal(VarSet(_fg->var(i)) | VarSet(_fg->var(j)), false).p();
416 _S[i][I.iter][j.iter] = marg;
417 }
418 }
419 }
420 }
421 }
422
423
424 void BBP::RegenerateR() {
425 // _R[I][_i][_J]
426 _R.clear();
427 _R.resize(_fg->nrFactors());
428 for( size_t I = 0; I < _fg->nrFactors(); I++ ) {
429 _R[I].resize(_fg->nbF(I).size());
430 foreach(const Neighbor& i, _fg->nbF(I)) {
431 _R[I][i.iter].resize(_fg->nbV(i).size());
432 foreach(const Neighbor& J, _fg->nbV(i)) {
433 if(I != J) {
434 Prob prod(_fg->var(i).states(), 1.0);
435 foreach(const Neighbor& K, _fg->nbV(i)) {
436 if(size_t(K) != size_t(I) &&
437 size_t(K) != size_t(J)) {
438 prod *= _bp_dual.msgM(i,K.iter);
439 }
440 }
441 _R[I][i.iter][J.iter] = prod;
442 }
443 }
444 }
445 }
446 }
447
448
449 void BBP::RegenerateInputs() {
450 _adj_b_V_unnorm.clear();
451 _adj_b_V_unnorm.reserve(_fg->nrVars());
452 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
453 _adj_b_V_unnorm.push_back(
454 unnormAdjoint(_bp_dual.beliefV(i).p(),
455 _bp_dual.beliefVZ(i), _adj_b_V[i]));
456 }
457 _adj_b_F_unnorm.clear();
458 _adj_b_F_unnorm.reserve(_fg->nrFactors());
459 for( size_t I = 0; I < _fg->nrFactors(); I++ ) {
460 _adj_b_F_unnorm.push_back(
461 unnormAdjoint(_bp_dual.beliefF(I).p(),
462 _bp_dual.beliefFZ(I), _adj_b_F[I]));
463 }
464 }
465
466
467 void BBP::RegeneratePsiAdjoints() {
468 _adj_psi_V.clear();
469 _adj_psi_V.reserve(_fg->nrVars());
470 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
471 Prob p(_adj_b_V_unnorm[i]);
472 assert(p.size()==_fg->var(i).states());
473 foreach(const Neighbor& I, _fg->nbV(i)) {
474 p *= _bp_dual.msgM(i,I.iter);
475 }
476 p += _init_adj_psi_V[i];
477 _adj_psi_V.push_back(p);
478 }
479 _adj_psi_F.clear();
480 _adj_psi_F.reserve(_fg->nrFactors());
481 for( size_t I = 0; I < _fg->nrFactors(); I++ ) {
482 Prob p(_adj_b_F_unnorm[I]);
483 assert(p.size()==_fg->factor(I).states());
484 foreach(const Neighbor& i, _fg->nbF(I)) {
485 Prob n_iI(_bp_dual.msgN(i,i.dual));
486 const _ind_t& ind = _index(i,i.dual);
487 // multiply prod with n_jI
488 for(size_t x_I = 0; x_I < p.size(); x_I++)
489 p[x_I] *= n_iI[ind[x_I]];
490 }
491 p += _init_adj_psi_F[I];
492 _adj_psi_F.push_back(p);
493 }
494 }
495
496
497 void BBP::RegenerateParMessageAdjoints() {
498 size_t nv = _fg->nrVars();
499 _adj_n.resize(nv);
500 _adj_m.resize(nv);
501 _adj_n_unnorm.resize(nv);
502 _adj_m_unnorm.resize(nv);
503 _new_adj_n.clear();
504 _new_adj_n.resize(nv);
505 _new_adj_m.clear();
506 _new_adj_m.resize(nv);
507 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
508 size_t n_i = _fg->nbV(i).size();
509 _adj_n[i].resize(n_i);
510 _adj_m[i].resize(n_i);
511 _adj_n_unnorm[i].resize(n_i);
512 _adj_m_unnorm[i].resize(n_i);
513 _new_adj_n[i].resize(n_i);
514 _new_adj_m[i].resize(n_i);
515 foreach(const Neighbor& I, _fg->nbV(i)) {
516 // calculate adj_n
517 {
518 Prob prod(_fg->factor(I).p());
519 prod *= _adj_b_F_unnorm[I];
520 foreach(const Neighbor& j, _fg->nbF(I)) {
521 if(i != j) {
522 Prob n_jI(_bp_dual.msgN(j,j.dual));
523 const _ind_t& ind = _index(j,j.dual);
524 // multiply prod with n_jI
525 for( size_t x_I = 0; x_I < prod.size(); x_I++ )
526 prod[x_I] *= n_jI[ind[x_I]];
527 }
528 }
529 Prob marg(_fg->var(i).states(), 0.0);
530 const _ind_t &ind = _index(i,I.iter);
531 for( size_t r = 0; r < prod.size(); r++ )
532 marg[ind[r]] += prod[r];
533 _new_adj_n[i][I.iter] = marg;
534 upMsgN(i,I.iter);
535 }
536
537 // calculate adj_m
538 {
539 Prob prod(_adj_b_V_unnorm[i]);
540 assert(prod.size()==_fg->var(i).states());
541 foreach(const Neighbor& J, _fg->nbV(i)) {
542 if(size_t(J) != size_t(I)) {
543 prod *= _bp_dual.msgM(i,J.iter);
544 }
545 }
546 _new_adj_m[i][I.iter] = prod;
547 upMsgM(i,I.iter);
548 }
549 }
550 }
551 }
552
553
554 void BBP::incrSeqMsgM(size_t i, size_t _I, const Prob& p) {
555 if(props.clean_updates) {
556 _new_adj_m[i][_I] += p;
557 } else {
558 _adj_m[i][_I] += p;
559 calcUnnormMsgM(i, _I);
560 }
561 }
562
563
564 Real pv_thresh=1000;
565
566
567 void BBP::updateSeqMsgM(size_t i, size_t _I) {
568 if(props.clean_updates) {
569 #if 0
570 if(_new_adj_m[i][_I].sumAbs() > pv_thresh ||
571 _adj_m[i][_I].sumAbs() > pv_thresh) {
572
573 DAI_DMSG("in updateSeqMsgM");
574 DAI_PV(i);
575 DAI_PV(_I);
576 DAI_PV(_adj_m[i][_I]);
577 DAI_PV(_new_adj_m[i][_I]);
578 }
579 #endif
580 _adj_m[i][_I] += _new_adj_m[i][_I];
581 calcUnnormMsgM(i, _I);
582 _new_adj_m[i][_I].fill(0.0);
583 }
584 }
585
586
587 void BBP::setSeqMsgM(size_t i, size_t _I, const Prob& p) {
588 _adj_m[i][_I] = p;
589 calcUnnormMsgM(i, _I);
590 }
591
592
593 void BBP::sendSeqMsgN(size_t i, size_t _I, const Prob &f) {
594 Prob f_unnorm = unnormAdjoint(_bp_dual.msgN(i,_I), _bp_dual.zN(i,_I), f);
595 const Neighbor& I = _fg->nbV(i)[_I];
596 assert(I.iter == _I);
597 _adj_psi_V[i] += f_unnorm * T(i,_I);
598 #if 0
599 if(f_unnorm.sumAbs() > pv_thresh) {
600 DAI_DMSG("in sendSeqMsgN");
601 DAI_PV(i);
602 DAI_PV(I);
603 DAI_PV(_I);
604 DAI_PV(_bp_dual.msgN(i,_I));
605 DAI_PV(_bp_dual.zN(i,_I));
606 DAI_PV(_bp_dual.msgM(i,_I));
607 DAI_PV(_bp_dual.zM(i,_I));
608 DAI_PV(_fg->factor(I).p());
609 }
610 #endif
611 foreach(const Neighbor& J, _fg->nbV(i)) {
612 if(size_t(J) != size_t(I)) {
613 #if 0
614 if(f_unnorm.sumAbs() > pv_thresh) {
615 DAI_DMSG("in sendSeqMsgN loop");
616 DAI_PV(J);
617 DAI_PV(f_unnorm);
618 DAI_PV(_R[J][J.dual][_I]);
619 DAI_PV(f_unnorm * _R[J][J.dual][_I]);
620 }
621 #endif
622 incrSeqMsgM(i, J.iter, f_unnorm * R(J,J.dual,_I));
623 }
624 }
625 }
626
627
628 void BBP::sendSeqMsgM(size_t j, size_t _I) {
629 const Neighbor& I = _fg->nbV(j)[_I];
630 size_t _j = I.dual;
631 const Prob &_adj_m_unnorm_jI = _adj_m_unnorm[j][_I];
632
633 // DAI_PV(j);
634 // DAI_PV(I);
635 // DAI_PV(_adj_m_unnorm_jI);
636 // DAI_PV(_adj_m[j][_I]);
637 // DAI_PV(_bp_dual.zM(j,_I));
638
639 Prob um(U(I,_j));
640 const _ind_t& ind = _index(j, _I);
641 for( size_t x_I = 0; x_I < um.size(); x_I++ )
642 um[x_I] *= _adj_m_unnorm_jI[ind[x_I]];
643 um *= 1-props.damping;
644 _adj_psi_F[I] += um;
645
646 // DAI_DMSG("in sendSeqMsgM");
647 // DAI_PV(j);
648 // DAI_PV(I);
649 // DAI_PV(_I);
650 // DAI_PV(_fg->nbF(I).size());
651 foreach(const Neighbor& i, _fg->nbF(I)) {
652 if(size_t(i) != j) {
653 const Prob &S = _S[i][i.dual][_j];
654 Prob msg(_fg->var(i).states(),0.0);
655 LOOP_ij(
656 msg[xi] += S[xij]*_adj_m_unnorm_jI[xj];
657 );
658 msg *= 1-props.damping;
659 #if 0
660 if(msg.sumAbs() > pv_thresh) {
661 DAI_DMSG("in sendSeqMsgM loop");
662
663 DAI_PV(j);
664 DAI_PV(I);
665 DAI_PV(_I);
666 DAI_PV(_fg->nbF(I).size());
667 DAI_PV(_fg->factor(I).p());
668 DAI_PV(_S[i][i.dual][_j]);
669
670 DAI_PV(i);
671 DAI_PV(i.dual);
672 DAI_PV(msg);
673 DAI_PV(_fg->nbV(i).size());
674 }
675 #endif
676 assert(size_t(_fg->nbV(i)[i.dual]) == I);
677 sendSeqMsgN(i, i.dual, msg);
678 }
679 }
680 // assert(dist(_adj_m_unnorm_jI, _adj_m_unnorm[j][_I],Prob::DISTL1)<=1.0e-5);
681 setSeqMsgM(j, _I, _adj_m[j][_I]*props.damping);
682 }
683
684
685 void BBP::RegenerateSeqMessageAdjoints() {
686 size_t nv = _fg->nrVars();
687 _adj_m.resize(nv);
688 _adj_m_unnorm.resize(nv);
689 _new_adj_m.resize(nv);
690 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
691 size_t n_i = _fg->nbV(i).size();
692 _adj_m[i].resize(n_i);
693 _adj_m_unnorm[i].resize(n_i);
694 _new_adj_m[i].resize(n_i);
695 foreach(const Neighbor& I, _fg->nbV(i)) {
696 // calculate adj_m
697 Prob prod(_adj_b_V_unnorm[i]);
698 assert(prod.size()==_fg->var(i).states());
699 foreach(const Neighbor& J, _fg->nbV(i)) {
700 if(size_t(J) != size_t(I)) {
701 prod *= _bp_dual.msgM(i,J.iter);
702 }
703 }
704 _adj_m[i][I.iter] = prod;
705 calcUnnormMsgM(i, I.iter);
706 _new_adj_m[i][I.iter] = Prob(_fg->var(i).states(),0.0);
707 }
708 }
709 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
710 foreach(const Neighbor& I, _fg->nbV(i)) {
711 // calculate adj_n
712 Prob prod(_fg->factor(I).p());
713 prod *= _adj_b_F_unnorm[I];
714 foreach(const Neighbor& j, _fg->nbF(I)) {
715 if(i != j) {
716 Prob n_jI(_bp_dual.msgN(j,j.dual));
717 const _ind_t& ind = _index(j,j.dual);
718 // multiply prod with n_jI
719 for( size_t x_I = 0; x_I < prod.size(); x_I++ )
720 prod[x_I] *= n_jI[ind[x_I]];
721 }
722 }
723 Prob marg(_fg->var(i).states(), 0.0);
724 const _ind_t &ind = _index(i,I.iter);
725 for( size_t r = 0; r < prod.size(); r++ )
726 marg[ind[r]] += prod[r];
727 sendSeqMsgN(i,I.iter,marg);
728 }
729 }
730 }
731
732
733 void BBP::Regenerate() {
734 RegenerateInds();
735 RegenerateT();
736 RegenerateU();
737 RegenerateS();
738 RegenerateR();
739 RegenerateInputs();
740 RegeneratePsiAdjoints();
741 if(props.updates == Properties::UpdateType::PAR) {
742 RegenerateParMessageAdjoints();
743 } else {
744 RegenerateSeqMessageAdjoints();
745 }
746 _iters = 0;
747 }
748
749
750 void BBP::calcNewN(size_t i, size_t _I) {
751 _adj_psi_V[i] += T(i,_I)*_adj_n_unnorm[i][_I];
752 Prob &new_adj_n_iI = _new_adj_n[i][_I];
753 new_adj_n_iI = Prob(_fg->var(i).states(),0.0);
754 size_t I = _fg->nbV(i)[_I];
755 foreach(const Neighbor& j, _fg->nbF(I)) {
756 if(j!=i) {
757 const Prob &p = _S[i][_I][j.iter];
758 const Prob &_adj_m_unnorm_jI = _adj_m_unnorm[j][j.dual];
759 LOOP_ij(
760 new_adj_n_iI[xi] += p[xij]*_adj_m_unnorm_jI[xj];
761 );
762 }
763 }
764 }
765
766
767 void BBP::calcNewM(size_t i, size_t _I) {
768 const Neighbor &I = _fg->nbV(i)[_I];
769 Prob p(U(I,I.dual));
770 const Prob &adj = _adj_m_unnorm[i][_I];
771 const _ind_t& ind = _index(i,_I);
772 for( size_t x_I = 0; x_I < p.size(); x_I++ )
773 p[x_I] *= adj[ind[x_I]];
774 _adj_psi_F[I] += p;
775
776 _new_adj_m[i][_I] = Prob(_fg->var(i).states(),0.0);
777 foreach(const Neighbor& J, _fg->nbV(i)) {
778 if(J!=I) {
779 _new_adj_m[i][_I] += _R[I][I.dual][J.iter]*_adj_n_unnorm[i][J.iter];
780 }
781 }
782 }
783
784
785 void BBP::calcUnnormMsgM(size_t i, size_t _I) {
786 _adj_m_unnorm[i][_I] = unnormAdjoint(_bp_dual.msgM(i,_I), _bp_dual.zM(i,_I), _adj_m[i][_I]);
787 }
788
789
790 void BBP::calcUnnormMsgN(size_t i, size_t _I) {
791 _adj_n_unnorm[i][_I] = unnormAdjoint(_bp_dual.msgN(i,_I), _bp_dual.zN(i,_I), _adj_n[i][_I]);
792 }
793
794
795 void BBP::upMsgM(size_t i, size_t _I) {
796 _adj_m[i][_I] = _new_adj_m[i][_I];
797 calcUnnormMsgM(i,_I);
798 }
799
800
801 void BBP::upMsgN(size_t i, size_t _I) {
802 _adj_n[i][_I] = _new_adj_n[i][_I];
803 calcUnnormMsgN(i,_I);
804 }
805
806
807 void BBP::doParUpdate() {
808 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
809 foreach(const Neighbor& I, _fg->nbV(i)) {
810 calcNewM(i,I.iter);
811 calcNewN(i,I.iter);
812 }
813 }
814 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
815 foreach(const Neighbor& I, _fg->nbV(i)) {
816 upMsgM(i,I.iter);
817 upMsgN(i,I.iter);
818 }
819 }
820 }
821
822
823 Real BBP::getUnMsgMag() {
824 Real s=0.0;
825 size_t e=0;
826 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
827 foreach(const Neighbor& I, _fg->nbV(i)) {
828 s += _adj_m_unnorm[i][I.iter].sumAbs();
829 s += _adj_n_unnorm[i][I.iter].sumAbs();
830 e++;
831 }
832 }
833 return s/e;
834 }
835
836
837 void BBP::getMsgMags(Real &s, Real &new_s) {
838 s=0.0; new_s=0.0;
839 size_t e=0;
840 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
841 foreach(const Neighbor& I, _fg->nbV(i)) {
842 s += _adj_m[i][I.iter].sumAbs();
843 s += _adj_n[i][I.iter].sumAbs();
844 new_s += _new_adj_m[i][I.iter].sumAbs();
845 new_s += _new_adj_n[i][I.iter].sumAbs();
846 e++;
847 }
848 }
849 s /= e; new_s /= e;
850 }
851
852 // tuple<size_t,size_t,Real> BBP::getArgMaxPsi1Adj() {
853 // size_t argmax_var=0;
854 // size_t argmax_var_state=0;
855 // Real max_var=0;
856 // for( size_t i = 0; i < _fg->nrVars(); i++ ) {
857 // pair<size_t,Real> argmax_state = adj_psi_V(i).argmax();
858 // if(i==0 || argmax_state.second>max_var) {
859 // argmax_var = i;
860 // max_var = argmax_state.second;
861 // argmax_var_state = argmax_state.first;
862 // }
863 // }
864 // assert(/*0 <= argmax_var_state &&*/
865 // argmax_var_state < _fg->var(argmax_var).states());
866 // return tuple<size_t,size_t,Real>(argmax_var,argmax_var_state,max_var);
867 // }
868
869
870 Real BBP::getMaxMsgM() {
871 size_t dummy;
872 Real mag;
873 getArgmaxMsgM(dummy, dummy, mag);
874 return mag;
875 }
876
877
878 Real BBP::getTotalMsgM() {
879 Real mag=0.0;
880 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
881 foreach(const Neighbor &I, _fg->nbV(i)) {
882 mag += _adj_m[i][I.iter].sumAbs();
883 }
884 }
885 return mag;
886 }
887
888
889 Real BBP::getTotalNewMsgM() {
890 Real mag=0.0;
891 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
892 foreach(const Neighbor &I, _fg->nbV(i)) {
893 mag += _new_adj_m[i][I.iter].sumAbs();
894 }
895 }
896 return mag;
897 }
898
899
900 Real BBP::getTotalMsgN() {
901 Real mag=0.0;
902 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
903 foreach(const Neighbor &I, _fg->nbV(i)) {
904 mag += _adj_n[i][I.iter].sumAbs();
905 }
906 }
907 return mag;
908 }
909
910
911 void BBP::getArgmaxMsgM(size_t &out_i, size_t &out__I, Real &mag) {
912 bool found=false;
913 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
914 foreach(const Neighbor &I, _fg->nbV(i)) {
915 Real thisMag = _adj_m[i][I.iter].sumAbs();
916 if(!found || mag < thisMag) {
917 found = true;
918 mag = thisMag;
919 out_i = i;
920 out__I = I.iter;
921 }
922 }
923 }
924 assert(found);
925 }
926
927
928 void BBP::run() {
929 typedef BBP::Properties::UpdateType UT;
930 Real tol = props.tol;
931 UT updates = props.updates;
932 Real tic=toc();
933 switch((size_t)updates) {
934 case UT::SEQ_MAX: {
935 size_t i, _I;
936 Real mag;
937 do {
938 _iters++;
939 getArgmaxMsgM(i,_I,mag);
940 sendSeqMsgM(i,_I);
941 } while(mag > tol && _iters < props.maxiter);
942
943 if(_iters >= props.maxiter) {
944 cerr << "Warning: BBP didn't converge in " << _iters
945 << " iterations (greatest message magnitude = " << mag << ")"
946 << endl;
947 }
948 break;
949 }
950 case UT::SEQ_FIX: {
951 Real mag;
952 do {
953 _iters++;
954 mag = getTotalMsgM();
955 if(mag < tol) break;
956
957 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
958 foreach(const Neighbor &I, _fg->nbV(i)) {
959 sendSeqMsgM(i, I.iter);
960 }
961 }
962 for( size_t i = 0; i < _fg->nrVars(); i++ ) {
963 foreach(const Neighbor &I, _fg->nbV(i)) {
964 updateSeqMsgM(i, I.iter);
965 }
966 }
967 } while(mag > tol && _iters < props.maxiter);
968
969 if(_iters >= props.maxiter) {
970 cerr << "Warning: BBP didn't converge in " << _iters
971 << " iterations (greatest message magnitude = " << mag << ")"
972 << endl;
973 break;
974 }
975 break;
976 }
977 case UT::SEQ_BP_REV:
978 case UT::SEQ_BP_FWD: {
979 const BP *bp = static_cast<const BP*>(_ia);
980 vector<pair<size_t, size_t> > sentMessages = bp->getSentMessages();
981 size_t totalMessages = sentMessages.size();
982 if(totalMessages==0) {
983 cerr << "Asked for updates = " << updates << " but no BP messages; did you forget to set recordSentMessages?" << endl;
984 DAI_THROW(INTERNAL_ERROR);
985 }
986 if(updates==UT::SEQ_BP_FWD) {
987 reverse(sentMessages.begin(), sentMessages.end());
988 }
989 // DAI_PV(sentMessages.size());
990 // DAI_PV(_iters);
991 // DAI_PV(props.maxiter);
992 while(sentMessages.size()>0 && _iters < props.maxiter) {
993 // DAI_PV(sentMessages.size());
994 // DAI_PV(_iters);
995 _iters++;
996 pair<size_t, size_t> e = sentMessages.back();
997 sentMessages.pop_back();
998 size_t i = e.first, _I = e.second;
999 sendSeqMsgM(i,_I);
1000 }
1001 if(_iters >= props.maxiter) {
1002 cerr << "Warning: BBP updates limited to " << props.maxiter
1003 << " iterations, but using UpdateType " << updates
1004 << " with " << totalMessages << " messages"
1005 << endl;
1006 }
1007 break;
1008 }
1009 case UT::PAR: {
1010 do {
1011 _iters++;
1012 doParUpdate();
1013 } while((_iters < 2 || getUnMsgMag() > tol) && _iters < props.maxiter);
1014 if(_iters==props.maxiter) {
1015 Real s, new_s;
1016 getMsgMags(s,new_s);
1017 cerr << "Warning: BBP didn't converge in " << _iters
1018 << " iterations (unnorm message magnitude = " << getUnMsgMag()
1019 << ", norm message mags = " << s << " -> " << new_s
1020 << ")" << endl;
1021 }
1022 break;
1023 }
1024 }
1025 if(props.verbose >= 3) {
1026 cerr << "BBP::run() took " << toc()-tic << " seconds "
1027 << doneIters() << " iterations" << endl;
1028 }
1029 }
1030
1031
1032 bool needGibbsState(bbp_cfn_t cfn) {
1033 switch((size_t)cfn) {
1034 case bbp_cfn_t::cfn_gibbs_b:
1035 case bbp_cfn_t::cfn_gibbs_b2:
1036 case bbp_cfn_t::cfn_gibbs_exp:
1037 case bbp_cfn_t::cfn_gibbs_b_factor:
1038 case bbp_cfn_t::cfn_gibbs_b2_factor:
1039 case bbp_cfn_t::cfn_gibbs_exp_factor:
1040 return true;
1041 default:
1042 return false;
1043 }
1044 }
1045
1046
1047 vector<size_t> getGibbsState(const InfAlg& ia, size_t iters) {
1048 PropertySet gibbsProps;
1049 gibbsProps.Set("iters", iters);
1050 gibbsProps.Set("verbose", size_t(0));
1051 Gibbs gibbs(ia.fg(), gibbsProps);
1052 gibbs.run();
1053 return gibbs.state();
1054 }
1055
1056
1057 double numericBBPTest(const InfAlg& bp, const vector<size_t> *state, const PropertySet& bbp_props, bbp_cfn_t cfn, double h) {
1058 // calculate the value of the unperturbed cost function
1059 Real cf0 = getCostFn(bp, cfn, state);
1060
1061 // run BBP to estimate adjoints
1062 BBP bbp(&bp,bbp_props);
1063 initBBPCostFnAdj(bbp, bp, cfn, state);
1064 bbp.run();
1065
1066 Real d=0;
1067 const FactorGraph& fg = bp.fg();
1068
1069 if(1) {
1070 // verify bbp.adj_psi_V
1071
1072 // for each variable i
1073 for(size_t i=0; i<fg.nrVars(); i++) {
1074 vector<double> adj_est;
1075 // for each value xi
1076 for(size_t xi=0; xi<fg.var(i).states(); xi++) {
1077 // Clone 'bp' (which may be any InfAlg)
1078 InfAlg *bp_prb = bp.clone();
1079
1080 // perturb it
1081 size_t n = bp_prb->fg().var(i).states();
1082 Prob psi_1_prb(n,1.0);
1083 psi_1_prb[xi] += h;
1084 // psi_1_prb.normalize();
1085 size_t I = bp_prb->fg().nbV(i)[0]; // use first factor in list of neighbors of i
1086 bp_prb->fg().factor(I) *= Factor(bp_prb->fg().var(i), psi_1_prb);
1087
1088 // call 'init' on the perturbed variables
1089 bp_prb->init(bp_prb->fg().var(i));
1090
1091 // run copy to convergence
1092 bp_prb->run();
1093
1094 // calculate new value of cost function
1095 Real cf_prb = getCostFn(*bp_prb, cfn, state);
1096
1097 // use to estimate adjoint for i
1098 adj_est.push_back((cf_prb-cf0)/h);
1099
1100 // free cloned InfAlg
1101 delete bp_prb;
1102 }
1103 Prob p_adj_est(adj_est.begin(), adj_est.end());
1104 // compare this numerical estimate to the BBP estimate; sum the distances
1105 cerr << "i: " << i
1106 << ", p_adj_est: " << p_adj_est
1107 << ", bbp.adj_psi_V(i): " << bbp.adj_psi_V(i) << endl;
1108 d += dist(p_adj_est, bbp.adj_psi_V(i), Prob::DISTL1);
1109 }
1110 }
1111 /* if(1) {
1112 // verify bbp.adj_n and bbp.adj_m
1113
1114 // We actually want to check the responsiveness of objective
1115 // function to changes in the final messages. But at the end of a
1116 // BBP run, the message adjoints are for the initial messages (and
1117 // they should be close to zero, see paper). So this resets the
1118 // BBP adjoints to the refer to the desired final messages
1119 bbp.RegenerateMessageAdjoints();
1120
1121 // for each variable i
1122 for(size_t i=0; i<bp_dual.nrVars(); i++) {
1123 // for each factor I ~ i
1124 foreach(size_t I, bp_dual.nbV(i)) {
1125 vector<double> adj_n_est;
1126 // for each value xi
1127 for(size_t xi=0; xi<bp_dual.var(i).states(); xi++) {
1128 BP_dual bp_dual_prb(bp_dual);
1129 // make h-sized change to newMsgN
1130 bp_dual_prb.newMsgN(i,I)[xi] += h;
1131 // recalculate beliefs
1132 bp_dual_prb.CalcBeliefs();
1133 // get cost function value
1134 Real cf_prb = getCostFn(bp_dual_prb, cfn, &state);
1135 // add it to list of adjoints
1136 adj_n_est.push_back((cf_prb-cf0)/h);
1137 }
1138
1139 vector<double> adj_m_est;
1140 // for each value xi
1141 for(size_t xi=0; xi<bp_dual.var(i).states(); xi++) {
1142 BP_dual bp_dual_prb(bp_dual);
1143 // make h-sized change to newMsgM
1144 bp_dual_prb.newMsgM(I,i)[xi] += h;
1145 // recalculate beliefs
1146 bp_dual_prb.CalcBeliefs();
1147 // get cost function value
1148 Real cf_prb = getCostFn(bp_dual_prb, cfn, &state);
1149 // add it to list of adjoints
1150 adj_m_est.push_back((cf_prb-cf0)/h);
1151 }
1152
1153 Prob p_adj_n_est(adj_n_est.begin(), adj_n_est.end());
1154 // compare this numerical estimate to the BBP estimate; sum the distances
1155 cerr << "i: " << i << ", I: " << I
1156 << ", adj_n_est: " << p_adj_n_est
1157 << ", bbp.adj_n(i,I): " << bbp.adj_n(i,I) << endl;
1158 d += dist(p_adj_n_est, bbp.adj_n(i,I), Prob::DISTL1);
1159
1160 Prob p_adj_m_est(adj_m_est.begin(), adj_m_est.end());
1161 // compare this numerical estimate to the BBP estimate; sum the distances
1162 cerr << "i: " << i << ", I: " << I
1163 << ", adj_m_est: " << p_adj_m_est
1164 << ", bbp.adj_m(I,i): " << bbp.adj_m(I,i) << endl;
1165 d += dist(p_adj_m_est, bbp.adj_m(I,i), Prob::DISTL1);
1166 }
1167 }
1168 }
1169 */
1170 /* if(0) {
1171 // verify bbp.adj_b_V
1172 for(size_t i=0; i<bp_dual.nrVars(); i++) {
1173 vector<double> adj_b_V_est;
1174 // for each value xi
1175 for(size_t xi=0; xi<bp_dual.var(i).states(); xi++) {
1176 BP_dual bp_dual_prb(bp_dual);
1177
1178 // make h-sized change to b_1(i)[x_i]
1179 bp_dual_prb._beliefs.b1[i][xi] += h;
1180
1181 // get cost function value
1182 Real cf_prb = getCostFn(bp_dual_prb, cfn, &state);
1183
1184 // add it to list of adjoints
1185 adj_b_V_est.push_back((cf_prb-cf0)/h);
1186 }
1187 Prob p_adj_b_V_est(adj_b_V_est.begin(), adj_b_V_est.end());
1188 // compare this numerical estimate to the BBP estimate; sum the distances
1189 cerr << "i: " << i
1190 << ", adj_b_V_est: " << p_adj_b_V_est
1191 << ", bbp.adj_b_V(i): " << bbp.adj_b_V(i) << endl;
1192 d += dist(p_adj_b_V_est, bbp.adj_b_V(i), Prob::DISTL1);
1193 }
1194 }
1195 */
1196
1197 // return total of distances
1198 return d;
1199 }
1200
1201
1202 } // end of namespace dai
1203
1204
1205 /* {{{ GENERATED CODE: DO NOT EDIT. Created by
1206 ./scripts/regenerate-properties include/dai/bbp.h src/bbp.cpp
1207 */
1208 namespace dai {
1209
1210 void BBP::Properties::set(const PropertySet &opts)
1211 {
1212 const std::set<PropertyKey> &keys = opts.allKeys();
1213 std::set<PropertyKey>::const_iterator i;
1214 bool die=false;
1215 for(i=keys.begin(); i!=keys.end(); i++) {
1216 if(*i == "verbose") continue;
1217 if(*i == "tol") continue;
1218 if(*i == "maxiter") continue;
1219 if(*i == "damping") continue;
1220 if(*i == "updates") continue;
1221 if(*i == "clean_updates") continue;
1222 cerr << "BBP: Unknown property " << *i << endl;
1223 die=true;
1224 }
1225 if(die) {
1226 DAI_THROW(UNKNOWN_PROPERTY_TYPE);
1227 }
1228 if(!opts.hasKey("verbose")) {
1229 cerr << "BBP: Missing property \"verbose\" for method \"BBP\"" << endl;
1230 die=true;
1231 }
1232 if(!opts.hasKey("tol")) {
1233 cerr << "BBP: Missing property \"tol\" for method \"BBP\"" << endl;
1234 die=true;
1235 }
1236 if(!opts.hasKey("maxiter")) {
1237 cerr << "BBP: Missing property \"maxiter\" for method \"BBP\"" << endl;
1238 die=true;
1239 }
1240 if(!opts.hasKey("damping")) {
1241 cerr << "BBP: Missing property \"damping\" for method \"BBP\"" << endl;
1242 die=true;
1243 }
1244 if(!opts.hasKey("updates")) {
1245 cerr << "BBP: Missing property \"updates\" for method \"BBP\"" << endl;
1246 die=true;
1247 }
1248 if(!opts.hasKey("clean_updates")) {
1249 cerr << "BBP: Missing property \"clean_updates\" for method \"BBP\"" << endl;
1250 die=true;
1251 }
1252 if(die) {
1253 DAI_THROW(NOT_ALL_PROPERTIES_SPECIFIED);
1254 }
1255 verbose = opts.getStringAs<size_t>("verbose");
1256 tol = opts.getStringAs<double>("tol");
1257 maxiter = opts.getStringAs<size_t>("maxiter");
1258 damping = opts.getStringAs<double>("damping");
1259 updates = opts.getStringAs<UpdateType>("updates");
1260 clean_updates = opts.getStringAs<bool>("clean_updates");
1261 }
1262 PropertySet BBP::Properties::get() const {
1263 PropertySet opts;
1264 opts.Set("verbose", verbose);
1265 opts.Set("tol", tol);
1266 opts.Set("maxiter", maxiter);
1267 opts.Set("damping", damping);
1268 opts.Set("updates", updates);
1269 opts.Set("clean_updates", clean_updates);
1270 return opts;
1271 }
1272 string BBP::Properties::toString() const {
1273 stringstream s(stringstream::out);
1274 s << "[";
1275 s << "verbose=" << verbose << ",";
1276 s << "tol=" << tol << ",";
1277 s << "maxiter=" << maxiter << ",";
1278 s << "damping=" << damping << ",";
1279 s << "updates=" << updates << ",";
1280 s << "clean_updates=" << clean_updates;
1281 s << "]";
1282 return s.str();
1283 }
1284 } // end of namespace dai
1285 /* }}} END OF GENERATED CODE */