Wrote exceptions, factorgraph unit tests and several other improvements
authorJoris Mooij <joris.mooij@tuebingen.mpg.de>
Tue, 6 Apr 2010 15:37:28 +0000 (17:37 +0200)
committerJoris Mooij <joris.mooij@tuebingen.mpg.de>
Tue, 6 Apr 2010 15:37:28 +0000 (17:37 +0200)
* Wrote exceptions.h/cpp unit tests
* Wrote factorgraph.h/cpp unit tests
* Improved bipgraph.h/cpp:
  - Added BipartiteGraph::operator==( const BipartiteGraph& )
  - Added BipartiteGraph( size_t nr1, size_t nr2 ) constructor
* Improved graph.h/cpp:
  - Added GraphAL::operator==( const GraphAL& )
* Improved smallset.h/cpp:
  - Added SmallSet& insert( const T& t )
* Improved factorgraph.h/factorgraph.cpp:
  - FactorGraph::clamped() now contains a delta factor for the clamped variable
  - Renamed FactorGraph::Cliques() into FactorGraph::maximalFactorDomains()
  - Added FactorGraph::MarkovGraph()
  - Fixed bug in FactorGraph::clone()
  - FactorGraph::findVars( const VarSet& ) now returns a SmallSet<size_t>
    and its argument now has a const-qualifier (which fixes a small bug)
  - Made previously public member G private and added the bipGraph() method,
    which offers read-only access to it

16 files changed:
ChangeLog
Makefile
include/dai/bipgraph.h
include/dai/exceptions.h
include/dai/factorgraph.h
include/dai/graph.h
include/dai/smallset.h
src/factorgraph.cpp
src/hak.cpp
tests/unit/bipgraph.cpp
tests/unit/exceptions.cpp [new file with mode: 0644]
tests/unit/factorgraph.cpp [new file with mode: 0644]
tests/unit/graph.cpp
tests/unit/prob.cpp
tests/unit/smallset.cpp
tests/unit/weightedgraph.cpp

index 9a81f7e..1e3395d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,17 @@
 git HEAD
 --------
 
-TODO:
-* Write unit tests for newly added functions
-
 * Fixed some bugs in the MatLab interface build system
 * Fixed a bug in utils/fginfo.cpp
+* Improved factorgraph.h/factorgraph.cpp:
+  - FactorGraph::clamped() now contains a delta factor for the clamped variable
+  - Renamed FactorGraph::Cliques() into FactorGraph::maximalFactorDomains()
+  - Added FactorGraph::MarkovGraph()
+  - Fixed bug in FactorGraph::clone()
+  - FactorGraph::findVars( const VarSet& ) now returns a SmallSet<size_t>
+    and its argument now has a const-qualifier (which fixes a small bug)
+  - Made previously public member G private and added the bipGraph() method,
+    which offers read-only access to it
 * Improved factor.h/cpp:
   - Fixed bug in min( const TFactor<T> &, const TFactor<T> & )
   - Fixed bug in max( const TFactor<T> &, const TFactor<T> & )
@@ -14,7 +20,7 @@ TODO:
   - Added TFactor<T>::takeLog( bool )
   - Added TFactor<T>::operator-() const
   - Added TFactor<T>::sumAbs() const
-  - Added TFactor<T>::operator=( const TFactor<T> &y )
+  - Added TFactor<T>::operator==( const TFactor<T> &y )
   - Renamed TFactor<T>::states() into TFactor<T>::nrStates()
   - Added get(size_t) and set(size_t,T) operators; get() is 
     equivalent to "operator[](size_t) const" and set() should
@@ -68,6 +74,8 @@ TODO:
   - Added BipartiteGraph::findNb2()
   - BipartiteGraph::delta1() and BipartiteGraph::delta2() now 
     return a SmallSet<size_t> instead of a vector<size_t>
+  - Added BipartiteGraph::operator==( const BipartiteGraph& )
+  - Added BipartiteGraph( size_t nr1, size_t nr2 ) constructor
 * Improved graph.h/cpp:
   - Fixed bug in GraphAL::nrEdges()
   - Fixed bug in GraphAL::addEdge()
@@ -77,16 +85,19 @@ TODO:
   - Fixed bug in createGraphGrid3D()
   - Fixed bug in createGraphRegular()
   - Added GraphAL::hasEdge(size_t,size_t)
+  - Added GraphAL::operator==( const GraphAL& )
 * Improved smallset.h/cpp:
   - The sizeHint argument of the iterator constructor
      SmallSet::SmallSet( TIterator begin, TIterator end, size_t sizeHint=0 )
     no longer has a default value in order to avoid confusion with the
      SmallSet::SmallSet( const T &t1, const T &t2 )
     constructor.
+  - Added SmallSet& insert( const T& t )
 * Removed RandomDRegularGraph(), please use createGraphRegular() instead
 * Compressed Makefile
 * Added unit tests for var, smallset, varset, graph, bipgraph,
-  weightedgraph, enum, util, properties, index, prob, factor
+  weightedgraph, enum, util, exceptions, properties, index, prob, 
+  factor, factorgraph
 * Added unit testing framework
 * Added initialization of TRWBP weights by sampling spanning trees
 * Cleaned up MR code:
index 6e8ad5b..d8e1f69 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -124,7 +124,7 @@ examples : examples/example$(EE) examples/example_bipgraph$(EE) examples/example
 
 matlabs : matlab/dai$(ME) matlab/dai_readfg$(ME) matlab/dai_writefg$(ME) matlab/dai_potstrength$(ME)
 
-unittests : tests/unit/var$(EE) tests/unit/smallset$(EE) tests/unit/varset$(EE) tests/unit/graph$(EE) tests/unit/bipgraph$(EE) tests/unit/weightedgraph$(EE) tests/unit/enum$(EE) tests/unit/enum$(EE) tests/unit/util$(EE) tests/unit/properties$(EE) tests/unit/index$(EE) tests/unit/prob$(EE) tests/unit/factor$(EE)
+unittests : tests/unit/var$(EE) tests/unit/smallset$(EE) tests/unit/varset$(EE) tests/unit/graph$(EE) tests/unit/bipgraph$(EE) tests/unit/weightedgraph$(EE) tests/unit/enum$(EE) tests/unit/enum$(EE) tests/unit/util$(EE) tests/unit/exceptions$(EE) tests/unit/properties$(EE) tests/unit/index$(EE) tests/unit/prob$(EE) tests/unit/factor$(EE) tests/unit/factorgraph$(EE)
        echo Running unit tests...
        tests/unit/var$(EE)
        tests/unit/smallset$(EE)
@@ -134,10 +134,17 @@ unittests : tests/unit/var$(EE) tests/unit/smallset$(EE) tests/unit/varset$(EE)
        tests/unit/weightedgraph$(EE)
        tests/unit/enum$(EE)
        tests/unit/util$(EE)
+       tests/unit/exceptions$(EE)
        tests/unit/properties$(EE)
        tests/unit/index$(EE)
        tests/unit/prob$(EE)
        tests/unit/factor$(EE)
+       tests/unit/factorgraph$(EE)
+ifneq ($(OS),WINDOWS)
+       rm factorgraph_test.fg
+else
+       del factorgraph_test.fg
+endif
 
 tests : tests/testdai$(EE) tests/testem/testem$(EE) tests/testbbp$(EE) $(unittests)
 
@@ -285,7 +292,7 @@ clean :
        -rm matlab/*$(ME)
        -rm examples/example$(EE) examples/example_bipgraph$(EE) examples/example_varset$(EE) examples/example_permute$(EE) examples/example_sprinkler$(EE) examples/example_sprinkler_gibbs$(EE) examples/example_sprinkler_em$(EE)
        -rm tests/testdai$(EE) tests/testem/testem$(EE) tests/testbbp$(EE)
-       -rm tests/unit/var$(EE) tests/unit/smallset$(EE) tests/unit/varset$(EE) tests/unit/graph$(EE) tests/unit/bipgraph$(EE) tests/unit/weightedgraph$(EE) tests/unit/enum$(EE) tests/unit/util$(EE) tests/unit/properties$(EE) tests/unit/index$(EE) tests/unit/prob$(EE) tests/unit/factor$(EE)
+       -rm tests/unit/var$(EE) tests/unit/smallset$(EE) tests/unit/varset$(EE) tests/unit/graph$(EE) tests/unit/bipgraph$(EE) tests/unit/weightedgraph$(EE) tests/unit/enum$(EE) tests/unit/util$(EE) tests/unit/exceptions$(EE) tests/unit/properties$(EE) tests/unit/index$(EE) tests/unit/prob$(EE) tests/unit/factor$(EE) tests/unit/factorgraph$(EE)
        -rm utils/fg2dot$(EE) utils/createfg$(EE) utils/fginfo$(EE)
        -rm -R doc
        -rm -R lib
@@ -324,10 +331,12 @@ clean :
        -del tests\unit\weightedgraph$(EE)
        -del tests\unit\enum$(EE)
        -del tests\unit\util$(EE)
+       -del tests\unit\exceptions$(EE)
        -del tests\unit\properties$(EE)
        -del tests\unit\index$(EE)
        -del tests\unit\prob$(EE)
        -del tests\unit\factor$(EE)
+       -del tests\unit\factorgraph$(EE)
        -del $(LIB)\libdai$(LE)
        -rmdir lib
 endif
index 8ab63e5..47aa8e3 100644 (file)
@@ -146,6 +146,9 @@ class BipartiteGraph {
         /// Default constructor (creates an empty bipartite graph)
         BipartiteGraph() : _nb1(), _nb2() {}
 
+        /// Constructs BipartiteGraph with \a nr1 nodes of type 1, \a nr2 nodes of type 2 and no edges.
+        BipartiteGraph( size_t nr1, size_t nr2 ) : _nb1(nr1), _nb2(nr2) {}
+
         /// Constructs BipartiteGraph from a range of edges.
         /** \tparam EdgeInputIterator Iterator that iterates over instances of BipartiteGraph::Edge.
          *  \param nrNodes1 The number of nodes of type 1.
@@ -311,7 +314,7 @@ class BipartiteGraph {
         /// Returns true if the graph contains an edge between node \a n1 of type 1 and node \a n2 of type 2.
         /** \note The time complexity is linear in the number of neighbors of \a n1 or \a n2
          */
-        bool hasEdge( size_t n1, size_t n2 ) {
+        bool hasEdge( size_t n1, size_t n2 ) const {
             if( nb1(n1).size() < nb2(n2).size() ) {
                 for( size_t _n2 = 0; _n2 < nb1(n1).size(); _n2++ )
                     if( nb1( n1, _n2 ) == n2 )
@@ -366,6 +369,29 @@ class BipartiteGraph {
         /// Returns true if the graph is a tree, i.e., if it is singly connected and connected.
         bool isTree() const;
 
+        /// Comparison operator which returns true if two graphs are identical
+        /** \note Two graphs are called identical if they have the same number of nodes
+         *  of both types and the same edges (i.e., \a x has an edge between nodes
+         *  n1 and n2 if and only if \c *this has an edge between nodes n1 and n2).
+         */
+        bool operator==( const BipartiteGraph& x ) const {
+            if( nrNodes1() != x.nrNodes1() )
+                return false;
+            if( nrNodes2() != x.nrNodes2() )
+                return false;
+            for( size_t n1 = 0; n1 < nrNodes1(); n1++ ) {
+                if( nb1(n1).size() != x.nb1(n1).size() )
+                    return false;
+                foreach( const Neighbor &n2, nb1(n1) )
+                    if( !x.hasEdge( n1, n2 ) )
+                        return false;
+                foreach( const Neighbor &n2, x.nb1(n1) )
+                    if( !hasEdge( n1, n2 ) )
+                        return false;
+            }
+            return true;
+        }
+
         /// Asserts internal consistency
         void checkConsistency() const;
     //@}
index 8e03342..7275569 100644 (file)
@@ -110,7 +110,7 @@ class Exception : public std::runtime_error {
         Code code() const { return errorcode; }
 
         /// Returns error message corresponding to an error code
-        const std::string &message( const Code c ) const { return ErrorStrings[c]; }
+        const std::stringmessage( const Code c ) const { return ErrorStrings[c]; }
 
 
     private:
index a8b07c5..0ee02b3 100644 (file)
@@ -4,7 +4,7 @@
  *  2, or (at your option) any later version. libDAI is distributed without any
  *  warranty. See the file COPYING for more details.
  *
- *  Copyright (C) 2006-2009  Joris Mooij  [joris dot mooij at libdai dot org]
+ *  Copyright (C) 2006-2010  Joris Mooij  [joris dot mooij at libdai dot org]
  *  Copyright (C) 2006-2007  Radboud University Nijmegen, The Netherlands
  */
 
@@ -20,6 +20,7 @@
 #include <iostream>
 #include <map>
 #include <dai/bipgraph.h>
+#include <dai/graph.h>
 #include <dai/factor.h>
 
 
@@ -64,9 +65,6 @@ namespace dai {
  */ 
 class FactorGraph {
     public:
-        /// Stores the neighborhood structure
-        BipartiteGraph                    G;
-
         /// Shorthand for BipartiteGraph::Neighbor
         typedef BipartiteGraph::Neighbor  Neighbor;
 
@@ -82,8 +80,9 @@ class FactorGraph {
         /// Constant iterator over factors
         typedef std::vector<Factor>::const_iterator const_iterator;
 
-
     private:
+        /// Stores the neighborhood structure
+        BipartiteGraph           _G;
         /// Stores the variables
         std::vector<Var>         _vars;
         /// Stores the factors
@@ -95,48 +94,59 @@ class FactorGraph {
     /// \name Constructors and destructors
     //@{
         /// Default constructor
-        FactorGraph() : G(), _vars(), _factors(), _backup() {}
+        FactorGraph() : _G(), _vars(), _factors(), _backup() {}
 
         /// Constructs a factor graph from a vector of factors
-        FactorGraph( const std::vector<Factor> &P );
+        FactorGraph( const std::vector<Factor>P );
 
         /// Constructs a factor graph from given factor and variable iterators
         /** \tparam FactorInputIterator Iterates over instances of type dai::Factor
          *  \tparam VarInputIterator Iterates over instances of type Var
-         *  \pre Assumes that the set of variables in [\a var_begin, \a var_end) is the union of the variables in the factors in [\a fact_begin, \a fact_end)
+         *  \pre Assumes that the set of variables in [\a varBegin, \a varEnd) is the union of the variables in the factors in [\a facBegin, \a facEnd)
          */
         template<typename FactorInputIterator, typename VarInputIterator>
-        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 );
+        FactorGraph(FactorInputIterator facBegin, FactorInputIterator facEnd, VarInputIterator varBegin, VarInputIterator varEnd, size_t nrFacHint = 0, size_t nrVarHint = 0 );
 
         /// Destructor
         virtual ~FactorGraph() {}
 
         /// Virtual copy constructor
-        virtual FactorGraph* clone() const { return new FactorGraph(); }
+        virtual FactorGraph* clone() const { return new FactorGraph(*this); }
     //@}
 
     /// \name Accessors and mutators
     //@{ 
         /// Returns constant reference the \a i 'th variable
-        const Var & var(size_t i) const { return _vars[i]; }
+        const Var& var( size_t i ) const { 
+            DAI_DEBASSERT( i < nrVars() );
+            return _vars[i]; 
+        }
+
         /// Returns constant reference to all variables
-        const std::vector<Var> & vars() const { return _vars; }
+        const std::vector<Var>& vars() const { return _vars; }
 
         /// Returns reference to \a I 'th factor
-        Factor & factor(size_t I) { return _factors[I]; }
+        Factor& factor( size_t I ) { 
+            DAI_DEBASSERT( I < nrFactors() );
+            return _factors[I]; 
+        }
+
         /// Returns constant reference to \a I 'th factor
-        const Factor & factor(size_t I) const { return _factors[I]; }
+        const Factor& factor( size_t I ) const { 
+            DAI_DEBASSERT( I < nrFactors() );
+            return _factors[I]; 
+        }
         /// Returns constant reference to all factors
-        const std::vector<Factor> & factors() const { return _factors; }
+        const std::vector<Factor>& factors() const { return _factors; }
 
         /// Returns constant reference to neighbors of the \a i 'th variable
-        const Neighbors & nbV( size_t i ) const { return G.nb1(i); }
+        const Neighbors& nbV( size_t i ) const { return _G.nb1(i); }
         /// Returns constant reference to neighbors of the \a I 'th factor
-        const Neighbors & nbF( size_t I ) const { return G.nb2(I); }
+        const Neighbors& nbF( size_t I ) const { return _G.nb2(I); }
         /// Returns constant reference to the \a _I 'th neighbor of the \a i 'th variable
-        const Neighbor & nbV( size_t i, size_t _I ) const { return G.nb1(i)[_I]; }
+        const Neighbor& nbV( size_t i, size_t _I ) const { return _G.nb1(i)[_I]; }
         /// Returns constant reference to the \a _i 'th neighbor of the \a I 'th factor
-        const Neighbor & nbF( size_t I, size_t _i ) const { return G.nb2(I)[_i]; }
+        const Neighbor& nbF( size_t I, size_t _i ) const { return _G.nb2(I)[_i]; }
     //@}
 
     /// \name Iterator interface
@@ -153,6 +163,8 @@ class FactorGraph {
 
     /// \name Queries
     //@{
+        /// Returns neighborhood structure
+        const BipartiteGraph& bipGraph() const { return _G; }
         /// Returns number of variables
         size_t nrVars() const { return vars().size(); }
         /// Returns number of factors
@@ -160,13 +172,13 @@ class FactorGraph {
         /// Calculates number of edges
         /** \note Time complexity: O(nrVars())
          */
-        size_t nrEdges() const { return G.nrEdges(); }
+        size_t nrEdges() const { return _G.nrEdges(); }
 
         /// Returns the index of a particular variable
         /** \note Time complexity: O(nrVars())
          *  \throw OBJECT_NOT_FOUND if the variable is not part of this factor graph
          */
-        size_t findVar( const Var &n ) const {
+        size_t findVar( const Varn ) const {
             size_t i = find( vars().begin(), vars().end(), n ) - vars().begin();
             if( i == nrVars() )
                 DAI_THROW(OBJECT_NOT_FOUND);
@@ -177,18 +189,18 @@ class FactorGraph {
         /** \note Time complexity: O( nrVars() * ns.size() )
          *  \throw OBJECT_NOT_FOUND if one of the variables is not part of this factor graph
          */
-        std::set<size_t> findVars( VarSet &ns ) const {
-            std::set<size_t> indexes;
+        SmallSet<size_t> findVars( const VarSet& ns ) const {
+            SmallSet<size_t> result;
             for( VarSet::const_iterator n = ns.begin(); n != ns.end(); n++ )
-                indexes.insert( findVar( *n ) );
-            return indexes;
+                result.insert( findVar( *n ) );
+            return result;
         }
 
         /// Returns index of the first factor that depends on the variables
         /** \note Time complexity: O(nrFactors())
          *  \throw OBJECT_NOT_FOUND if no factor in this factor graph depends on those variables
          */
-        size_t findFactor( const VarSet &ns ) const {
+        size_t findFactor( const VarSetns ) const {
             size_t I;
             for( I = 0; I < nrFactors(); I++ )
                 if( factor(I).vars() == ns )
@@ -202,21 +214,23 @@ class FactorGraph {
         VarSet Delta( size_t i ) const;
 
         /// Return all variables that occur in a factor involving some variable in \a vs, \a vs itself included
-        VarSet Delta( const VarSet &vs ) const;
+        VarSet Delta( const VarSetvs ) const;
 
         /// Return all variables that occur in a factor involving the \a i 'th variable, itself excluded
-        VarSet delta( size_t i ) const;
+        VarSet delta( size_t i ) const {
+            return( Delta( i ) / var( i ) );
+        }
 
         /// Return all variables that occur in a factor involving some variable in \a vs, \a vs itself excluded
-        VarSet delta( const VarSet &vs ) const {
+        VarSet delta( const VarSetvs ) const {
             return Delta( vs ) / vs;
         }
 
         /// Returns \c true if the factor graph is connected
-        bool isConnected() const { return G.isConnected(); }
+        bool isConnected() const { return _G.isConnected(); }
 
         /// Returns \c true if the factor graph is a tree (i.e., has no cycles and is connected)
-        bool isTree() const { return G.isTree(); }
+        bool isTree() const { return _G.isTree(); }
 
         /// Returns \c true if each factor depends on at most two variables
         bool isPairwise() const;
@@ -224,14 +238,30 @@ class FactorGraph {
         /// Returns \c true if each variable has only two possible values
         bool isBinary() const;
 
-        /// Returns the cliques (fully connected subgraphs of the corresponding Markov graph) in this factor graph
-        std::vector<VarSet> Cliques() const;
+        /// Constructs the corresponding Markov graph 
+        /** \note The Markov graph has the variables as nodes and an edge
+         *  between two variables if and only if the variables share a factor.
+         */
+        GraphAL MarkovGraph() const;
+
+        /// Returns the maximal factor domains in this factorgraph
+        /** \note A factor domain is \a maximal if and only if it is not a
+         *  strict subset of another factor domain.
+         */
+        std::vector<VarSet> maximalFactorDomains() const;
+
+        /// Returns the maximal factors domains in this factorgraph
+        /** \deprecated Please use dai::FactorGraph::maximalFactorDomains() instead
+         */
+        std::vector<VarSet> cliques() const {
+            return maximalFactorDomains();
+        }
     //@}
 
     /// \name Backup/restore mechanism for factors
     //@{
         /// Set the content of the \a I 'th factor and make a backup of its old content if \a backup == \c true
-        virtual void setFactor( size_t I, const Factor &newFactor, bool backup = false ) {
+        virtual void setFactor( size_t I, const FactornewFactor, bool backup = false ) {
             DAI_ASSERT( newFactor.vars() == factor(I).vars() );
             if( backup )
                 backupFactor( I );
@@ -239,7 +269,7 @@ class FactorGraph {
         }
 
         /// Set the contents of all factors as specified by \a facs and make a backup of the old contents if \a backup == \c true
-        virtual void setFactors( const std::map<size_t, Factor> & facs, bool backup = false ) {
+        virtual void setFactors( const std::map<size_t, Factor>& facs, bool backup = false ) {
             for( std::map<size_t, Factor>::const_iterator fac = facs.begin(); fac != facs.end(); fac++ ) {
                 if( backup )
                     backupFactor( fac->first );
@@ -253,12 +283,14 @@ class FactorGraph {
         void backupFactor( size_t I );
 
         /// Restores the \a I 'th factor from the backup (it should be backed up first)
+        /** \throw OBJECT_NOT_FOUND if a backup does not exist
+         */
         void restoreFactor( size_t I );
 
         /// Backup the factors specified by indices in \a facs
         /** \throw MULTIPLE_UNDO if a backup already exists
          */
-        virtual void backupFactors( const std::set<size_t> & facs );
+        virtual void backupFactors( const std::set<size_t>& facs );
 
         /// Restore all factors to the backup copies
         virtual void restoreFactors();
@@ -266,10 +298,10 @@ class FactorGraph {
         /// Makes a backup of all factors connected to a set of variables
         /** \throw MULTIPLE_UNDO if a backup already exists
          */
-        void backupFactors( const VarSet &ns );
+        void backupFactors( const VarSetns );
 
         /// Restores all factors connected to a set of variables from their backups
-        void restoreFactors( const VarSet &ns );
+        void restoreFactors( const VarSetns );
     //@}
 
     /// \name Transformations
@@ -277,7 +309,7 @@ class FactorGraph {
         /// Returns a copy of \c *this, where all factors that are subsumed by some larger factor are merged with the larger factors.
         FactorGraph maximalFactors() const;
 
-        /// Clamp the \a i 'th variable to value \a x (i.e. multiply with a Kronecker delta \f$\delta_{x_i,x}\f$);
+        /// Returns a copy of \c *this, where the \a i 'th variable has been clamped to value \a x
         /** \note This version changes the factor graph structure and thus returns a newly constructed FactorGraph
          *  and keeps the current one constant, contrary to clamp()
          */
@@ -294,12 +326,12 @@ class FactorGraph {
         /// Clamp a variable in a factor graph to have one out of a list of values
         /** If \a backup == \c true, make a backup of all factors that are changed
          */
-        void clampVar( size_t i, const std::vector<size_t> &xis, bool backup = false );
+        void clampVar( size_t i, const std::vector<size_t>xis, bool backup = false );
 
         /// Clamp a factor in a factor graph to have one out of a list of values
         /** If \a backup == \c true, make a backup of all factors that are changed
          */
-        void clampFactor( size_t I, const std::vector<size_t> &xIs, bool backup = false );
+        void clampFactor( size_t I, const std::vector<size_t>xIs, bool backup = false );
 
         /// Set all factors interacting with the \a i 'th variable to 1
         /** If \a backup == \c true, make a backup of all factors that are changed
@@ -325,13 +357,13 @@ class FactorGraph {
         /// Writes a factor graph to an output stream
         /** \see \ref fileformats-factorgraph
          */
-        friend std::ostream& operator<< (std::ostream &os, const FactorGraph &fg );
+        friend std::ostream& operator<< (std::ostream& os, const FactorGraph& fg );
 
         /// Reads a factor graph from an input stream
         /** \see \ref fileformats-factorgraph
          *  \throw INVALID_FACTORGRAPH_FILE if the input stream is not valid
          */
-        friend std::istream& operator>> (std::istream &is, FactorGraph &fg );
+        friend std::istream& operator>> (std::istream& is, FactorGraph& fg );
 
         /// Writes a factor graph to a GraphViz .dot file
         void printDot( std::ostream& os ) const;
@@ -344,18 +376,18 @@ class FactorGraph {
 
 
 template<typename FactorInputIterator, typename VarInputIterator>
-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() {
+FactorGraph::FactorGraph(FactorInputIterator facBegin, FactorInputIterator facEnd, VarInputIterator varBegin, VarInputIterator varEnd, size_t nrFacHint, size_t nrVarHint ) : _G(), _backup() {
     // add factors
     size_t nrEdges = 0;
-    _factors.reserve( nr_fact_hint );
-    for( FactorInputIterator p2 = fact_begin; p2 != fact_end; ++p2 ) {
+    _factors.reserve( nrFacHint );
+    for( FactorInputIterator p2 = facBegin; p2 != facEnd; ++p2 ) {
         _factors.push_back( *p2 );
         nrEdges += p2->vars().size();
     }
 
     // add variables
-    _vars.reserve( nr_var_hint );
-    for( VarInputIterator p1 = var_begin; p1 != var_end; ++p1 )
+    _vars.reserve( nrVarHint );
+    for( VarInputIterator p1 = varBegin; p1 != varEnd; ++p1 )
         _vars.push_back( *p1 );
 
     // create graph structure
index 02da765..cd6dd4d 100644 (file)
@@ -235,7 +235,7 @@ class GraphAL {
         /// Returns true if the graph contains an edge between nodes \a n1 and \a n2
         /** \note The time complexity is linear in the number of neighbors of \a n1 or \a n2
          */
-        bool hasEdge( size_t n1, size_t n2 ) {
+        bool hasEdge( size_t n1, size_t n2 ) const {
             if( nb(n1).size() < nb(n2).size() ) {
                 for( size_t _n2 = 0; _n2 < nb(n1).size(); _n2++ )
                     if( nb( n1, _n2 ) == n2 )
@@ -268,6 +268,27 @@ class GraphAL {
 
         /// Asserts internal consistency
         void checkConsistency() const;
+
+        /// Comparison operator which returns true if two graphs are identical
+        /** \note Two graphs are called identical if they have the same number 
+         *  of nodes and the same edges (i.e., \a x has an edge between nodes
+         *  n1 and n2 if and only if \c *this has an edge between nodes n1 and n2).
+         */
+        bool operator==( const GraphAL& x ) const {
+            if( nrNodes() != x.nrNodes() )
+                return false;
+            for( size_t n1 = 0; n1 < nrNodes(); n1++ ) {
+                if( nb(n1).size() != x.nb(n1).size() )
+                    return false;
+                foreach( const Neighbor &n2, nb(n1) )
+                    if( !x.hasEdge( n1, n2 ) )
+                        return false;
+                foreach( const Neighbor &n2, x.nb(n1) )
+                    if( !hasEdge( n1, n2 ) )
+                        return false;
+            }
+            return true;
+        }
     //@}
 
     /// \name Input and output
index d00ec2e..506120d 100644 (file)
@@ -79,6 +79,14 @@ class SmallSet {
 
     /// \name Operators for set-theoretic operations
     //@{
+        /// Inserts \a t into \c *this
+        SmallSet& insert( const T& t ) {
+            SmallSet::iterator it = std::lower_bound( _elements.begin(), _elements.end(), t );
+            if( (it == _elements.end()) || (*it != t) )
+                _elements.insert( it, t );
+            return *this;
+        }
+
         /// Set-minus operator: returns all elements in \c *this, except those in \a x
         SmallSet operator/ ( const SmallSet& x ) const {
             SmallSet res;
index b21d7b2..cc25844 100644 (file)
@@ -30,7 +30,7 @@ namespace dai {
 using namespace std;
 
 
-FactorGraph::FactorGraph( const std::vector<Factor> &P ) : G(), _backup() {
+FactorGraph::FactorGraph( const std::vector<Factor> &P ) : _G(), _backup() {
     // add factors, obtain variables
     set<Var> varset;
     _factors.reserve( P.size() );
@@ -68,7 +68,7 @@ void FactorGraph::constructGraph( size_t nrEdges ) {
     }
 
     // create bipartite graph
-    G.construct( nrVars(), nrFactors(), edges.begin(), edges.end() );
+    _G.construct( nrVars(), nrFactors(), edges.begin(), edges.end() );
 }
 
 
@@ -201,11 +201,6 @@ std::istream& operator>> ( std::istream& is, FactorGraph &fg ) {
 }
 
 
-VarSet FactorGraph::delta( size_t i ) const {
-    return( Delta(i) / var(i) );
-}
-
-
 VarSet FactorGraph::Delta( size_t i ) const {
     // calculate Markov Blanket
     VarSet Del;
@@ -220,7 +215,7 @@ VarSet FactorGraph::Delta( size_t i ) const {
 VarSet FactorGraph::Delta( const VarSet &ns ) const {
     VarSet result;
     for( VarSet::const_iterator n = ns.begin(); n != ns.end(); n++ )
-        result |= Delta(findVar(*n));
+        result |= Delta( findVar(*n) );
     return result;
 }
 
@@ -272,7 +267,18 @@ void FactorGraph::printDot( std::ostream &os ) const {
 }
 
 
-vector<VarSet> FactorGraph::Cliques() const {
+GraphAL FactorGraph::MarkovGraph() const {
+    GraphAL G( nrVars() );
+    for( size_t i = 0; i < nrVars(); i++ )
+        foreach( const Neighbor &I, nbV(i) )
+            foreach( const Neighbor &j, nbF(I) )
+                if( i < j )
+                    G.addEdge( i, j );
+    return G;
+}
+
+
+vector<VarSet> FactorGraph::maximalFactorDomains() const {
     vector<VarSet> result;
 
     for( size_t I = 0; I < nrFactors(); I++ ) {
@@ -345,7 +351,8 @@ void FactorGraph::restoreFactor( size_t I ) {
     if( it != _backup.end() ) {
         setFactor(I, it->second);
         _backup.erase(it);
-    }
+    } else
+        DAI_THROW(OBJECT_NOT_FOUND);
 }
 
 
@@ -403,6 +410,7 @@ FactorGraph FactorGraph::clamped( size_t i, size_t state ) const {
     Var v = var( i );
     Real zeroth_order = (Real)1;
     vector<Factor> clamped_facs;
+    clamped_facs.push_back( createFactorDelta( v, state ) );
     for( size_t I = 0; I < nrFactors(); I++ ) {
         VarSet v_I = factor(I).vars();
         Factor new_factor;
index db8b7da..285fb51 100644 (file)
@@ -154,7 +154,7 @@ HAK::HAK(const FactorGraph & fg, const PropertySet &opts) : DAIAlgRG(), _Qa(), _
 
     vector<VarSet> cl;
     if( props.clusters == Properties::ClustersType::MIN ) {
-        cl = fg.Cliques();
+        cl = fg.maximalFactorDomains();
         constructCVM( fg, cl );
     } else if( props.clusters == Properties::ClustersType::DELTA ) {
         cl.reserve( fg.nrVars() );
@@ -162,7 +162,7 @@ HAK::HAK(const FactorGraph & fg, const PropertySet &opts) : DAIAlgRG(), _Qa(), _
             cl.push_back( fg.Delta(i) );
         constructCVM( fg, cl );
     } else if( props.clusters == Properties::ClustersType::LOOP ) {
-        cl = fg.Cliques();
+        cl = fg.maximalFactorDomains();
         set<VarSet> scl;
         for( size_t i0 = 0; i0 < fg.nrVars(); i0++ ) {
             VarSet i0d = fg.delta(i0);
@@ -178,8 +178,8 @@ HAK::HAK(const FactorGraph & fg, const PropertySet &opts) : DAIAlgRG(), _Qa(), _
         }
         constructCVM( fg, cl );
     } else if( props.clusters == Properties::ClustersType::BETHE ) {
-        // build outer regions (the cliques)
-        cl = fg.Cliques();
+        // build outer regions (the maximal factor domains)
+        cl = fg.maximalFactorDomains();
         size_t nrEdges = 0;
         for( size_t c = 0; c < cl.size(); c++ )
             nrEdges += cl[c].size();
index 2456ad4..2cd2fc6 100644 (file)
@@ -37,6 +37,15 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK( G.isTree() );
     G.checkConsistency();
 
+    BipartiteGraph G1( 2, 3 );
+    BOOST_CHECK_EQUAL( G1.nrNodes1(), 2 );
+    BOOST_CHECK_EQUAL( G1.nrNodes2(), 3 );
+    BOOST_CHECK_EQUAL( G1.nrEdges(), 0 );
+    BOOST_CHECK( !G1.isConnected() );
+    BOOST_CHECK( !G1.isTree() );
+    BOOST_CHECK( !(G1 == G) );
+    G1.checkConsistency();
+
     std::vector<Edge> edges;
     edges.push_back( Edge(0, 0) );
     edges.push_back( Edge(0, 1) );
@@ -49,6 +58,8 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK_EQUAL( G2.nrEdges(), 4 );
     BOOST_CHECK( G2.isConnected() );
     BOOST_CHECK( G2.isTree() );
+    BOOST_CHECK( !(G2 == G) );
+    BOOST_CHECK( !(G2 == G1) );
     G2.checkConsistency();
 
     edges.push_back( Edge(1, 0) );
@@ -58,6 +69,9 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK_EQUAL( G3.nrEdges(), 5 );
     BOOST_CHECK( G3.isConnected() );
     BOOST_CHECK( !G3.isTree() );
+    BOOST_CHECK( !(G3 == G) );
+    BOOST_CHECK( !(G3 == G1) );
+    BOOST_CHECK( !(G3 == G2) );
     G3.checkConsistency();
 
     BipartiteGraph G4( 3, 3, edges.begin(), edges.end() );
@@ -66,6 +80,10 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK_EQUAL( G4.nrEdges(), 5 );
     BOOST_CHECK( !G4.isConnected() );
     BOOST_CHECK( !G4.isTree() );
+    BOOST_CHECK( !(G4 == G) );
+    BOOST_CHECK( !(G4 == G1) );
+    BOOST_CHECK( !(G4 == G2) );
+    BOOST_CHECK( !(G4 == G3) );
     G4.checkConsistency();
 
     G.construct( 3, 3, edges.begin(), edges.end() );
@@ -74,7 +92,17 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK_EQUAL( G.nrEdges(), 5 );
     BOOST_CHECK( !G.isConnected() );
     BOOST_CHECK( !G.isTree() );
+    BOOST_CHECK( !(G == G1) );
+    BOOST_CHECK( !(G == G2) );
+    BOOST_CHECK( !(G == G3) );
+    BOOST_CHECK( G == G4 );
     G.checkConsistency();
+    
+    BipartiteGraph G5( G4 );
+    BOOST_CHECK( G5 == G4 );
+
+    BipartiteGraph G6 = G4;
+    BOOST_CHECK( G6 == G4 );
 }
 
 
diff --git a/tests/unit/exceptions.cpp b/tests/unit/exceptions.cpp
new file mode 100644 (file)
index 0000000..fa10674
--- /dev/null
@@ -0,0 +1,60 @@
+/*  This file is part of libDAI - http://www.libdai.org/
+ *
+ *  libDAI is licensed under the terms of the GNU General Public License version
+ *  2, or (at your option) any later version. libDAI is distributed without any
+ *  warranty. See the file COPYING for more details.
+ *
+ *  Copyright (C) 2010  Joris Mooij      [joris dot mooij at libdai dot org]
+ */
+
+
+#define BOOST_TEST_DYN_LINK
+
+
+#include <dai/exceptions.h>
+#include <strstream>
+
+
+using namespace dai;
+
+
+#define BOOST_TEST_MODULE ExceptionsTest
+
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_AUTO_TEST_CASE( ExceptionsTest ) {
+    BOOST_CHECK_THROW( DAI_THROW(NOT_IMPLEMENTED), Exception );
+    BOOST_CHECK_THROW( DAI_THROW(NOT_IMPLEMENTED), std::runtime_error );
+    BOOST_CHECK_THROW( DAI_THROWE(NOT_IMPLEMENTED,"Detailed error message"), Exception );
+    BOOST_CHECK_THROW( DAI_THROWE(NOT_IMPLEMENTED,"Detailed error messgae"), std::runtime_error );
+    BOOST_CHECK_THROW( DAI_ASSERT( 0 ), Exception );
+    BOOST_CHECK_THROW( DAI_ASSERT( 0 == 1 ), std::runtime_error );
+
+    try {
+        DAI_THROW(NOT_IMPLEMENTED);
+    } catch( Exception& e ) {
+        BOOST_CHECK_EQUAL( e.code(), Exception::NOT_IMPLEMENTED );
+        BOOST_CHECK_EQUAL( e.message(e.code()), std::string("Feature not implemented") );
+    }
+
+    try {
+        DAI_THROWE(NOT_IMPLEMENTED,"Detailed error message");
+    } catch( Exception& e ) {
+        BOOST_CHECK_EQUAL( e.code(), Exception::NOT_IMPLEMENTED );
+        BOOST_CHECK_EQUAL( e.message(e.code()), std::string("Feature not implemented") );
+    }
+
+    try {
+        DAI_THROW(NOT_IMPLEMENTED);
+    } catch( std::runtime_error& e ) {
+        BOOST_CHECK_EQUAL( e.what(), std::string("Feature not implemented [tests/unit/exceptions.cpp, line 50]") );
+    }
+
+    try {
+        DAI_THROWE(NOT_IMPLEMENTED,"Detailed error message");
+    } catch( std::runtime_error& e ) {
+        BOOST_CHECK_EQUAL( e.what(), std::string("Feature not implemented [tests/unit/exceptions.cpp, line 56]") );
+    }
+}
diff --git a/tests/unit/factorgraph.cpp b/tests/unit/factorgraph.cpp
new file mode 100644 (file)
index 0000000..497ca71
--- /dev/null
@@ -0,0 +1,735 @@
+/*  This file is part of libDAI - http://www.libdai.org/
+ *
+ *  libDAI is licensed under the terms of the GNU General Public License version
+ *  2, or (at your option) any later version. libDAI is distributed without any
+ *  warranty. See the file COPYING for more details.
+ *
+ *  Copyright (C) 2010  Joris Mooij      [joris dot mooij at libdai dot org]
+ */
+
+
+#define BOOST_TEST_DYN_LINK
+
+
+#include <dai/bipgraph.h>
+#include <dai/factorgraph.h>
+#include <vector>
+#include <strstream>
+
+
+using namespace dai;
+
+
+const double tol = 1e-8;
+
+
+#define BOOST_TEST_MODULE FactorGraphTest
+
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+
+BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
+    FactorGraph G;
+    BOOST_CHECK_EQUAL( G.vars(), std::vector<Var>() );
+    BOOST_CHECK_EQUAL( G.factors(), std::vector<Factor>() );
+
+    std::vector<Factor> facs;
+    facs.push_back( Factor( VarSet( Var(0, 2), Var(1, 2) ) ) );
+    facs.push_back( Factor( VarSet( Var(0, 2), Var(2, 2) ) ) );
+    facs.push_back( Factor( VarSet( Var(1, 2), Var(2, 2) ) ) );
+    facs.push_back( Factor( VarSet( Var(1, 2) ) ) );
+    std::vector<Var> vars;
+    vars.push_back( Var( 0, 2 ) );
+    vars.push_back( Var( 1, 2 ) );
+    vars.push_back( Var( 2, 2 ) );
+
+    FactorGraph G1( facs );
+    BOOST_CHECK_EQUAL( G1.vars(), vars );
+    BOOST_CHECK_EQUAL( G1.factors(), facs );
+
+    FactorGraph G2( facs.begin(), facs.end(), vars.begin(), vars.end(), facs.size(), vars.size() ); 
+    BOOST_CHECK_EQUAL( G2.vars(), vars );
+    BOOST_CHECK_EQUAL( G2.factors(), facs );
+
+    FactorGraph *G3 = G2.clone();
+    BOOST_CHECK_EQUAL( G3->vars(), vars );
+    BOOST_CHECK_EQUAL( G3->factors(), facs );
+    delete G3;
+
+    FactorGraph G4 = G2;
+    BOOST_CHECK_EQUAL( G4.vars(), vars );
+    BOOST_CHECK_EQUAL( G4.factors(), facs );
+
+    FactorGraph G5( G2 );
+    BOOST_CHECK_EQUAL( G5.vars(), vars );
+    BOOST_CHECK_EQUAL( G5.factors(), facs );
+}
+
+
+BOOST_AUTO_TEST_CASE( AccMutIterTest ) {
+    std::vector<Factor> facs;
+    facs.push_back( Factor( VarSet( Var(0, 2), Var(1, 2) ) ) );
+    facs.push_back( Factor( VarSet( Var(0, 2), Var(2, 2) ) ) );
+    facs.push_back( Factor( VarSet( Var(1, 2), Var(2, 2) ) ) );
+    facs.push_back( Factor( VarSet( Var(1, 2) ) ) );
+    std::vector<Var> vars;
+    vars.push_back( Var( 0, 2 ) );
+    vars.push_back( Var( 1, 2 ) );
+    vars.push_back( Var( 2, 2 ) );
+
+    FactorGraph G( facs );
+    BOOST_CHECK_EQUAL( G.var(0), Var(0, 2) );
+    BOOST_CHECK_EQUAL( G.var(1), Var(1, 2) );
+    BOOST_CHECK_EQUAL( G.var(2), Var(2, 2) );
+    BOOST_CHECK_EQUAL( G.vars(), vars );
+    BOOST_CHECK_EQUAL( G.factor(0), facs[0] );
+    BOOST_CHECK_EQUAL( G.factor(1), facs[1] );
+    BOOST_CHECK_EQUAL( G.factor(2), facs[2] );
+    BOOST_CHECK_EQUAL( G.factor(3), facs[3] );
+    BOOST_CHECK_EQUAL( G.factors(), facs );
+    BOOST_CHECK_EQUAL( G.nbV(0).size(), 2 );
+    BOOST_CHECK_EQUAL( G.nbV(0,0), 0 );
+    BOOST_CHECK_EQUAL( G.nbV(0,1), 1 );
+    BOOST_CHECK_EQUAL( G.nbV(1).size(), 3 );
+    BOOST_CHECK_EQUAL( G.nbV(1,0), 0 );
+    BOOST_CHECK_EQUAL( G.nbV(1,1), 2 );
+    BOOST_CHECK_EQUAL( G.nbV(1,2), 3 );
+    BOOST_CHECK_EQUAL( G.nbV(0).size(), 2 );
+    BOOST_CHECK_EQUAL( G.nbV(2,0), 1 );
+    BOOST_CHECK_EQUAL( G.nbV(2,1), 2 );
+    BOOST_CHECK_EQUAL( G.nbF(0).size(), 2 );
+    BOOST_CHECK_EQUAL( G.nbF(0,0), 0 );
+    BOOST_CHECK_EQUAL( G.nbF(0,1), 1 );
+    BOOST_CHECK_EQUAL( G.nbF(1).size(), 2 );
+    BOOST_CHECK_EQUAL( G.nbF(1,0), 0 );
+    BOOST_CHECK_EQUAL( G.nbF(1,1), 2 );
+    BOOST_CHECK_EQUAL( G.nbF(2).size(), 2 );
+    BOOST_CHECK_EQUAL( G.nbF(2,0), 1 );
+    BOOST_CHECK_EQUAL( G.nbF(2,1), 2 );
+    BOOST_CHECK_EQUAL( G.nbF(3).size(), 1 );
+    BOOST_CHECK_EQUAL( G.nbF(3,0), 1 );
+
+    FactorGraph::const_iterator cit = G.begin();
+    FactorGraph::iterator it = G.begin();
+    for( size_t I = 0; I < G.nrFactors(); I++, cit++, it++ ) {
+        BOOST_CHECK_EQUAL( *cit, G.factor(I) );
+        BOOST_CHECK_EQUAL( *it, G.factor(I) );
+    }
+    BOOST_CHECK( cit == G.end() );
+    BOOST_CHECK( it == G.end() );
+}
+
+
+BOOST_AUTO_TEST_CASE( QueriesTest ) {
+    Var v0( 0, 2 );
+    Var v1( 1, 2 );
+    Var v2( 2, 2 );
+    VarSet v01( v0, v1 );
+    VarSet v02( v0, v2 );
+    VarSet v12( v1, v2 );
+    VarSet v012 = v01 | v2;
+
+    FactorGraph G0;
+    BOOST_CHECK_EQUAL( G0.nrVars(), 0 );
+    BOOST_CHECK_EQUAL( G0.nrFactors(), 0 );
+    BOOST_CHECK_EQUAL( G0.nrEdges(), 0 );
+    BOOST_CHECK_THROW( G0.findVar( v0 ), Exception );
+    BOOST_CHECK_THROW( G0.findVars( v01 ), Exception );
+    BOOST_CHECK_THROW( G0.findFactor( v01 ), Exception );
+#ifdef DAI_DBEUG
+    BOOST_CHECK_THROW( G0.delta( 0 ), Exception );
+    BOOST_CHECK_THROW( G0.Delta( 0 ), Exception );
+    BOOST_CHECK_THROW( G0.delta( v0 ), Exception );
+    BOOST_CHECK_THROW( G0.Delta( v0 ), Exception );
+#endif
+    BOOST_CHECK( G0.isConnected() );
+    BOOST_CHECK( G0.isTree() );
+    BOOST_CHECK( G0.isBinary() );
+    BOOST_CHECK( G0.isPairwise() );
+    BOOST_CHECK( G0.MarkovGraph() == GraphAL() );
+    BOOST_CHECK( G0.bipGraph() == BipartiteGraph() );
+    BOOST_CHECK_EQUAL( G0.maximalFactorDomains().size(), 0 );
+
+    std::vector<Factor> facs;
+    facs.push_back( Factor( v01 ) );
+    facs.push_back( Factor( v12 ) );
+    facs.push_back( Factor( v1 ) );
+    std::vector<Var> vars;
+    vars.push_back( v0 );
+    vars.push_back( v1 );
+    vars.push_back( v2 );
+    GraphAL H(3);
+    H.addEdge( 0, 1 );
+    H.addEdge( 1, 2 );
+    BipartiteGraph K(3, 3);
+    K.addEdge( 0, 0 );
+    K.addEdge( 1, 0 );
+    K.addEdge( 1, 1 );
+    K.addEdge( 2, 1 );
+    K.addEdge( 1, 2 );
+
+    FactorGraph G1( facs );
+    BOOST_CHECK_EQUAL( G1.nrVars(), 3 );
+    BOOST_CHECK_EQUAL( G1.nrFactors(), 3 );
+    BOOST_CHECK_EQUAL( G1.nrEdges(), 5 );
+    BOOST_CHECK_EQUAL( G1.findVar( v0 ), 0 );
+    BOOST_CHECK_EQUAL( G1.findVar( v1 ), 1 );
+    BOOST_CHECK_EQUAL( G1.findVar( v2 ), 2 );
+    BOOST_CHECK_EQUAL( G1.findVars( v01 ), SmallSet<size_t>( 0, 1 ) );
+    BOOST_CHECK_EQUAL( G1.findVars( v02 ), SmallSet<size_t>( 0, 2 ) );
+    BOOST_CHECK_EQUAL( G1.findVars( v12 ), SmallSet<size_t>( 1, 2 ) );
+    BOOST_CHECK_EQUAL( G1.findFactor( v01 ), 0 );
+    BOOST_CHECK_EQUAL( G1.findFactor( v12 ), 1 );
+    BOOST_CHECK_EQUAL( G1.findFactor( v1 ), 2 );
+    BOOST_CHECK_THROW( G1.findFactor( v02 ), Exception );
+    BOOST_CHECK_EQUAL( G1.delta( 0 ), v1 );
+    BOOST_CHECK_EQUAL( G1.delta( 1 ), v02 );
+    BOOST_CHECK_EQUAL( G1.delta( 2 ), v1 );
+    BOOST_CHECK_EQUAL( G1.Delta( 0 ), v01 );
+    BOOST_CHECK_EQUAL( G1.Delta( 1 ), v012 );
+    BOOST_CHECK_EQUAL( G1.Delta( 2 ), v12 );
+    BOOST_CHECK_EQUAL( G1.delta( v0 ), v1 );
+    BOOST_CHECK_EQUAL( G1.delta( v1 ), v02 );
+    BOOST_CHECK_EQUAL( G1.delta( v2 ), v1 );
+    BOOST_CHECK_EQUAL( G1.delta( v01 ), v2 );
+    BOOST_CHECK_EQUAL( G1.delta( v02 ), v1 );
+    BOOST_CHECK_EQUAL( G1.delta( v12 ), v0 );
+    BOOST_CHECK_EQUAL( G1.delta( v012 ), VarSet() );
+    BOOST_CHECK_EQUAL( G1.Delta( v0 ), v01 );
+    BOOST_CHECK_EQUAL( G1.Delta( v1 ), v012 );
+    BOOST_CHECK_EQUAL( G1.Delta( v2 ), v12 );
+    BOOST_CHECK_EQUAL( G1.Delta( v01 ), v012 );
+    BOOST_CHECK_EQUAL( G1.Delta( v02 ), v012 );
+    BOOST_CHECK_EQUAL( G1.Delta( v12 ), v012 );
+    BOOST_CHECK_EQUAL( G1.Delta( v012 ), v012 );
+    BOOST_CHECK( G1.isConnected() );
+    BOOST_CHECK( G1.isTree() );
+    BOOST_CHECK( G1.isBinary() );
+    BOOST_CHECK( G1.isPairwise() );
+    BOOST_CHECK( G1.MarkovGraph() == H );
+    BOOST_CHECK( G1.bipGraph() == K );
+    BOOST_CHECK_EQUAL( G1.maximalFactorDomains().size(), 2 );
+    BOOST_CHECK_EQUAL( G1.maximalFactorDomains()[0], v01 );
+    BOOST_CHECK_EQUAL( G1.maximalFactorDomains()[1], v12 );
+
+    facs.push_back( Factor( v02 ) );
+    H.addEdge( 0, 2 );
+    K.addNode2();
+    K.addEdge( 0, 3 );
+    K.addEdge( 2, 3 );
+    FactorGraph G2( facs );
+    BOOST_CHECK_EQUAL( G2.nrVars(), 3 );
+    BOOST_CHECK_EQUAL( G2.nrFactors(), 4 );
+    BOOST_CHECK_EQUAL( G2.nrEdges(), 7 );
+    BOOST_CHECK_EQUAL( G2.findVar( v0 ), 0 );
+    BOOST_CHECK_EQUAL( G2.findVar( v1 ), 1 );
+    BOOST_CHECK_EQUAL( G2.findVar( v2 ), 2 );
+    BOOST_CHECK_EQUAL( G2.findVars( v01 ), SmallSet<size_t>( 0, 1 ) );
+    BOOST_CHECK_EQUAL( G2.findVars( v02 ), SmallSet<size_t>( 0, 2 ) );
+    BOOST_CHECK_EQUAL( G2.findVars( v12 ), SmallSet<size_t>( 1, 2 ) );
+    BOOST_CHECK_EQUAL( G2.findFactor( v01 ), 0 );
+    BOOST_CHECK_EQUAL( G2.findFactor( v12 ), 1 );
+    BOOST_CHECK_EQUAL( G2.findFactor( v1 ), 2 );
+    BOOST_CHECK_EQUAL( G2.findFactor( v02 ), 3 );
+    BOOST_CHECK_EQUAL( G2.delta( 0 ), v12 );
+    BOOST_CHECK_EQUAL( G2.delta( 1 ), v02 );
+    BOOST_CHECK_EQUAL( G2.delta( 2 ), v01 );
+    BOOST_CHECK_EQUAL( G2.Delta( 0 ), v012 );
+    BOOST_CHECK_EQUAL( G2.Delta( 1 ), v012 );
+    BOOST_CHECK_EQUAL( G2.Delta( 2 ), v012 );
+    BOOST_CHECK( G2.isConnected() );
+    BOOST_CHECK( !G2.isTree() );
+    BOOST_CHECK( G2.isBinary() );
+    BOOST_CHECK( G2.isPairwise() );
+    BOOST_CHECK( G2.MarkovGraph() == H );
+    BOOST_CHECK( G2.bipGraph() == K );
+    BOOST_CHECK_EQUAL( G2.maximalFactorDomains().size(), 3 );
+    BOOST_CHECK_EQUAL( G2.maximalFactorDomains()[0], v01 );
+    BOOST_CHECK_EQUAL( G2.maximalFactorDomains()[1], v12 );
+    BOOST_CHECK_EQUAL( G2.maximalFactorDomains()[2], v02 );
+
+    Var v3( 3, 3 );
+    VarSet v03( v0, v3 );
+    VarSet v13( v1, v3 );
+    VarSet v23( v2, v3 );
+    VarSet v013 = v01 | v3;
+    VarSet v023 = v02 | v3;
+    VarSet v123 = v12 | v3;
+    VarSet v0123 = v012 | v3;
+    vars.push_back( v3 );
+    facs.push_back( Factor( v3 ) );
+    H.addNode();
+    K.addNode1();
+    K.addNode2();
+    K.addEdge( 3, 4 );
+    FactorGraph G3( facs );
+    BOOST_CHECK_EQUAL( G3.nrVars(), 4 );
+    BOOST_CHECK_EQUAL( G3.nrFactors(), 5 );
+    BOOST_CHECK_EQUAL( G3.nrEdges(), 8 );
+    BOOST_CHECK_EQUAL( G3.findVar( v0 ), 0 );
+    BOOST_CHECK_EQUAL( G3.findVar( v1 ), 1 );
+    BOOST_CHECK_EQUAL( G3.findVar( v2 ), 2 );
+    BOOST_CHECK_EQUAL( G3.findVar( v3 ), 3 );
+    BOOST_CHECK_EQUAL( G3.findVars( v01 ), SmallSet<size_t>( 0, 1 ) );
+    BOOST_CHECK_EQUAL( G3.findVars( v02 ), SmallSet<size_t>( 0, 2 ) );
+    BOOST_CHECK_EQUAL( G3.findVars( v12 ), SmallSet<size_t>( 1, 2 ) );
+    BOOST_CHECK_EQUAL( G3.findFactor( v01 ), 0 );
+    BOOST_CHECK_EQUAL( G3.findFactor( v12 ), 1 );
+    BOOST_CHECK_EQUAL( G3.findFactor( v1 ), 2 );
+    BOOST_CHECK_EQUAL( G3.findFactor( v02 ), 3 );
+    BOOST_CHECK_EQUAL( G3.findFactor( v3 ), 4 );
+    BOOST_CHECK_THROW( G3.findFactor( v23 ), Exception );
+    BOOST_CHECK_EQUAL( G3.delta( 0 ), v12 );
+    BOOST_CHECK_EQUAL( G3.delta( 1 ), v02 );
+    BOOST_CHECK_EQUAL( G3.delta( 2 ), v01 );
+    BOOST_CHECK_EQUAL( G3.delta( 3 ), VarSet() );
+    BOOST_CHECK_EQUAL( G3.Delta( 0 ), v012 );
+    BOOST_CHECK_EQUAL( G3.Delta( 1 ), v012 );
+    BOOST_CHECK_EQUAL( G3.Delta( 2 ), v012 );
+    BOOST_CHECK_EQUAL( G3.Delta( 3 ), v3 );
+    BOOST_CHECK( !G3.isConnected() );
+    BOOST_CHECK( !G3.isTree() );
+    BOOST_CHECK( !G3.isBinary() );
+    BOOST_CHECK( G3.isPairwise() );
+    BOOST_CHECK( G3.MarkovGraph() == H );
+    BOOST_CHECK( G3.bipGraph() == K );
+    BOOST_CHECK_EQUAL( G3.maximalFactorDomains().size(), 4 );
+    BOOST_CHECK_EQUAL( G3.maximalFactorDomains()[0], v01 );
+    BOOST_CHECK_EQUAL( G3.maximalFactorDomains()[1], v12 );
+    BOOST_CHECK_EQUAL( G3.maximalFactorDomains()[2], v02 );
+    BOOST_CHECK_EQUAL( G3.maximalFactorDomains()[3], v3 );
+
+    facs.push_back( Factor( v123 ) );
+    H.addEdge( 1, 3 );
+    H.addEdge( 2, 3 );
+    K.addNode2();
+    K.addEdge( 1, 5 );
+    K.addEdge( 2, 5 );
+    K.addEdge( 3, 5 );
+    FactorGraph G4( facs );
+    BOOST_CHECK_EQUAL( G4.nrVars(), 4 );
+    BOOST_CHECK_EQUAL( G4.nrFactors(), 6 );
+    BOOST_CHECK_EQUAL( G4.nrEdges(), 11 );
+    BOOST_CHECK_EQUAL( G4.findVar( v0 ), 0 );
+    BOOST_CHECK_EQUAL( G4.findVar( v1 ), 1 );
+    BOOST_CHECK_EQUAL( G4.findVar( v2 ), 2 );
+    BOOST_CHECK_EQUAL( G4.findVar( v3 ), 3 );
+    BOOST_CHECK_EQUAL( G4.findVars( v01 ), SmallSet<size_t>( 0, 1 ) );
+    BOOST_CHECK_EQUAL( G4.findVars( v02 ), SmallSet<size_t>( 0, 2 ) );
+    BOOST_CHECK_EQUAL( G4.findVars( v12 ), SmallSet<size_t>( 1, 2 ) );
+    BOOST_CHECK_EQUAL( G4.findFactor( v01 ), 0 );
+    BOOST_CHECK_EQUAL( G4.findFactor( v12 ), 1 );
+    BOOST_CHECK_EQUAL( G4.findFactor( v1 ), 2 );
+    BOOST_CHECK_EQUAL( G4.findFactor( v02 ), 3 );
+    BOOST_CHECK_EQUAL( G4.findFactor( v3 ), 4 );
+    BOOST_CHECK_EQUAL( G4.findFactor( v123 ), 5 );
+    BOOST_CHECK_THROW( G4.findFactor( v23 ), Exception );
+    BOOST_CHECK_EQUAL( G4.delta( 0 ), v12 );
+    BOOST_CHECK_EQUAL( G4.delta( 1 ), v023 );
+    BOOST_CHECK_EQUAL( G4.delta( 2 ), v013 );
+    BOOST_CHECK_EQUAL( G4.delta( 3 ), v12 );
+    BOOST_CHECK_EQUAL( G4.Delta( 0 ), v012 );
+    BOOST_CHECK_EQUAL( G4.Delta( 1 ), v0123 );
+    BOOST_CHECK_EQUAL( G4.Delta( 2 ), v0123 );
+    BOOST_CHECK_EQUAL( G4.Delta( 3 ), v123 );
+    BOOST_CHECK( G4.isConnected() );
+    BOOST_CHECK( !G4.isTree() );
+    BOOST_CHECK( !G4.isBinary() );
+    BOOST_CHECK( !G4.isPairwise() );
+    BOOST_CHECK( G4.MarkovGraph() == H );
+    BOOST_CHECK( G4.bipGraph() == K );
+    BOOST_CHECK_EQUAL( G4.maximalFactorDomains().size(), 3 );
+    BOOST_CHECK_EQUAL( G4.maximalFactorDomains()[0], v01 );
+    BOOST_CHECK_EQUAL( G4.maximalFactorDomains()[1], v02 );
+    BOOST_CHECK_EQUAL( G4.maximalFactorDomains()[2], v123 );
+}
+
+
+BOOST_AUTO_TEST_CASE( BackupRestoreTest ) {
+    Var v0( 0, 2 );
+    Var v1( 1, 2 );
+    Var v2( 2, 2 );
+    VarSet v01( v0, v1 );
+    VarSet v02( v0, v2 );
+    VarSet v12( v1, v2 );
+    VarSet v012 = v01 | v2;
+
+    std::vector<Factor> facs;
+    facs.push_back( Factor( v01 ) );
+    facs.push_back( Factor( v12 ) );
+    facs.push_back( Factor( v1 ) );
+    std::vector<Var> vars;
+    vars.push_back( v0 );
+    vars.push_back( v1 );
+    vars.push_back( v2 );
+
+    FactorGraph G( facs );
+    FactorGraph Gorg( G );
+
+    BOOST_CHECK_THROW( G.setFactor( 0, Factor( v0 ), false ), Exception );
+    G.setFactor( 0, Factor( v01, 2.0 ), false );
+    BOOST_CHECK_THROW( G.restoreFactor( 0 ), Exception );
+    G.setFactor( 0, Factor( v01, 3.0 ), true );
+    G.restoreFactor( 0 );
+    BOOST_CHECK_EQUAL( G.factor( 0 )[0], 2.0 );
+    G.setFactor( 0, Gorg.factor( 0 ), false );
+    G.backupFactor( 0 );
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    G.setFactor( 0, Factor( v01, 2.0 ), false );
+    BOOST_CHECK_EQUAL( G.factor( 0 )[0], 2.0 );
+    G.restoreFactor( 0 );
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+
+    std::map<size_t, Factor> fs;
+    fs[0] = Factor( v01, 3.0 );
+    fs[2] = Factor( v1, 2.0 );
+    G.setFactors( fs, false );
+    BOOST_CHECK_EQUAL( G.factor(0), fs[0] );
+    BOOST_CHECK_EQUAL( G.factor(2), fs[2] );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    G.restoreFactors();
+    BOOST_CHECK_EQUAL( G.factor(0), fs[0] );
+    BOOST_CHECK_EQUAL( G.factor(2), fs[2] );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    G = Gorg;
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+    G.setFactors( fs, true );
+    BOOST_CHECK_EQUAL( G.factor(0), fs[0] );
+    BOOST_CHECK_EQUAL( G.factor(2), fs[2] );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    G.restoreFactors();
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+    std::set<size_t> fsind;
+    fsind.insert( 0 );
+    fsind.insert( 2 );
+    G.backupFactors( fsind );
+    G.setFactors( fs, false );
+    BOOST_CHECK_EQUAL( G.factor(0), fs[0] );
+    BOOST_CHECK_EQUAL( G.factor(2), fs[2] );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    G.restoreFactors();
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+
+    G.backupFactors( v2 );
+    G.setFactor( 1, Factor(v12, 5.0) );
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Factor(v12, 5.0) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+    G.restoreFactors( v2 );
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+
+    G.backupFactors( v1 );
+    fs[1] = Factor( v12, 5.0 );
+    G.setFactors( fs, false );
+    BOOST_CHECK_EQUAL( G.factor(0), fs[0] );
+    BOOST_CHECK_EQUAL( G.factor(1), fs[1] );
+    BOOST_CHECK_EQUAL( G.factor(2), fs[2] );
+    G.restoreFactors();
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+    G.setFactors( fs, true );
+    BOOST_CHECK_EQUAL( G.factor(0), fs[0] );
+    BOOST_CHECK_EQUAL( G.factor(1), fs[1] );
+    BOOST_CHECK_EQUAL( G.factor(2), fs[2] );
+    G.restoreFactors( v1 );
+    BOOST_CHECK_EQUAL( G.factor(0), Gorg.factor(0) );
+    BOOST_CHECK_EQUAL( G.factor(1), Gorg.factor(1) );
+    BOOST_CHECK_EQUAL( G.factor(2), Gorg.factor(2) );
+}
+
+
+BOOST_AUTO_TEST_CASE( TransformationsTest ) {
+    Var v0( 0, 2 );
+    Var v1( 1, 2 );
+    Var v2( 2, 2 );
+    VarSet v01( v0, v1 );
+    VarSet v02( v0, v2 );
+    VarSet v12( v1, v2 );
+    VarSet v012 = v01 | v2;
+
+    std::vector<Factor> facs;
+    facs.push_back( Factor( v01 ).randomize() );
+    facs.push_back( Factor( v12 ).randomize() );
+    facs.push_back( Factor( v1 ).randomize() );
+    std::vector<Var> vars;
+    vars.push_back( v0 );
+    vars.push_back( v1 );
+    vars.push_back( v2 );
+
+    FactorGraph G( facs );
+
+    FactorGraph Gsmall = G.maximalFactors();
+    BOOST_CHECK_EQUAL( Gsmall.nrVars(), 3 );
+    BOOST_CHECK_EQUAL( Gsmall.nrFactors(), 2 );
+    BOOST_CHECK_EQUAL( Gsmall.factor( 0 ), G.factor( 0 ) * G.factor( 2 ) );
+    BOOST_CHECK_EQUAL( Gsmall.factor( 1 ), G.factor( 1 ) );
+
+    size_t i = 0;
+    for( size_t x = 0; x < 2; x++ ) {
+        FactorGraph Gcl = G.clamped( i, x );
+        BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+        BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+        BOOST_CHECK_EQUAL( Gcl.factor(0), createFactorDelta(vars[i], x) );
+        BOOST_CHECK_EQUAL( Gcl.factor(1), G.factor(0).slice(vars[i], x) * G.factor(2) );
+        BOOST_CHECK_EQUAL( Gcl.factor(2), G.factor(1) );
+    }
+    i = 1;
+    for( size_t x = 0; x < 2; x++ ) {
+        FactorGraph Gcl = G.clamped( i, x );
+        BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+        BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+        BOOST_CHECK_EQUAL( Gcl.factor(0), createFactorDelta(vars[i], x) * G.factor(2).slice(vars[i],x) );
+        BOOST_CHECK_EQUAL( Gcl.factor(1), G.factor(0).slice(vars[i], x) );
+        BOOST_CHECK_EQUAL( Gcl.factor(2), G.factor(1).slice(vars[i], x) );
+    }
+    i = 2;
+    for( size_t x = 0; x < 2; x++ ) {
+        FactorGraph Gcl = G.clamped( i, x );
+        BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+        BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+        BOOST_CHECK_EQUAL( Gcl.factor(0), createFactorDelta(vars[i], x) );
+        BOOST_CHECK_EQUAL( Gcl.factor(1), G.factor(0) );
+        BOOST_CHECK_EQUAL( Gcl.factor(2), G.factor(1).slice(vars[i], x) * G.factor(2) );
+    }
+}
+
+
+BOOST_AUTO_TEST_CASE( OperationsTest ) {
+    Var v0( 0, 2 );
+    Var v1( 1, 2 );
+    Var v2( 2, 2 );
+    VarSet v01( v0, v1 );
+    VarSet v02( v0, v2 );
+    VarSet v12( v1, v2 );
+    VarSet v012 = v01 | v2;
+
+    std::vector<Factor> facs;
+    facs.push_back( Factor( v01 ).randomize() );
+    facs.push_back( Factor( v12 ).randomize() );
+    facs.push_back( Factor( v1 ).randomize() );
+    std::vector<Var> vars;
+    vars.push_back( v0 );
+    vars.push_back( v1 );
+    vars.push_back( v2 );
+
+    FactorGraph G( facs );
+
+    // clamp
+    FactorGraph Gcl = G;
+    for( size_t i = 0; i < 3; i++ )
+        for( size_t x = 0; x < 2; x++ ) {
+            Gcl.clamp( i, x, true );
+            Factor delta = createFactorDelta( vars[i], x );
+            BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+            BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+            for( size_t j = 0; j < 3; j++ )
+                if( G.factor(j).vars().contains( vars[i] ) )
+                    BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) * delta );
+                else
+                    BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+
+            Gcl.restoreFactors();
+            for( size_t j = 0; j < 3; j++ )
+                BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+        }
+
+    // clampVar
+    for( size_t i = 0; i < 3; i++ )
+        for( size_t x = 0; x < 2; x++ ) {
+            Gcl.clampVar( i, std::vector<size_t>(1, x), true );
+            Factor delta = createFactorDelta( vars[i], x );
+            BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+            BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+            for( size_t j = 0; j < 3; j++ )
+                if( G.factor(j).vars().contains( vars[i] ) )
+                    BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) * delta );
+                else
+                    BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+
+            Gcl.restoreFactors();
+            for( size_t j = 0; j < 3; j++ )
+                BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+        }
+    for( size_t i = 0; i < 3; i++ )
+        for( size_t x = 0; x < 2; x++ ) {
+            Gcl.clampVar( i, std::vector<size_t>(), true );
+            BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+            BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+            for( size_t j = 0; j < 3; j++ )
+                if( G.factor(j).vars().contains( vars[i] ) )
+                    BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) * 0.0 );
+                else
+                    BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+
+            Gcl.restoreFactors();
+            for( size_t j = 0; j < 3; j++ )
+                BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+        }
+    std::vector<size_t> both;
+    both.push_back( 0 );
+    both.push_back( 1 );
+    for( size_t i = 0; i < 3; i++ )
+        for( size_t x = 0; x < 2; x++ ) {
+            Gcl.clampVar( i, both, true );
+            BOOST_CHECK_EQUAL( Gcl.nrVars(), 3 );
+            BOOST_CHECK_EQUAL( Gcl.nrFactors(), 3 );
+            for( size_t j = 0; j < 3; j++ )
+                BOOST_CHECK_EQUAL( Gcl.factor(j), G.factor(j) );
+            Gcl.restoreFactors();
+        }
+
+    // clampFactor
+    for( size_t x = 0; x < 4; x++ ) {
+        Gcl.clampFactor( 0, std::vector<size_t>(1,x), true );
+        Factor mask( v01, 0.0 );
+        mask.set( x, 1.0 );
+        BOOST_CHECK_EQUAL( Gcl.factor(0), G.factor(0) * mask );
+        BOOST_CHECK_EQUAL( Gcl.factor(1), G.factor(1) );
+        BOOST_CHECK_EQUAL( Gcl.factor(2), G.factor(2) );
+        Gcl.restoreFactor( 0 );
+    }
+    for( size_t x = 0; x < 4; x++ ) {
+        Gcl.clampFactor( 1, std::vector<size_t>(1,x), true );
+        Factor mask( v12, 0.0 );
+        mask.set( x, 1.0 );
+        BOOST_CHECK_EQUAL( Gcl.factor(0), G.factor(0) );
+        BOOST_CHECK_EQUAL( Gcl.factor(1), G.factor(1) * mask );
+        BOOST_CHECK_EQUAL( Gcl.factor(2), G.factor(2) );
+        Gcl.restoreFactor( 1 );
+    }
+    for( size_t x = 0; x < 2; x++ ) {
+        Gcl.clampFactor( 2, std::vector<size_t>(1,x), true );
+        Factor mask( v1, 0.0 );
+        mask.set( x, 1.0 );
+        BOOST_CHECK_EQUAL( Gcl.factor(0), G.factor(0) );
+        BOOST_CHECK_EQUAL( Gcl.factor(1), G.factor(1) );
+        BOOST_CHECK_EQUAL( Gcl.factor(2), G.factor(2) * mask );
+        Gcl.restoreFactors();
+    }
+
+    // makeCavity
+    FactorGraph Gcav( G );
+    Gcav.makeCavity( 0, true );
+    BOOST_CHECK_EQUAL( Gcav.factor(0), Factor( v01, 1.0 ) );
+    BOOST_CHECK_EQUAL( Gcav.factor(1), G.factor(1) );
+    BOOST_CHECK_EQUAL( Gcav.factor(2), G.factor(2) );
+    Gcav.restoreFactors();
+    Gcav.makeCavity( 1, true );
+    BOOST_CHECK_EQUAL( Gcav.factor(0), Factor( v01, 1.0 ) );
+    BOOST_CHECK_EQUAL( Gcav.factor(1), Factor( v12, 1.0 ) );
+    BOOST_CHECK_EQUAL( Gcav.factor(2), Factor( v1, 1.0 ) );
+    Gcav.restoreFactors();
+    Gcav.makeCavity( 2, true );
+    BOOST_CHECK_EQUAL( Gcav.factor(0), G.factor(0) );
+    BOOST_CHECK_EQUAL( Gcav.factor(1), Factor( v12, 1.0 ) );
+    BOOST_CHECK_EQUAL( Gcav.factor(2), G.factor(2) );
+    Gcav.restoreFactors();
+}
+
+
+BOOST_AUTO_TEST_CASE( IOTest ) {
+    Var v0( 0, 2 );
+    Var v1( 1, 2 );
+    Var v2( 2, 2 );
+    VarSet v01( v0, v1 );
+    VarSet v02( v0, v2 );
+    VarSet v12( v1, v2 );
+    VarSet v012 = v01 | v2;
+
+    std::vector<Factor> facs;
+    facs.push_back( Factor( v01 ).randomize() );
+    facs.push_back( Factor( v12 ).randomize() );
+    facs.push_back( Factor( v1 ).randomize() );
+    std::vector<Var> vars;
+    vars.push_back( v0 );
+    vars.push_back( v1 );
+    vars.push_back( v2 );
+
+    FactorGraph G( facs );
+
+    G.WriteToFile( "factorgraph_test.fg" );
+    FactorGraph G2;
+    G2.ReadFromFile( "factorgraph_test.fg" );
+
+    BOOST_CHECK( G.vars() == G2.vars() );
+    BOOST_CHECK( G.bipGraph() == G2.bipGraph() );
+    BOOST_CHECK_EQUAL( G.nrFactors(), G2.nrFactors() );
+    for( size_t I = 0; I < G.nrFactors(); I++ ) {
+        BOOST_CHECK( G.factor(I).vars() == G2.factor(I).vars() );
+        for( size_t s = 0; s < G.factor(I).nrStates(); s++ )
+            BOOST_CHECK_CLOSE( G.factor(I)[s], G2.factor(I)[s], tol );
+    }
+
+    std::stringstream ss;
+    std::string s;
+    G.printDot( ss );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "graph G {" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "node[shape=circle,width=0.4,fixedsize=true];" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv0;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv1;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv2;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "node[shape=box,width=0.3,height=0.3,fixedsize=true];" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tf0;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tf1;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tf2;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv0 -- f0;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv1 -- f0;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv1 -- f1;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv1 -- f2;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "\tv2 -- f1;" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "}" );
+
+    G.factor(0).fill(1.0);
+    G.factor(1).fill(2.0);
+    G.factor(2).fill(3.0);
+    ss << G;
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "3" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "0 1 " );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2 2 " );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "4" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "0          1" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "1          1" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2          1" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "3          1" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "1 2 " );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2 2 " );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "4" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "0          2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "1          2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2          2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "3          2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "1" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "1 " );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2 " );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "2" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "0          3" );
+    std::getline( ss, s ); BOOST_CHECK_EQUAL( s, "1          3" );
+
+    ss << G;
+    FactorGraph G3;
+    ss >> G3;
+    BOOST_CHECK( G.vars() == G3.vars() );
+    BOOST_CHECK( G.bipGraph() == G3.bipGraph() );
+    BOOST_CHECK_EQUAL( G.nrFactors(), G3.nrFactors() );
+    for( size_t I = 0; I < G.nrFactors(); I++ ) {
+        BOOST_CHECK( G.factor(I).vars() == G3.factor(I).vars() );
+        for( size_t s = 0; s < G.factor(I).nrStates(); s++ )
+            BOOST_CHECK_CLOSE( G.factor(I)[s], G3.factor(I)[s], tol );
+    }
+}
index a7bc4b3..4d8471f 100644 (file)
@@ -40,6 +40,7 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK_EQUAL( G2.isConnected(), false );
     BOOST_CHECK_EQUAL( G2.isTree(), false );
     G2.checkConsistency();
+    BOOST_CHECK( !(G2 == G0) );
     
     typedef GraphAL::Edge Edge;
     std::vector<Edge> edges;
@@ -53,6 +54,18 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     BOOST_CHECK_EQUAL( G3.isConnected(), true );
     BOOST_CHECK_EQUAL( G3.isTree(), true );
     G3.checkConsistency();
+    BOOST_CHECK( !(G3 == G0) );
+    BOOST_CHECK( !(G3 == G2) );
+
+    GraphAL G4( G3 );
+    BOOST_CHECK( !(G4 == G0) );
+    BOOST_CHECK( !(G4 == G2) );
+    BOOST_CHECK( G4 == G3 );
+
+    GraphAL G5 = G3;
+    BOOST_CHECK( !(G5 == G0) );
+    BOOST_CHECK( !(G5 == G2) );
+    BOOST_CHECK( G5 == G3 );
 }
 
 
index 5df21ab..c9a99d3 100644 (file)
@@ -88,6 +88,18 @@ BOOST_AUTO_TEST_CASE( ConstructorsTest ) {
     
     Prob x8 = x6;
     BOOST_CHECK( x8 == x6 );
+
+    x7.resize( 5 );
+    BOOST_CHECK_EQUAL( x7.size(), 5 );
+    BOOST_CHECK_EQUAL( x7[0], 2.0 );
+    BOOST_CHECK_EQUAL( x7[1], 2.0 );
+    BOOST_CHECK_EQUAL( x7[2], 2.0 );
+    BOOST_CHECK_EQUAL( x7[3], 0.0 );
+    BOOST_CHECK_EQUAL( x7[4], 0.0 );
+
+    x8.resize( 1 );
+    BOOST_CHECK_EQUAL( x8.size(), 1 );
+    BOOST_CHECK_EQUAL( x8[0], 2.0 );
 }
 
 
index 87d20f4..c77fa3a 100644 (file)
@@ -461,6 +461,32 @@ BOOST_AUTO_TEST_CASE( OperatorTest ) {
     y = x123; y /= x13;  BOOST_CHECK_EQUAL( y, x2   );
     y = x123; y /= x123; BOOST_CHECK_EQUAL( y, x    );
 
+    // check insert
+    y = x   ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x1   );
+    y = x   ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x2   );
+    y = x   ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x3   );
+    y = x1  ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x1   );
+    y = x1  ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x12  );
+    y = x1  ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x13  );
+    y = x2  ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x12  );
+    y = x2  ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x2   );
+    y = x2  ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x23  );
+    y = x3  ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x13  );
+    y = x3  ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x23  );
+    y = x3  ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x3   );
+    y = x12 ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x12  );
+    y = x12 ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x12  );
+    y = x12 ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x123 );
+    y = x23 ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x123 );
+    y = x23 ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x23  );
+    y = x23 ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x23  );
+    y = x13 ; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x13  );
+    y = x13 ; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x123 );
+    y = x13 ; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x13  );
+    y = x123; y.insert( 1 );   BOOST_CHECK_EQUAL( y, x123 );
+    y = x123; y.insert( 2 );   BOOST_CHECK_EQUAL( y, x123 );
+    y = x123; y.insert( 3 );   BOOST_CHECK_EQUAL( y, x123 );
+
     // check operator|=
     y = x   ; y |= x;    BOOST_CHECK_EQUAL( y, x    );
     y = x   ; y |= x1;   BOOST_CHECK_EQUAL( y, x1   );
index 38beade..732b57f 100644 (file)
@@ -168,6 +168,14 @@ BOOST_AUTO_TEST_CASE( RootedTreeTest ) {
     edges.push_back( E(5, 6) );
     G = GraphEL( edges.begin(), edges.end() );
     BOOST_CHECK_THROW( RootedTree T( G, 1 ), Exception );
+
+    GraphAL H( 3 );
+    H.addEdge( 0, 1 );
+    H.addEdge( 1, 2 );
+    H.addEdge( 2, 1 );
+    G = GraphEL( H );
+    for( GraphEL::const_iterator e = G.begin(); e != G.end(); e++ )
+        BOOST_CHECK( H.hasEdge( e->first, e->second ) );
 }