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