Added functionality for reading files in the UAI approximate inference challenge...
authorJoris Mooij <joris.mooij@tuebingen.mpg.de>
Thu, 5 Aug 2010 10:53:22 +0000 (12:53 +0200)
committerJoris Mooij <joris.mooij@tuebingen.mpg.de>
Thu, 5 Aug 2010 10:53:22 +0000 (12:53 +0200)
ChangeLog
Makefile
examples/uai2010-aie-solver.cpp
include/dai/io.h [new file with mode: 0644]
src/io.cpp [new file with mode: 0644]
utils/uai2fg.cpp

index 5d3aea7..043b2f9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 git HEAD
 --------
+* Added io.h/io.cpp which currently provides functionality for reading
+  files in the UAI Approximate Inference Challenge fileformats
+  (supporting both the 2006/2008 evidence file format and the 2010
+  evidence file format)
+* Deprecated void tokenizeString( const string&, vector<string>&, const string& )
+  and replaced it with an improved version
+  vector<string> tokenizeString( const string&, bool, const string& )
 * [Matt Dunham] Fixed a bug in Factors2mx in src/matlab/matlab.cpp:
   segfault if factors depending on 0 variables were passed to MatLab
 * Added source code for one of the winning solvers of the 
index d76c56f..c8e1c59 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -44,7 +44,7 @@ ifdef WITH_DOC
 endif
 
 # Define conditional build targets
-NAMES:=graph dag bipgraph varset daialg alldai clustergraph factor factorgraph properties regiongraph util weightedgraph exceptions exactinf evidence emalg
+NAMES:=graph dag bipgraph varset daialg alldai clustergraph factor factorgraph properties regiongraph util weightedgraph exceptions exactinf evidence emalg io
 ifdef WITH_BP
   WITHFLAGS:=$(WITHFLAGS) -DDAI_WITH_BP
   NAMES:=$(NAMES) bp
index 7547335..851b10d 100644 (file)
@@ -13,9 +13,7 @@
 #include <ostream>
 #include <cstdlib>
 #include <dai/alldai.h>
-#include <dai/util.h>
-#include <dai/index.h>
-#include <dai/jtree.h>
+#include <dai/io.h>
 
 
 using namespace std;
@@ -48,182 +46,6 @@ struct MPEbest {
 };
 
 
-/// Reads "evidence" (a mapping from observed variable labels to the observed values) from a UAI evidence file
-vector<map<size_t, size_t> > ReadUAIEvidenceFile( char* filename, size_t verbose ) {
-    vector<map<size_t, size_t> > evid;
-
-    // open file
-    ifstream is;
-    is.open( filename );
-    if( is.is_open() ) {
-        // read number of evidence cases
-        size_t nr_evid;
-        is >> nr_evid;
-        if( is.fail() )
-            DAI_THROWE(INVALID_EVIDENCE_FILE,"Cannot read number of evidence cases");
-        if( verbose >= 2 )
-            cout << "Reading " << nr_evid << " evidence cases..." << endl;
-        
-        evid.resize( nr_evid );
-        for( size_t i = 0; i < nr_evid; i++ ) {
-            // read number of variables
-            size_t nr_obs;
-            is >> nr_obs;
-            if( is.fail() )
-                DAI_THROWE(INVALID_EVIDENCE_FILE,"Evidence case " + toString(i) + ": Cannot read number of observations");
-            if( verbose >= 2 )
-                cout << "Evidence case " << i << ": reading " << nr_obs << " observations..." << endl;
-
-            // for each observation, read the variable label and the observed value
-            for( size_t j = 0; j < nr_obs; j++ ) {
-                size_t label, val;
-                is >> label;
-                if( is.fail() )
-                    DAI_THROWE(INVALID_EVIDENCE_FILE,"Evidence case " + toString(i) + ": Cannot read label for " + toString(j) + "'th observed variable");
-                is >> val;
-                if( is.fail() )
-                    DAI_THROWE(INVALID_EVIDENCE_FILE,"Evidence case " + toString(i) + ": Cannot read value of " + toString(j) + "'th observed variable");
-                if( verbose >= 3 )
-                    cout << "  variable: " << label << ", value: " << val << endl;
-                evid[i][label] = val;
-            }
-        }
-
-        // close file
-        is.close();
-    } else
-        DAI_THROWE(CANNOT_READ_FILE,"Cannot read from file " + std::string(filename));
-
-    if( evid.size() == 0 )
-        evid.resize( 1 );
-
-    return evid;
-}
-
-
-/// Reads factor graph (as a pair of a variable vector and factor vector) from a UAI factor graph file
-void ReadUAIFGFile( const char *filename, size_t verbose, vector<Var>& vars, vector<Factor>& factors, vector<Permute>& permutations ) {
-    vars.clear();
-    factors.clear();
-    permutations.clear();
-
-    // open file
-    ifstream is;
-    is.open( filename );
-    if( is.is_open() ) {
-        size_t nrFacs, nrVars;
-        string line;
-        
-        // read header line
-        getline(is,line);
-        if( is.fail() || (line != "BAYES" && line != "MARKOV" && line != "BAYES\r" && line != "MARKOV\r") )
-            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"UAI factor graph file should start with \"BAYES\" or \"MARKOV\"");
-        if( verbose >= 2 )
-            cout << "Reading " << line << " network..." << endl;
-
-        // read number of variables
-        is >> nrVars;
-        if( is.fail() )
-            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of variables");
-        if( verbose >= 2 )
-            cout << "Reading " << nrVars << " variables..." << endl;
-
-        // for each variable, read its number of states
-        vars.reserve( nrVars );
-        for( size_t i = 0; i < nrVars; i++ ) {
-            size_t dim;
-            is >> dim;
-            if( is.fail() )
-                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of states of " + toString(i) + "'th variable");
-            vars.push_back( Var( i, dim ) );
-        }
-
-        // read number of factors
-        is >> nrFacs;
-        if( is.fail() )
-            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of factors");
-        if( verbose >= 2 )
-            cout << "Reading " << nrFacs << " factors..." << endl;
-
-        // for each factor, read the variables on which it depends
-        vector<vector<Var> > factorVars;
-        factors.reserve( nrFacs );
-        factorVars.reserve( nrFacs );
-        for( size_t I = 0; I < nrFacs; I++ ) {
-            if( verbose >= 3 )
-                cout << "Reading factor " << I << "..." << endl;
-
-            // read number of variables for factor I
-            size_t I_nrVars;
-            is >> I_nrVars;
-            if( is.fail() )
-                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of variables for " + toString(I) + "'th factor");
-            if( verbose >= 3 )
-                cout << "  which depends on " << I_nrVars << " variables" << endl;
-
-            // read the variable labels
-            vector<long> I_labels;
-            vector<size_t> I_dims;
-            I_labels.reserve( I_nrVars );
-            I_dims.reserve( I_nrVars );
-            factorVars[I].reserve( I_nrVars );
-            for( size_t _i = 0; _i < I_nrVars; _i++ ) {
-                long label;
-                is >> label;
-                if( is.fail() )
-                    DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read variable labels for " + toString(I) + "'th factor");
-                I_labels.push_back( label );
-                I_dims.push_back( vars[label].states() );
-                factorVars[I].push_back( vars[label] );
-            }
-            if( verbose >= 3 )
-                cout << "  labels: " << I_labels << ", dimensions " << I_dims << endl;
-
-            // add the factor and the labels
-            factors.push_back( Factor( VarSet( factorVars[I].begin(), factorVars[I].end(), factorVars[I].size() ), (Real)0 ) );
-        }
-
-        // for each factor, read its values
-        permutations.reserve( nrFacs );
-        for( size_t I = 0; I < nrFacs; I++ ) {
-            if( verbose >= 3 )
-                cout << "Reading factor " << I << "..." << endl;
-
-            // calculate permutation object, reversing the indexing in factorVars[I] first
-            Permute permindex( factorVars[I], true );
-            permutations.push_back( permindex );
-
-            // read factor values
-            size_t nrNonZeros;
-            is >> nrNonZeros;
-            if( is.fail() )
-                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of nonzero factor values for " + toString(I) + "'th factor");
-            if( verbose >= 3 ) 
-                cout << "  number of nonzero values: " << nrNonZeros << endl;
-            DAI_ASSERT( nrNonZeros == factors[I].nrStates() );
-            for( size_t li = 0; li < nrNonZeros; li++ ) {
-                Real val;
-                is >> val;
-                if( is.fail() )
-                    DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read factor values of " + toString(I) + "'th factor");
-                // assign value after calculating its linear index corresponding to the permutation
-                if( verbose >= 4 )
-                    cout << "  " << li << "'th value " << val << " corresponds with index " << permindex.convertLinearIndex(li) << endl;
-                factors[I].set( permindex.convertLinearIndex( li ), val );
-            }
-        }
-        if( verbose >= 3 )
-            cout << "variables:" << vars << endl;
-        if( verbose >= 3 )
-            cout << "factors:" << factors << endl;
-
-        // close file
-        is.close();
-    } else
-        DAI_THROWE(CANNOT_READ_FILE,"Cannot read from file " + std::string(filename));
-}
-
-
 int main( int argc, char *argv[] ) {
     if ( argc != 5 ) {
         cout << "This program is part of libDAI - http://www.libdai.org/" << endl << endl;
@@ -235,9 +57,9 @@ int main( int argc, char *argv[] ) {
     } else {
         double starttic = toc();
 
-        size_t verbose = 1;
-        size_t ia_verbose = 0;
-        bool surgery = true;
+        size_t verbose = 1;    // verbosity
+        size_t ia_verbose = 0; // verbosity of inference algorithms
+        bool surgery = true;   // change factor graph structure based on evidence
         if( verbose )
             cout << "Solver:               " << argv[0] << endl;
 
@@ -295,7 +117,7 @@ int main( int argc, char *argv[] ) {
         vector<Permute> permutations;
         if( verbose )
             cout << "Reading factor graph..." << endl;
-        ReadUAIFGFile( argv[1], verbose, vars, facs0, permutations );
+        ReadUaiAieFactorGraphFile( argv[1], verbose, vars, facs0, permutations );
         if( verbose )
             cout << "Successfully read factor graph" << endl;
 
@@ -323,7 +145,7 @@ int main( int argc, char *argv[] ) {
         // read evidence
         if( verbose )
             cout << "Reading evidence..." << endl;
-        vector<map<size_t,size_t> > evid = ReadUAIEvidenceFile( argv[2], verbose );
+        vector<map<size_t,size_t> > evid = ReadUaiAieEvidenceFile( argv[2], verbose );
         if( verbose )
             cout << "Successfully read " << evid.size() << " evidence cases" << endl;
 
@@ -420,7 +242,7 @@ int main( int argc, char *argv[] ) {
                 // construct inference algorithm on clamped factor graph
                 if( verbose )
                     cout << "      Constructing inference algorithm..." << endl;
-                InfAlg *ia;
+                InfAlg *ia = NULL;
                 double tic = toc();
                 bool failed = false;
                 try {
diff --git a/include/dai/io.h b/include/dai/io.h
new file mode 100644 (file)
index 0000000..e5dd501
--- /dev/null
@@ -0,0 +1,49 @@
+/*  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]
+ */
+
+
+/// \file
+/// \brief Provides functionality for input/output of data structures in various file formats
+
+
+#ifndef __defined_libdai_io_h
+#define __defined_libdai_io_h
+
+
+#include <dai/factor.h>
+#include <vector>
+#include <map>
+
+
+namespace dai {
+
+
+/// Reads factor graph (as a pair of a variable vector and factor vector) from a file in the UAI approximate inference challenge format
+/** \param[in] filename The filename (usually ends with ".uai")
+ *  \param[in] verbose The amount of output sent to cout
+ *  \param[out] vars Array of variables read from the file
+ *  \param[out] factors Array of factors read from the file
+ *  \param[out] permutations Array of permutations, which permute between libDAI canonical ordering and ordering specified by the file
+ *  \see http://www.cs.huji.ac.il/project/UAI10 and http://graphmod.ics.uci.edu/uai08
+ */
+void ReadUaiAieFactorGraphFile( const char *filename, size_t verbose, std::vector<Var>& vars, std::vector<Factor>& factors, std::vector<Permute>& permutations );
+
+
+/// Reads evidence (a mapping from observed variable labels to the observed values) from a file in the UAI approximate inference challenge format
+/** \param[in] filename The filename (usually ends with ".uai.evid")
+ *  \param[in] verbose The amount of output sent to cout
+ *  \see http://www.cs.huji.ac.il/project/UAI10 and http://graphmod.ics.uci.edu/uai08
+ */
+std::vector<std::map<size_t, size_t> > ReadUaiAieEvidenceFile( const char* filename, size_t verbose );
+
+
+} // end of namespace dai
+
+
+#endif
diff --git a/src/io.cpp b/src/io.cpp
new file mode 100644 (file)
index 0000000..84c44f0
--- /dev/null
@@ -0,0 +1,236 @@
+/*  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) 2008-2010  Joris Mooij  [joris dot mooij at libdai dot org]
+ */
+
+
+#include <dai/io.h>
+#include <dai/alldai.h>
+#include <iostream>
+#include <fstream>
+
+
+namespace dai {
+
+
+using namespace std;
+
+
+void ReadUaiAieFactorGraphFile( const char *filename, size_t verbose, std::vector<Var>& vars, std::vector<Factor>& factors, std::vector<Permute>& permutations ) {
+    vars.clear();
+    factors.clear();
+    permutations.clear();
+
+    // open file
+    ifstream is;
+    is.open( filename );
+    if( is.is_open() ) {
+        size_t nrFacs, nrVars;
+        string line;
+        
+        // read header line
+        getline(is,line);
+        if( is.fail() || line.size() == 0 )
+            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"UAI factor graph file should start with nonempty header line");
+        if( line[line.size() - 1] == '\r' )
+            line.resize( line.size() - 1 ); // for DOS text files
+        if( line != "BAYES" && line != "MARKOV" )
+            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"UAI factor graph file should start with \"BAYES\" or \"MARKOV\"");
+        if( verbose >= 2 )
+            cout << "Reading " << line << " network..." << endl;
+
+        // read number of variables
+        is >> nrVars;
+        if( is.fail() )
+            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of variables");
+        if( verbose >= 2 )
+            cout << "Reading " << nrVars << " variables..." << endl;
+
+        // for each variable, read its number of states
+        vars.reserve( nrVars );
+        for( size_t i = 0; i < nrVars; i++ ) {
+            size_t dim;
+            is >> dim;
+            if( is.fail() )
+                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of states of " + toString(i) + "'th variable");
+            vars.push_back( Var( i, dim ) );
+        }
+
+        // read number of factors
+        is >> nrFacs;
+        if( is.fail() )
+            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of factors");
+        if( verbose >= 2 )
+            cout << "Reading " << nrFacs << " factors..." << endl;
+
+        // for each factor, read the variables on which it depends
+        vector<vector<Var> > factorVars;
+        factors.reserve( nrFacs );
+        factorVars.reserve( nrFacs );
+        for( size_t I = 0; I < nrFacs; I++ ) {
+            if( verbose >= 3 )
+                cout << "Reading factor " << I << "..." << endl;
+
+            // read number of variables for factor I
+            size_t I_nrVars;
+            is >> I_nrVars;
+            if( is.fail() )
+                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of variables for " + toString(I) + "'th factor");
+            if( verbose >= 3 )
+                cout << "  which depends on " << I_nrVars << " variables" << endl;
+
+            // read the variable labels
+            vector<long> I_labels;
+            vector<size_t> I_dims;
+            I_labels.reserve( I_nrVars );
+            I_dims.reserve( I_nrVars );
+            factorVars[I].reserve( I_nrVars );
+            for( size_t _i = 0; _i < I_nrVars; _i++ ) {
+                long label;
+                is >> label;
+                if( is.fail() )
+                    DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read variable labels for " + toString(I) + "'th factor");
+                I_labels.push_back( label );
+                I_dims.push_back( vars[label].states() );
+                factorVars[I].push_back( vars[label] );
+            }
+            if( verbose >= 3 )
+                cout << "  labels: " << I_labels << ", dimensions " << I_dims << endl;
+
+            // add the factor and the labels
+            factors.push_back( Factor( VarSet( factorVars[I].begin(), factorVars[I].end(), factorVars[I].size() ), (Real)0 ) );
+        }
+
+        // for each factor, read its values
+        permutations.reserve( nrFacs );
+        for( size_t I = 0; I < nrFacs; I++ ) {
+            if( verbose >= 3 )
+                cout << "Reading factor " << I << "..." << endl;
+
+            // calculate permutation object, reversing the indexing in factorVars[I] first
+            Permute permindex( factorVars[I], true );
+            permutations.push_back( permindex );
+
+            // read factor values
+            size_t nrNonZeros;
+            is >> nrNonZeros;
+            if( is.fail() )
+                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of nonzero factor values for " + toString(I) + "'th factor");
+            if( verbose >= 3 ) 
+                cout << "  number of nonzero values: " << nrNonZeros << endl;
+            DAI_ASSERT( nrNonZeros == factors[I].nrStates() );
+            for( size_t li = 0; li < nrNonZeros; li++ ) {
+                Real val;
+                is >> val;
+                if( is.fail() )
+                    DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read factor values of " + toString(I) + "'th factor");
+                // assign value after calculating its linear index corresponding to the permutation
+                if( verbose >= 4 )
+                    cout << "  " << li << "'th value " << val << " corresponds with index " << permindex.convertLinearIndex(li) << endl;
+                factors[I].set( permindex.convertLinearIndex( li ), val );
+            }
+        }
+        if( verbose >= 3 )
+            cout << "variables:" << vars << endl;
+        if( verbose >= 3 )
+            cout << "factors:" << factors << endl;
+
+        // close file
+        is.close();
+    } else
+        DAI_THROWE(CANNOT_READ_FILE,"Cannot read from file " + std::string(filename));
+}
+
+
+std::vector<std::map<size_t, size_t> > ReadUaiAieEvidenceFile( const char* filename, size_t verbose ) {
+    vector<map<size_t, size_t> > evid;
+
+    // open file
+    ifstream is;
+    string line;
+    is.open( filename );
+    if( is.is_open() ) {
+        // read number of lines
+        getline( is, line );
+        if( is.fail() || line.size() == 0 )
+            DAI_THROWE(INVALID_EVIDENCE_FILE,"Cannot read header line of evidence file");
+        if( line[line.size() - 1] == '\r' )
+            line.resize( line.size() - 1 ); // for DOS text files
+        size_t nrLines = fromString<size_t>( line );
+        if( verbose >= 2 )
+            cout << "Reading " << nrLines << " evidence file lines..." << endl;
+
+        if( nrLines ) {
+            // detect version (pre-2010 or 2010)
+            streampos pos = is.tellg();
+            getline( is, line );
+            if( is.fail() || line.size() == 0 )
+                DAI_THROWE(INVALID_EVIDENCE_FILE,"Cannot read second line of evidence file");
+            if( line[line.size() - 1] == '\r' )
+                line.resize( line.size() - 1 ); // for DOS text files
+            vector<string> cols;
+            cols = tokenizeString( line, false, " \t" );
+            bool oldVersion = true;
+            if( cols.size() % 2 )
+                oldVersion = false;
+            if( verbose >= 2 ) {
+                if( oldVersion )
+                    cout << "Detected old (2006, 2008) evidence file format" << endl;
+                else
+                    cout << "Detected new (2010) evidence file format" << endl;
+            }
+            size_t nrEvid;
+            if( oldVersion ) {
+                nrEvid = 1;
+                is.seekg( 0 );
+            } else {
+                nrEvid = nrLines;
+                is.seekg( pos );
+            }
+                
+            // read all evidence cases
+            if( verbose >= 2 )
+                cout << "Reading " << nrEvid << " evidence cases..." << endl;
+            evid.resize( nrEvid );
+            for( size_t i = 0; i < nrEvid; i++ ) {
+                // read number of variables
+                size_t nrObs;
+                is >> nrObs;
+                if( is.fail() )
+                    DAI_THROWE(INVALID_EVIDENCE_FILE,"Evidence case " + toString(i) + ": Cannot read number of observations");
+                if( verbose >= 2 )
+                    cout << "Evidence case " << i << ": reading " << nrObs << " observations..." << endl;
+
+                // for each observation, read the variable label and the observed value
+                for( size_t j = 0; j < nrObs; j++ ) {
+                    size_t label, val;
+                    is >> label;
+                    if( is.fail() )
+                        DAI_THROWE(INVALID_EVIDENCE_FILE,"Evidence case " + toString(i) + ": Cannot read label for " + toString(j) + "'th observed variable");
+                    is >> val;
+                    if( is.fail() )
+                        DAI_THROWE(INVALID_EVIDENCE_FILE,"Evidence case " + toString(i) + ": Cannot read value of " + toString(j) + "'th observed variable");
+                    if( verbose >= 3 )
+                        cout << "  variable: " << label << ", value: " << val << endl;
+                    evid[i][label] = val;
+                }
+            }
+        }
+
+        // close file
+        is.close();
+    } else
+        DAI_THROWE(CANNOT_READ_FILE,"Cannot read from file " + std::string(filename));
+
+    if( evid.size() == 0 )
+        evid.resize( 1 );
+
+    return evid;
+}
+
+
+} // end of namespace dai
index e1c315c..b643758 100644 (file)
 
 #include <iostream>
 #include <fstream>
+#include <cstdlib>
 #include <dai/alldai.h>
-#include <dai/util.h>
-#include <dai/index.h>
-#include <dai/jtree.h>
+#include <dai/io.h>
 
 
 using namespace std;
 using namespace dai;
 
 
-/// Reads "evidence" (a mapping from observed variable labels to the observed values) from a UAI evidence file
-map<size_t, size_t> ReadUAIEvidenceFile( char* filename ) {
-    map<size_t, size_t> evid;
-
-    // open file
-    ifstream is;
-    is.open( filename );
-    if( is.is_open() ) {
-        // read number of observed variables
-        size_t nr_evid;
-        is >> nr_evid;
-        if( is.fail() )
-            DAI_THROWE(INVALID_EVIDENCE_FILE,"Cannot read number of observed variables");
-
-        // for each observation, read the variable label and the observed value
-        for( size_t i = 0; i < nr_evid; i++ ) {
-            size_t label, val;
-            is >> label;
-            if( is.fail() )
-                DAI_THROWE(INVALID_EVIDENCE_FILE,"Cannot read label for " + toString(i) + "'th observed variable");
-            is >> val;
-            if( is.fail() )
-                DAI_THROWE(INVALID_EVIDENCE_FILE,"Cannot read value of " + toString(i) + "'th observed variable");
-            evid[label] = val;
-        }
-
-        // close file
-        is.close();
-    } else
-        DAI_THROWE(CANNOT_READ_FILE,"Cannot read from file " + std::string(filename));
-
-    return evid;
-}
-
-
-/// Reads factor graph (as a pair of a variable vector and factor vector) from a UAI factor graph file
-void ReadUAIFGFile( const char *filename, size_t verbose, vector<Var>& vars, vector<Factor>& factors, vector<Permute>& permutations ) {
-    vars.clear();
-    factors.clear();
-    permutations.clear();
-
-    // open file
-    ifstream is;
-    is.open( filename );
-    if( is.is_open() ) {
-        size_t nrFacs, nrVars;
-        string line;
-        
-        // read header line
-        getline(is,line);
-        if( is.fail() || (line != "BAYES" && line != "MARKOV" && line != "BAYES\r" && line != "MARKOV\r") )
-            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"UAI factor graph file should start with \"BAYES\" or \"MARKOV\"");
-        if( verbose >= 2 )
-            cout << "Reading " << line << " network..." << endl;
-
-        // read number of variables
-        is >> nrVars;
-        if( is.fail() )
-            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of variables");
-        if( verbose >= 2 )
-            cout << "Reading " << nrVars << " variables..." << endl;
-
-        // for each variable, read its number of states
-        vars.reserve( nrVars );
-        for( size_t i = 0; i < nrVars; i++ ) {
-            size_t dim;
-            is >> dim;
-            if( is.fail() )
-                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of states of " + toString(i) + "'th variable");
-            vars.push_back( Var( i, dim ) );
-        }
-
-        // read number of factors
-        is >> nrFacs;
-        if( is.fail() )
-            DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of factors");
-        if( verbose >= 2 )
-            cout << "Reading " << nrFacs << " factors..." << endl;
-
-        // for each factor, read the variables on which it depends
-        vector<vector<Var> > factorVars;
-        factors.reserve( nrFacs );
-        factorVars.reserve( nrFacs );
-        for( size_t I = 0; I < nrFacs; I++ ) {
-            if( verbose >= 3 )
-                cout << "Reading factor " << I << "..." << endl;
-
-            // read number of variables for factor I
-            size_t I_nrVars;
-            is >> I_nrVars;
-            if( is.fail() )
-                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of variables for " + toString(I) + "'th factor");
-            if( verbose >= 3 )
-                cout << "  which depends on " << I_nrVars << " variables" << endl;
-
-            // read the variable labels
-            vector<long> I_labels;
-            vector<size_t> I_dims;
-            I_labels.reserve( I_nrVars );
-            I_dims.reserve( I_nrVars );
-            factorVars[I].reserve( I_nrVars );
-            for( size_t _i = 0; _i < I_nrVars; _i++ ) {
-                long label;
-                is >> label;
-                if( is.fail() )
-                    DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read variable labels for " + toString(I) + "'th factor");
-                I_labels.push_back( label );
-                I_dims.push_back( vars[label].states() );
-                factorVars[I].push_back( vars[label] );
-            }
-            if( verbose >= 3 )
-                cout << "  labels: " << I_labels << ", dimensions " << I_dims << endl;
-
-            // add the factor and the labels
-            factors.push_back( Factor( VarSet( factorVars[I].begin(), factorVars[I].end(), factorVars[I].size() ), (Real)0 ) );
-        }
-
-        // for each factor, read its values
-        permutations.reserve( nrFacs );
-        for( size_t I = 0; I < nrFacs; I++ ) {
-            if( verbose >= 3 )
-                cout << "Reading factor " << I << "..." << endl;
-
-            // calculate permutation object, reversing the indexing in factorVars[I] first
-            Permute permindex( factorVars[I], true );
-            permutations.push_back( permindex );
-
-            // read factor values
-            size_t nrNonZeros;
-            is >> nrNonZeros;
-            if( is.fail() )
-                DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read number of nonzero factor values for " + toString(I) + "'th factor");
-            if( verbose >= 3 ) 
-                cout << "  number of nonzero values: " << nrNonZeros << endl;
-            DAI_ASSERT( nrNonZeros == factors[I].nrStates() );
-            for( size_t li = 0; li < nrNonZeros; li++ ) {
-                Real val;
-                is >> val;
-                if( is.fail() )
-                    DAI_THROWE(INVALID_FACTORGRAPH_FILE,"Cannot read factor values of " + toString(I) + "'th factor");
-                // assign value after calculating its linear index corresponding to the permutation
-                if( verbose >= 4 )
-                    cout << "  " << li << "'th value " << val << " corresponds with index " << permindex.convertLinearIndex(li) << endl;
-                factors[I].set( permindex.convertLinearIndex( li ), val );
-            }
-        }
-        if( verbose >= 3 )
-            cout << "variables:" << vars << endl;
-        if( verbose >= 3 )
-            cout << "factors:" << factors << endl;
-
-        // close file
-        is.close();
-    } else
-        DAI_THROWE(CANNOT_READ_FILE,"Cannot read from file " + std::string(filename));
-}
-
-
 int main( int argc, char *argv[] ) {
-    if ( argc != 7 ) {
+    if ( argc != 4 ) {
         cout << "This program is part of libDAI - http://www.libdai.org/" << endl << endl;
-        cout << "Usage: ./uai2fg <filename.uai> <filename.uai.evid> <filename.fg> <type> <run_jtree> <verbose>" << endl << endl;
-        cout << "Converts input files in the UAI 2008 approximate inference evaluation format" << endl;
-        cout << "(see http://graphmod.ics.uci.edu/uai08/) to the libDAI factor graph format." << endl;
-        cout << "Reads factor graph <filename.uai> and evidence <filename.uai.evid>" << endl;
-        cout << "and writes the resulting clamped factor graph to <filename.fg>." << endl;
-        cout << "If type==0, uses surgery (recommended), otherwise, uses just adds delta factors." << endl;
-        cout << "If run_jtree!=0, runs a junction tree and reports the results in the UAI 2008 results file format." << endl;
+        cout << "Usage: ./uai2fg <basename> <surgery> <verbose>" << endl << endl;
+        cout << "Converts input files in the UAI 2006/2008/2010 approximate inference evaluation format" << endl;
+        cout << "(see http://graphmod.ics.uci.edu/uai08/ and http://www.cs.huji.ac.il/project/UAI10/)" << endl;
+        cout << "to the libDAI factor graph format." << endl << endl;
+        cout << "Reads factor graph <basename.uai> and evidence <basename.uai.evid>" << endl;
+        cout << "and writes the resulting clamped factor graphs to <basename.X.fg>," << endl;
+        cout << "where X=0,1,2,... enumerates the different evidence cases." << endl << endl;
+        cout << "If surgery!=0, uses surgery on the factor graph (recommended)," << endl;
+        cout << "otherwise, just adds delta factors to the factor graph." << endl;
         return 1;
     } else {
-        long verbose = fromString<long>( argv[6] );
-        long type = fromString<long>( argv[4] );
-        bool run_jtree = fromString<bool>( argv[5] );
+        string basename( argv[1] );
+        bool surgery = fromString<size_t>( argv[2] );
+        size_t verbose = fromString<size_t>( argv[3] );
+        string uainame = basename + ".uai";
+        string evidname = uainame + ".evid";
+
+        // output command line options
+        if( verbose ) {
+            cout << "Factorgraph filename: " << uainame << endl;
+            cout << "Evidence filename:    " << evidname << endl;
+            cout << "Output basename:      " << basename << endl;
+            cout << "Surgery:              " << surgery << endl;
+        }
 
         // read factor graph
         vector<Var> vars;
-        vector<Factor> facs;
+        vector<Factor> facs0;
         vector<Permute> permutations;
-        ReadUAIFGFile( argv[1], verbose, vars, facs, permutations );
+        if( verbose )
+            cout << "Reading factor graph..." << endl;
+        ReadUaiAieFactorGraphFile( uainame.c_str(), verbose, vars, facs0, permutations );
+        if( verbose )
+            cout << "Successfully read factor graph" << endl;
 
         // read evidence
-        map<size_t,size_t> evid = ReadUAIEvidenceFile( argv[2] );
-
-        // construct unclamped factor graph
-        FactorGraph fg0( facs.begin(), facs.end(), vars.begin(), vars.end(), facs.size(), vars.size() );
-
-        // change factor graph to reflect observed evidence
-        if( type == 0 ) {
-            // replace factors with clamped variables with slices
-            for( size_t I = 0; I < facs.size(); I++ ) {
-                for( map<size_t,size_t>::const_iterator e = evid.begin(); e != evid.end(); e++ ) {
-                    if( facs[I].vars() >> vars[e->first] ) {
-                        if( verbose >= 2 )
-                            cout << "Clamping " << e->first << " to value " << e->second << " in factor " << I << " = " << facs[I].vars() << endl;
-                        facs[I] = facs[I].slice( vars[e->first], e->second );
-                        if( verbose >= 2 )
-                            cout << "...remaining vars: " << facs[I].vars() << endl;
+        if( verbose )
+            cout << "Reading evidence..." << endl;
+        vector<map<size_t,size_t> > evid = ReadUaiAieEvidenceFile( evidname.c_str(), verbose );
+        if( verbose )
+            cout << "Successfully read " << evid.size() << " evidence cases" << endl;
+
+        // build output file names
+        vector<string> fgnames;
+        fgnames.reserve( evid.size() );
+        for( size_t ev = 0; ev < evid.size(); ev++ )
+            fgnames.push_back( basename + '.' + toString(ev) + ".fg" );
+
+        // construct clamped factor graphs which reflect observed evidence cases
+        if( verbose )
+            cout << "Constructing clamped factor graphs..." << endl;
+        vector<FactorGraph> fgs;
+        fgs.reserve( evid.size() );
+        for( size_t ev = 0; ev < evid.size(); ev++ ) {
+            if( verbose )
+                cout << "  Evidence case " << ev << "..." << endl;
+            // copy vector of factors
+            vector<Factor> facs( facs0 );
+
+            // change factor graph to reflect observed evidence
+            if( verbose )
+                cout << "    Applying evidence..." << endl;
+            if( surgery ) {
+                // replace factors with clamped variables with slices
+                for( size_t I = 0; I < facs.size(); I++ ) {
+                    for( map<size_t,size_t>::const_iterator e = evid[ev].begin(); e != evid[ev].end(); e++ ) {
+                        if( facs[I].vars() >> vars[e->first] ) {
+                            if( verbose >= 2 )
+                                cout << "      Clamping " << e->first << " to value " << e->second << " in factor " << I << " = " << facs[I].vars() << endl;
+                            facs[I] = facs[I].slice( vars[e->first], e->second );
+                            if( verbose >= 2 )
+                                cout << "      ...remaining vars: " << facs[I].vars() << endl;
+                        }
                     }
                 }
+                // remove empty factors
+                Real logZcorr = 0.0;
+                for( vector<Factor>::iterator I = facs.begin(); I != facs.end(); )
+                    if( I->vars().size() == 0 ) {
+                        logZcorr += std::log( (Real)(*I)[0] );
+                        I = facs.erase( I );
+                    } else
+                        I++;
+                // multiply with logZcorr constant
+                if( facs.size() == 0 )
+                    facs.push_back( Factor( VarSet(), std::exp(logZcorr) ) );
+                else
+                    facs.front() *= std::exp(logZcorr);
             }
-            // remove empty factors
-            double logZcorr = 0.0;
-            for( vector<Factor>::iterator I = facs.begin(); I != facs.end(); )
-                if( I->vars().size() == 0 ) {
-                    logZcorr += std::log( (Real)(*I)[0] );
-                    I = facs.erase( I );
-                } else
-                    I++;
-            // multiply with logZcorr constant
-            if( facs.size() == 0 )
-                facs.push_back( Factor( VarSet(), std::exp(logZcorr) ) );
-            else
-                facs.front() *= std::exp(logZcorr);
+            // add delta factors corresponding to observed variable values
+            for( map<size_t,size_t>::const_iterator e = evid[ev].begin(); e != evid[ev].end(); e++ )
+                facs.push_back( createFactorDelta( vars[e->first], e->second ) );
+
+            // construct clamped factor graph
+            if( verbose )
+                cout << "    Constructing factor graph..." << endl;
+            fgs.push_back( FactorGraph( facs.begin(), facs.end(), vars.begin(), vars.end(), facs.size(), vars.size() ) );
+
+            // write it to a file
+            if( verbose )
+                cout << "    Saving factor graph as " << fgnames[ev] << "..." << endl;
+            fgs[ev].WriteToFile( fgnames[ev].c_str() );
         }
-        // add delta factors corresponding to observed variable values
-        for( map<size_t,size_t>::const_iterator e = evid.begin(); e != evid.end(); e++ )
-            facs.push_back( createFactorDelta( vars[e->first], e->second ) );
-
-        // construct clamped factor graph
-        FactorGraph fg( facs.begin(), facs.end(), vars.begin(), vars.end(), facs.size(), vars.size() );
-
-        // write it to a file
-        fg.WriteToFile( argv[3] );
-
-        // if requested, perform various inference tasks
-        if( run_jtree ) {
-            // construct junction tree on unclamped factor graph
-            JTree jt0( fg0, PropertySet()("updates",string("HUGIN")) );
-            jt0.init();
-            jt0.run();
-
-            // construct junction tree on clamped factor graph
-            JTree jt( fg, PropertySet()("updates",string("HUGIN")) );
-            jt.init();
-            jt.run();
 
-            // output probability of evidence
-            cout.precision( 8 );
-            if( evid.size() )
-                cout << "z " << (jt.logZ() - jt0.logZ()) / dai::log((Real)10.0) << endl;
-            else
-                cout << "z " << jt.logZ() / dai::log((Real)10.0) << endl;
-
-            // output variable marginals
-            cout << "m " << jt.nrVars() << " ";
-            for( size_t i = 0; i < jt.nrVars(); i++ ) {
-                cout << jt.var(i).states() << " ";
-                for( size_t s = 0; s < jt.var(i).states(); s++ )
-                    cout << jt.beliefV(i)[s] << " ";
-            }
-            cout << endl;
-
-            // calculate MAP state
-            jt.props.inference = JTree::Properties::InfType::MAXPROD;
-            jt.init();
-            jt.run();
-            vector<size_t> MAP = jt.findMaximum();
-            map<Var, size_t> state;
-            for( size_t i = 0; i < MAP.size(); i++ )
-                state[jt.var(i)] = MAP[i];
-            double log_MAP_prob = 0.0;
-            for( size_t I = 0; I < jt.nrFactors(); I++ )
-                log_MAP_prob += dai::log( jt.factor(I)[calcLinearState( jt.factor(I).vars(), state )] );
-
-            // output MAP state
-            cout << "s ";
-            if( evid.size() )
-                cout << (log_MAP_prob - jt0.logZ()) / dai::log((Real)10.0) << " ";
-            else
-                cout << log_MAP_prob / dai::log((Real)10.0) << " ";
-            cout << jt.nrVars() << " ";
-            for( size_t i = 0; i < jt.nrVars(); i++ )
-                cout << MAP[i] << " ";
-            cout << endl;
-        }
+        if( verbose )
+            cout << "Done!" << endl;
     }
 
     return 0;