Updated copyrights
[libdai.git] / src / mf.cpp
1 /* Copyright (C) 2006-2008 Joris Mooij [joris dot mooij at tuebingen dot mpg dot de]
2 Radboud University Nijmegen, The Netherlands /
3 Max Planck Institute for Biological Cybernetics, Germany
4
5 This file is part of libDAI.
6
7 libDAI is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 libDAI is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with libDAI; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23 #include <iostream>
24 #include <sstream>
25 #include <map>
26 #include <set>
27 #include <dai/mf.h>
28 #include <dai/diffs.h>
29 #include <dai/util.h>
30
31
32 namespace dai {
33
34
35 using namespace std;
36
37
38 const char *MF::Name = "MF";
39
40
41 void MF::setProperties( const PropertySet &opts ) {
42 assert( opts.hasKey("tol") );
43 assert( opts.hasKey("maxiter") );
44
45 props.tol = opts.getStringAs<double>("tol");
46 props.maxiter = opts.getStringAs<size_t>("maxiter");
47 if( opts.hasKey("verbose") )
48 props.verbose = opts.getStringAs<size_t>("verbose");
49 else
50 props.verbose = 0U;
51 if( opts.hasKey("damping") )
52 props.damping = opts.getStringAs<double>("damping");
53 else
54 props.damping = 0.0;
55 }
56
57
58 PropertySet MF::getProperties() const {
59 PropertySet opts;
60 opts.Set( "tol", props.tol );
61 opts.Set( "maxiter", props.maxiter );
62 opts.Set( "verbose", props.verbose );
63 opts.Set( "damping", props.damping );
64 return opts;
65 }
66
67
68 string MF::printProperties() const {
69 stringstream s( stringstream::out );
70 s << "[";
71 s << "tol=" << props.tol << ",";
72 s << "maxiter=" << props.maxiter << ",";
73 s << "verbose=" << props.verbose << ",";
74 s << "damping=" << props.damping << "]";
75 return s.str();
76 }
77
78
79 void MF::construct() {
80 // create beliefs
81 _beliefs.clear();
82 _beliefs.reserve( nrVars() );
83 for( size_t i = 0; i < nrVars(); ++i )
84 _beliefs.push_back( Factor( var(i) ) );
85 }
86
87
88 string MF::identify() const {
89 return string(Name) + printProperties();
90 }
91
92
93 void MF::init() {
94 for( vector<Factor>::iterator qi = _beliefs.begin(); qi != _beliefs.end(); qi++ )
95 qi->fill(1.0);
96 }
97
98
99 double MF::run() {
100 double tic = toc();
101
102 if( props.verbose >= 1 )
103 cout << "Starting " << identify() << "...";
104
105 size_t pass_size = _beliefs.size();
106 Diffs diffs(pass_size * 3, 1.0);
107
108 size_t t=0;
109 for( t=0; t < (props.maxiter*pass_size) && diffs.maxDiff() > props.tol; t++ ) {
110 // choose random Var i
111 size_t i = (size_t) (nrVars() * rnd_uniform());
112
113 Factor jan;
114 Factor piet;
115 foreach( const Neighbor &I, nbV(i) ) {
116 Factor henk;
117 foreach( const Neighbor &j, nbF(I) ) // for all j in I \ i
118 if( j != i )
119 henk *= _beliefs[j];
120 piet = factor(I).log0();
121 piet *= henk;
122 piet = piet.partSum(var(i));
123 piet = piet.exp();
124 jan *= piet;
125 }
126
127 jan.normalize();
128
129 if( jan.hasNaNs() ) {
130 cout << Name << "::run(): ERROR: jan has NaNs!" << endl;
131 return 1.0;
132 }
133
134 if( props.damping != 0.0 )
135 jan = (jan^(1.0 - props.damping)) * (_beliefs[i]^props.damping);
136 diffs.push( dist( jan, _beliefs[i], Prob::DISTLINF ) );
137
138 _beliefs[i] = jan;
139 }
140
141 _iters = t / pass_size;
142 if( diffs.maxDiff() > _maxdiff )
143 _maxdiff = diffs.maxDiff();
144
145 if( props.verbose >= 1 ) {
146 if( diffs.maxDiff() > props.tol ) {
147 if( props.verbose == 1 )
148 cout << endl;
149 cout << Name << "::run: WARNING: not converged within " << props.maxiter << " passes (" << toc() - tic << " seconds)...final maxdiff:" << diffs.maxDiff() << endl;
150 } else {
151 if( props.verbose >= 2 )
152 cout << Name << "::run: ";
153 cout << "converged in " << t / pass_size << " passes (" << toc() - tic << " seconds)." << endl;
154 }
155 }
156
157 return diffs.maxDiff();
158 }
159
160
161 Factor MF::beliefV( size_t i ) const {
162 Factor piet;
163 piet = _beliefs[i];
164 piet.normalize();
165 return(piet);
166 }
167
168
169 Factor MF::belief (const VarSet &ns) const {
170 if( ns.size() == 1 )
171 return belief( *(ns.begin()) );
172 else {
173 assert( ns.size() == 1 );
174 return Factor();
175 }
176 }
177
178
179 Factor MF::belief (const Var &n) const {
180 return( beliefV( findVar( n ) ) );
181 }
182
183
184 vector<Factor> MF::beliefs() const {
185 vector<Factor> result;
186 for( size_t i = 0; i < nrVars(); i++ )
187 result.push_back( beliefV(i) );
188 return result;
189 }
190
191
192 Real MF::logZ() const {
193 Real sum = 0.0;
194
195 for(size_t i=0; i < nrVars(); i++ )
196 sum -= beliefV(i).entropy();
197 for(size_t I=0; I < nrFactors(); I++ ) {
198 Factor henk;
199 foreach( const Neighbor &j, nbF(I) ) // for all j in I
200 henk *= _beliefs[j];
201 henk.normalize();
202 Factor piet;
203 piet = factor(I).log0();
204 piet *= henk;
205 sum -= piet.totalSum();
206 }
207
208 return -sum;
209 }
210
211
212 void MF::init( const VarSet &ns ) {
213 for( size_t i = 0; i < nrVars(); i++ ) {
214 if( ns.contains(var(i) ) )
215 _beliefs[i].fill( 1.0 );
216 }
217 }
218
219
220 } // end of namespace dai