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
5 This file is part of libDAI.
7 libDAI is free software; you can redistribute it and/or modify
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
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.
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 */
23 /// \file
24 /// \brief Defines the FactorGraph class
27 #ifndef __defined_libdai_factorgraph_h
28 #define __defined_libdai_factorgraph_h
31 #include <iostream>
32 #include <map>
33 #include <dai/bipgraph.h>
34 #include <dai/factor.h>
37 namespace dai {
40 /// Represents a factor graph.
41 /** Both Bayesian Networks and Markov random fields can be represented in a
42 * unifying representation, called <em>factor graph</em> [\ref KFL01],
43 * implemented in libDAI by the FactorGraph class.
44 *
45 * Consider a probability distribution over \f$N\f$ discrete random variables
46 * \f$x_0,x_1,\dots,x_N\f$ that factorizes as a product of factors, each of
47 * which depends on some subset of the variables:
48 * \f[
49 * P(x_0,x_1,\dots,x_N) = \frac{1}{Z} \prod_{I=0}^M f_I(x_I), \qquad
50 * Z = \sum_{x_0}\dots\sum_{x_N} \prod_{I=0}^M f_I(X_I).
51 * \f]
52 * Each factor \f$f_I\f$ is a function from an associated subset
53 * of variables \f$X_I \subset \{x_0,x_1,\dots,x_N\}\f$ to the nonnegative
54 * real numbers.
55 *
56 * For a Bayesian network, each factor corresponds to a (conditional)
57 * probability table, whereas for a Markov random field, each factor
58 * corresponds to a maximal clique of the undirected graph.
59 *
60 * Factor graphs explicitly express the factorization structure of the
61 * corresponding probability distribution.
62 */
63 class FactorGraph {
64 public:
65 /// Stores the neighborhood structure
66 BipartiteGraph G;
68 /// Shorthand for BipartiteGraph::Neighbor
69 typedef BipartiteGraph::Neighbor Neighbor;
71 /// Shorthand for BipartiteGraph::Neighbors
72 typedef BipartiteGraph::Neighbors Neighbors;
74 /// Shorthand for BipartiteGraph::Edge
75 typedef BipartiteGraph::Edge Edge;
77 private:
78 std::vector<Var> _vars;
79 std::vector<Factor> _factors;
80 std::map<size_t,Factor> _backup;
82 public:
83 /// Default constructor
84 FactorGraph() : G(), _vars(), _factors(), _backup() {}
86 /// Copy constructor
87 FactorGraph(const FactorGraph & x) : G(x.G), _vars(x._vars), _factors(x._factors), _backup(x._backup) {}
89 /// Assignment operator
90 FactorGraph & operator=(const FactorGraph & x) {
91 if( this != &x ) {
92 G = x.G;
93 _vars = x._vars;
94 _factors = x._factors;
95 _backup = x._backup;
96 }
97 return *this;
98 }
100 /// Constructs a FactorGraph from a vector of factors
101 FactorGraph(const std::vector<Factor> &P);
103 /// Constructs a FactorGraph from given factor and variable iterators
104 /** \tparam FactorInputIterator Iterator with value_type Factor
105 * \tparam VarInputIterator Iterator with value_type Var
106 * \pre Assumes that the set of variables in [var_begin,var_end) is the union of the variables in the factors in [fact_begin, fact_end)
107 */
108 template<typename FactorInputIterator, typename VarInputIterator>
109 FactorGraph(FactorInputIterator fact_begin, FactorInputIterator fact_end, VarInputIterator var_begin, VarInputIterator var_end, size_t nr_fact_hint = 0, size_t nr_var_hint = 0 );
111 /// Destructor
112 virtual ~FactorGraph() {}
114 /// Clone *this (virtual copy constructor)
115 virtual FactorGraph* clone() const { return new FactorGraph(); }
117 /// Create (virtual default constructor)
118 virtual FactorGraph* create() const { return new FactorGraph(*this); }
120 /// Returns const reference to i'th variable
121 const Var & var(size_t i) const { return _vars[i]; }
122 /// Returns const reference to all factors
123 const std::vector<Var> & vars() const { return _vars; }
124 /// Returns reference to I'th factor
125 Factor & factor(size_t I) { return _factors[I]; }
126 /// Returns const reference to I'th factor
127 const Factor & factor(size_t I) const { return _factors[I]; }
128 /// Returns const reference to all factors
129 const std::vector<Factor> & factors() const { return _factors; }
131 /// Returns number of variables
132 size_t nrVars() const { return vars().size(); }
133 /// Returns number of factors
134 size_t nrFactors() const { return factors().size(); }
135 /// Calculates number of edges
136 size_t nrEdges() const { return G.nrEdges(); }
139 const Neighbors & nbV( size_t i ) const { return G.nb1(i); }
141 Neighbors & nbV( size_t i ) { return G.nb1(i); }
143 const Neighbors & nbF( size_t I ) const { return G.nb2(I); }
145 Neighbors & nbF( size_t I ) { return G.nb2(I); }
147 const Neighbor & nbV( size_t i, size_t _I ) const { return G.nb1(i)[_I]; }
149 Neighbor & nbV( size_t i, size_t _I ) { return G.nb1(i)[_I]; }
151 const Neighbor & nbF( size_t I, size_t _i ) const { return G.nb2(I)[_i]; }
153 Neighbor & nbF( size_t I, size_t _i ) { return G.nb2(I)[_i]; }
155 /// Returns the index of a particular variable
156 size_t findVar( const Var & n ) const {
157 size_t i = find( vars().begin(), vars().end(), n ) - vars().begin();
158 assert( i != nrVars() );
159 return i;
160 }
162 /// Returns a set of indexes corresponding to a set of variables
163 std::set<size_t> findVars( VarSet &ns ) const {
164 std::set<size_t> indexes;
165 for( VarSet::const_iterator n = ns.begin(); n != ns.end(); n++ )
166 indexes.insert( findVar( *n ) );
167 return indexes;
168 }
170 /// Returns index of the first factor that depends on the variables
171 size_t findFactor(const VarSet &ns) const {
172 size_t I;
173 for( I = 0; I < nrFactors(); I++ )
174 if( factor(I).vars() == ns )
175 break;
176 assert( I != nrFactors() );
177 return I;
178 }
180 /// Return all variables that occur in a factor involving the i'th variable, itself included
181 VarSet Delta( unsigned i ) const;
183 /// Return all variables that occur in a factor involving some variable in ns, ns itself included
184 VarSet Delta( const VarSet &ns ) const;
186 /// Return all variables that occur in a factor involving the i'th variable, n itself excluded
187 VarSet delta( unsigned i ) const;
189 /// Return all variables that occur in a factor involving some variable in ns, ns itself excluded
190 VarSet delta( const VarSet & ns ) const {
191 return Delta( ns ) / ns;
192 }
194 /// Set the content of the I'th factor and make a backup of its old content if backup == true
195 virtual void setFactor( size_t I, const Factor &newFactor, bool backup = false ) {
196 assert( newFactor.vars() == factor(I).vars() );
197 if( backup )
198 backupFactor( I );
199 _factors[I] = newFactor;
200 }
202 /// Set the contents of all factors as specified by facs and make a backup of the old contents if backup == true
203 virtual void setFactors( const std::map<size_t, Factor> & facs, bool backup = false ) {
204 for( std::map<size_t, Factor>::const_iterator fac = facs.begin(); fac != facs.end(); fac++ ) {
205 if( backup )
206 backupFactor( fac->first );
207 setFactor( fac->first, fac->second );
208 }
209 }
211 /// Clamp variable n to value i (i.e. multiply with a Kronecker delta \f$\delta_{x_n, i}\f$);
212 /// If backup == true, make a backup of all factors that are changed
213 virtual void clamp( const Var & n, size_t i, bool backup = false );
215 /// Set all factors interacting with the i'th variable 1
216 virtual void makeCavity( unsigned i, bool backup = false );
218 /// Backup the factors specified by indices in facs
219 virtual void backupFactors( const std::set<size_t> & facs );
221 /// Restore all factors to the backup copies
222 virtual void restoreFactors();
224 /// Returns true if the FactorGraph is connected
225 bool isConnected() const { return G.isConnected(); }
227 /// Returns true if the FactorGraph is a tree
228 bool isTree() const { return G.isTree(); }
230 /// Returns true if each factor depends on at most two variables
231 bool isPairwise() const;
233 /// Returns true if each variable has only two possible values
234 bool isBinary() const;
236 /// Reads a FactorGraph from a file
239 /// Writes a FactorGraph to a file
240 void WriteToFile(const char *filename) const;
242 /// Writes a FactorGraph to a GraphViz .dot file
243 void printDot( std::ostream& os ) const;
245 /// Returns the cliques in this FactorGraph
246 std::vector<VarSet> Cliques() const;
248 /// Clamp variable v_i to value state (i.e. multiply with a Kronecker delta \f$\delta_{x_{v_i},x}\f$);
249 /** This version changes the factor graph structure and thus returns a newly constructed FactorGraph
250 * and keeps the current one constant, contrary to clamp()
251 */
252 FactorGraph clamped( const Var & v_i, size_t x ) const;
254 /// Returns a copy of *this, where all factors that are subsumed by some larger factor are merged with the larger factors.
255 FactorGraph maximalFactors() const;
257 /// Makes a backup of the I'th Factor
258 void restoreFactor( size_t I );
260 /// Restores the I'th Factor from the backup (it should be backed up first)
261 void backupFactor( size_t I );
263 /// Makes a backup of all factors connected to a set of variables
264 void backupFactors( const VarSet &ns );
265 /// Restores all factors connected to a set of variables from their backups
266 void restoreFactors( const VarSet &ns );
268 // Friends
269 friend std::ostream& operator << (std::ostream& os, const FactorGraph& fg);
270 friend std::istream& operator >> (std::istream& is, FactorGraph& fg);
272 private:
273 /// Part of constructors (creates edges, neighbors and adjacency matrix)
274 void constructGraph( size_t nrEdges );
275 };
278 template<typename FactorInputIterator, typename VarInputIterator>
279 FactorGraph::FactorGraph(FactorInputIterator fact_begin, FactorInputIterator fact_end, VarInputIterator var_begin, VarInputIterator var_end, size_t nr_fact_hint, size_t nr_var_hint ) : G(), _backup() {
281 size_t nrEdges = 0;
282 _factors.reserve( nr_fact_hint );
283 for( FactorInputIterator p2 = fact_begin; p2 != fact_end; ++p2 ) {
284 _factors.push_back( *p2 );
285 nrEdges += p2->vars().size();
286 }