153df2747184055d5145e3c1e9f9215db1e04d2a
1 /* This file is part of libDAI - http://www.libdai.org/
3 * Copyright (c) 2006-2011, The libDAI authors. All rights reserved.
5 * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
15 #include <dai/alldai.h>
24 void LC::setProperties( const PropertySet
&opts
) {
25 DAI_ASSERT( opts
.hasKey("tol") );
26 DAI_ASSERT( opts
.hasKey("maxiter") );
27 DAI_ASSERT( opts
.hasKey("cavity") );
28 DAI_ASSERT( opts
.hasKey("updates") );
30 props
.tol
= opts
.getStringAs
<Real
>("tol");
31 props
.maxiter
= opts
.getStringAs
<size_t>("maxiter");
32 props
.cavity
= opts
.getStringAs
<Properties::CavityType
>("cavity");
33 props
.updates
= opts
.getStringAs
<Properties::UpdateType
>("updates");
34 if( opts
.hasKey("verbose") )
35 props
.verbose
= opts
.getStringAs
<size_t>("verbose");
38 if( opts
.hasKey("cavainame") )
39 props
.cavainame
= opts
.getStringAs
<string
>("cavainame");
40 if( opts
.hasKey("cavaiopts") )
41 props
.cavaiopts
= opts
.getStringAs
<PropertySet
>("cavaiopts");
42 if( opts
.hasKey("reinit") )
43 props
.reinit
= opts
.getStringAs
<bool>("reinit");
44 if( opts
.hasKey("damping") )
45 props
.damping
= opts
.getStringAs
<Real
>("damping");
51 PropertySet
LC::getProperties() const {
53 opts
.set( "tol", props
.tol
);
54 opts
.set( "maxiter", props
.maxiter
);
55 opts
.set( "verbose", props
.verbose
);
56 opts
.set( "cavity", props
.cavity
);
57 opts
.set( "updates", props
.updates
);
58 opts
.set( "cavainame", props
.cavainame
);
59 opts
.set( "cavaiopts", props
.cavaiopts
);
60 opts
.set( "reinit", props
.reinit
);
61 opts
.set( "damping", props
.damping
);
66 string
LC::printProperties() const {
67 stringstream
s( stringstream::out
);
69 s
<< "tol=" << props
.tol
<< ",";
70 s
<< "maxiter=" << props
.maxiter
<< ",";
71 s
<< "verbose=" << props
.verbose
<< ",";
72 s
<< "cavity=" << props
.cavity
<< ",";
73 s
<< "updates=" << props
.updates
<< ",";
74 s
<< "cavainame=" << props
.cavainame
<< ",";
75 s
<< "cavaiopts=" << props
.cavaiopts
<< ",";
76 s
<< "reinit=" << props
.reinit
<< ",";
77 s
<< "damping=" << props
.damping
<< "]";
82 LC::LC( const FactorGraph
& fg
, const PropertySet
&opts
) : DAIAlgFG(fg
), _pancakes(), _cavitydists(), _phis(), _beliefs(), _maxdiff(0.0), _iters(0), props() {
83 setProperties( opts
);
86 _pancakes
.resize( nrVars() );
89 for( size_t i
=0; i
< nrVars(); i
++ )
90 _cavitydists
.push_back(Factor( delta(i
) ));
93 _phis
.reserve( nrVars() );
94 for( size_t i
= 0; i
< nrVars(); i
++ ) {
95 _phis
.push_back( vector
<Factor
>() );
96 _phis
[i
].reserve( nbV(i
).size() );
97 bforeach( const Neighbor
&I
, nbV(i
) )
98 _phis
[i
].push_back( Factor( factor(I
).vars() / var(i
) ) );
102 _beliefs
.reserve( nrVars() );
103 for( size_t i
=0; i
< nrVars(); i
++ )
104 _beliefs
.push_back(Factor(var(i
)));
108 void LC::CalcBelief (size_t i
) {
109 _beliefs
[i
] = _pancakes
[i
].marginal(var(i
));
113 Factor
LC::belief (const VarSet
&ns
) const {
116 else if( ns
.size() == 1 )
117 return beliefV( findVar( *(ns
.begin()) ) );
119 DAI_THROW(BELIEF_NOT_AVAILABLE
);
125 Real
LC::CalcCavityDist (size_t i
, const std::string
&name
, const PropertySet
&opts
) {
129 if( props
.verbose
>= 2 )
130 cerr
<< "Initing cavity " << var(i
) << "(" << delta(i
).size() << " vars, " << delta(i
).nrStates() << " states)" << endl
;
132 if( props
.cavity
== Properties::CavityType::UNIFORM
)
133 Bi
= Factor(delta(i
));
135 InfAlg
*cav
= newInfAlg( name
, *this, opts
);
136 cav
->makeCavity( i
);
138 if( props
.cavity
== Properties::CavityType::FULL
)
139 Bi
= calcMarginal( *cav
, cav
->fg().delta(i
), props
.reinit
);
140 else if( props
.cavity
== Properties::CavityType::PAIR
) {
141 vector
<Factor
> pairbeliefs
= calcPairBeliefs( *cav
, cav
->fg().delta(i
), props
.reinit
, false );
142 for( size_t ij
= 0; ij
< pairbeliefs
.size(); ij
++ )
143 Bi
*= pairbeliefs
[ij
];
144 } else if( props
.cavity
== Properties::CavityType::PAIR2
) {
145 vector
<Factor
> pairbeliefs
= calcPairBeliefs( *cav
, cav
->fg().delta(i
), props
.reinit
, true );
146 for( size_t ij
= 0; ij
< pairbeliefs
.size(); ij
++ )
147 Bi
*= pairbeliefs
[ij
];
149 maxdiff
= cav
->maxDiff();
153 _cavitydists
[i
] = Bi
;
159 Real
LC::InitCavityDists( const std::string
&name
, const PropertySet
&opts
) {
162 if( props
.verbose
>= 1 ) {
163 cerr
<< this->name() << "::InitCavityDists: ";
164 if( props
.cavity
== Properties::CavityType::UNIFORM
)
165 cerr
<< "Using uniform initial cavity distributions" << endl
;
166 else if( props
.cavity
== Properties::CavityType::FULL
)
167 cerr
<< "Using full " << name
<< opts
<< "...";
168 else if( props
.cavity
== Properties::CavityType::PAIR
)
169 cerr
<< "Using pairwise " << name
<< opts
<< "...";
170 else if( props
.cavity
== Properties::CavityType::PAIR2
)
171 cerr
<< "Using pairwise(new) " << name
<< opts
<< "...";
175 for( size_t i
= 0; i
< nrVars(); i
++ ) {
176 Real md
= CalcCavityDist(i
, name
, opts
);
181 if( props
.verbose
>= 1 ) {
182 cerr
<< this->name() << "::InitCavityDists used " << toc() - tic
<< " seconds." << endl
;
189 long LC::SetCavityDists( std::vector
<Factor
> &Q
) {
190 if( props
.verbose
>= 1 )
191 cerr
<< name() << "::SetCavityDists: Setting initial cavity distributions" << endl
;
192 if( Q
.size() != nrVars() )
194 for( size_t i
= 0; i
< nrVars(); i
++ ) {
195 if( _cavitydists
[i
].vars() != Q
[i
].vars() ) {
198 _cavitydists
[i
] = Q
[i
];
205 for( size_t i
= 0; i
< nrVars(); ++i
)
206 bforeach( const Neighbor
&I
, nbV(i
) )
207 if( props
.updates
== Properties::UpdateType::SEQRND
)
208 _phis
[i
][I
.iter
].randomize();
210 _phis
[i
][I
.iter
].fill(1.0);
214 Factor
LC::NewPancake (size_t i
, size_t _I
, bool & hasNaNs
) {
215 size_t I
= nbV(i
)[_I
];
216 Factor piet
= _pancakes
[i
];
218 // recalculate _pancake[i]
219 VarSet Ivars
= factor(I
).vars();
221 for( VarSet::const_iterator k
= Ivars
.begin(); k
!= Ivars
.end(); k
++ )
223 A_I
*= (_pancakes
[findVar(*k
)] * factor(I
).inverse()).marginal( Ivars
/ var(i
), false );
224 if( Ivars
.size() > 1 )
225 A_I
^= (1.0 / (Ivars
.size() - 1));
226 Factor A_Ii
= (_pancakes
[i
] * factor(I
).inverse() * _phis
[i
][_I
].inverse()).marginal( Ivars
/ var(i
), false );
227 Factor quot
= A_I
/ A_Ii
;
228 if( props
.damping
!= 0.0 )
229 quot
= (quot
^(1.0 - props
.damping
)) * (_phis
[i
][_I
]^props
.damping
);
231 piet
*= quot
/ _phis
[i
][_I
].normalized();
232 _phis
[i
][_I
] = quot
.normalized();
236 if( piet
.hasNaNs() ) {
237 cerr
<< name() << "::NewPancake(" << i
<< ", " << _I
<< "): has NaNs!" << endl
;
246 if( props
.verbose
>= 1 )
247 cerr
<< "Starting " << identify() << "...";
248 if( props
.verbose
>= 2 )
253 Real md
= InitCavityDists( props
.cavainame
, props
.cavaiopts
);
257 for( size_t i
= 0; i
< nrVars(); i
++ ) {
258 _pancakes
[i
] = _cavitydists
[i
];
260 bforeach( const Neighbor
&I
, nbV(i
) ) {
261 _pancakes
[i
] *= factor(I
);
262 if( props
.updates
== Properties::UpdateType::SEQRND
)
263 _pancakes
[i
] *= _phis
[i
][I
.iter
];
266 _pancakes
[i
].normalize();
271 vector
<Factor
> oldBeliefsV
;
272 for( size_t i
= 0; i
< nrVars(); i
++ )
273 oldBeliefsV
.push_back( beliefV(i
) );
275 bool hasNaNs
= false;
276 for( size_t i
=0; i
< nrVars(); i
++ )
277 if( _pancakes
[i
].hasNaNs() ) {
282 cerr
<< name() << "::run: initial _pancakes has NaNs!" << endl
;
286 size_t nredges
= nrEdges();
287 vector
<Edge
> update_seq
;
288 update_seq
.reserve( nredges
);
289 for( size_t i
= 0; i
< nrVars(); ++i
)
290 bforeach( const Neighbor
&I
, nbV(i
) )
291 update_seq
.push_back( Edge( i
, I
.iter
) );
293 // do several passes over the network until maximum number of iterations has
294 // been reached or until the maximum belief difference is smaller than tolerance
295 Real maxDiff
= INFINITY
;
296 for( _iters
= 0; _iters
< props
.maxiter
&& maxDiff
> props
.tol
; _iters
++ ) {
297 // Sequential updates
298 if( props
.updates
== Properties::UpdateType::SEQRND
)
299 random_shuffle( update_seq
.begin(), update_seq
.end(), rnd
);
301 for( size_t t
=0; t
< nredges
; t
++ ) {
302 size_t i
= update_seq
[t
].first
;
303 size_t _I
= update_seq
[t
].second
;
304 _pancakes
[i
] = NewPancake( i
, _I
, hasNaNs
);
310 // compare new beliefs with old ones
312 for( size_t i
= 0; i
< nrVars(); i
++ ) {
313 maxDiff
= std::max( maxDiff
, dist( beliefV(i
), oldBeliefsV
[i
], DISTLINF
) );
314 oldBeliefsV
[i
] = beliefV(i
);
317 if( props
.verbose
>= 3 )
318 cerr
<< name() << "::run: maxdiff " << maxDiff
<< " after " << _iters
+1 << " passes" << endl
;
321 if( maxDiff
> _maxdiff
)
324 if( props
.verbose
>= 1 ) {
325 if( maxDiff
> props
.tol
) {
326 if( props
.verbose
== 1 )
328 cerr
<< name() << "::run: WARNING: not converged within " << props
.maxiter
<< " passes (" << toc() - tic
<< " seconds)...final maxdiff:" << maxDiff
<< endl
;
330 if( props
.verbose
>= 2 )
331 cerr
<< name() << "::run: ";
332 cerr
<< "converged in " << _iters
<< " passes (" << toc() - tic
<< " seconds)." << endl
;
340 } // end of namespace dai