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