table_factor.hpp

00001 /*
00002 This file is part of GraphLab.
00003 
00004 GraphLab is free software: you can redistribute it and/or modify
00005 it under the terms of the GNU Lesser General Public License as 
00006 published by the Free Software Foundation, either version 3 of 
00007 the License, or (at your option) any later version.
00008 
00009 GraphLab is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public 
00015 License along with GraphLab.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #ifndef GRAPHLAB_FACTORS_HPP
00019 #define GRAPHLAB_FACTORS_HPP
00020 
00021 
00022 /**
00023  * This file contains the definitions of some of the basic factor
00024  * types needed for loopy belief propagation.  This is demo code and
00025  * is intentionally kept as simple as possible.
00026  *
00027  *  \author Joseph Gonzalez
00028  */
00029 
00030 
00031 
00032 // INCLUDES ===================================================================>
00033 
00034 // Including Standard Libraries
00035 #include <cassert>
00036 #include <cmath>
00037 
00038 #include <iostream>
00039 #include <algorithm>
00040 #include <limits>
00041 #include <vector>
00042 #include <set>
00043 
00044 
00045 // Random number generation
00046 #include <graphlab/util/random.hpp>
00047 
00048 #include <graphlab/serialization/serialization_includes.hpp>
00049 
00050 #include <graphlab/factors/discrete_variable.hpp>
00051 #include <graphlab/factors/discrete_domain.hpp>
00052 #include <graphlab/factors/discrete_assignment.hpp>
00053 #include <graphlab/factors/fast_discrete_assignment.hpp>
00054 
00055 
00056 
00057 // Include the macro for the for each operation
00058 #include <graphlab/macros_def.hpp>
00059 
00060 namespace graphlab {
00061 
00062 
00063 
00064 
00065 
00066   // static const double EPSILON = std::numeric_limits<double>::min();
00067   // static const double LOG_EPSILON = log(EPSILON);
00068   // static const double MAX_DOUBLE =  std::numeric_limits<double>::max();
00069   //  static const double LOG_MAX_DOUBLE = std::log(MAX_DOUBLE);
00070 
00071 
00072 
00073 
00074   
00075   /**
00076    * A factor over up to max_dim dimensions
00077    */
00078   template<size_t MAX_DIM>
00079   class table_factor {
00080   public:
00081     typedef discrete_variable            variable_type;
00082     typedef discrete_domain<MAX_DIM>     domain_type;
00083     typedef discrete_assignment<MAX_DIM> assignment_type;
00084     
00085 
00086     /** Construct an empty table factor */
00087     table_factor() { }
00088     
00089     /** Construct a table factor over the given domain */
00090     table_factor(const domain_type& dom) :
00091       _args(dom), _data(dom.size()) {  }
00092 
00093     /** Construct a copy */
00094     table_factor(const table_factor& other) :
00095       _args(other._args), _data(other._data) { }
00096 
00097     /** Standard assignment operator */
00098     table_factor& operator=(const table_factor& other) {
00099       _args = other._args;
00100       _data = other._data;
00101       return *this;
00102     }
00103 
00104     void set_args(const domain_type& args) {
00105       _args = args;
00106       _data.resize(args.size());
00107     }
00108     
00109     const domain_type& args() const {
00110       return _args;
00111     }
00112 
00113     const double& logP(size_t index) const {
00114       ASSERT_LT(index, _data.size());
00115       return _data[index];
00116     }
00117     
00118     double& logP(size_t index) {
00119       ASSERT_LT(index, _data.size());
00120       return _data[index];
00121     }
00122 
00123     const double& logP(const assignment_type& asg) const {
00124       if(asg.args() == args()) {
00125         // if the assignment index matches
00126         const size_t index(asg.linear_index());
00127         ASSERT_LT(index, _data.size());
00128         return _data[index];
00129       } else {
00130         // Restrict the assignment to this domain
00131         const assignment_type sub_asg = asg.restrict(_args);
00132         const size_t index(sub_asg.linear_index());
00133         ASSERT_LT(index, _data.size());
00134         return _data[index];
00135       }
00136     }
00137     
00138 
00139     double& logP(const assignment_type& asg) {
00140       if(asg.args() == args()) {
00141         // if the assignment index matches
00142         const size_t index(asg.linear_index());
00143         ASSERT_LT(index, _data.size());
00144         return _data[index];
00145       } else {
00146         // Restrict the assignment to this domain
00147         const assignment_type sub_asg = asg.restrict(_args);
00148         const size_t index(sub_asg.linear_index());
00149         ASSERT_LT(index, _data.size());
00150         return _data[sub_asg.linear_index()];
00151       }
00152     } // end of logP
00153 
00154     size_t size() const { return _args.size(); }
00155 
00156     size_t num_vars() const { return _args.num_vars(); }
00157 
00158     double* begin() { return _data.begin(); }
00159     const double* begin() const { return _data.begin(); }
00160     
00161 
00162     
00163     double* end() { return _data.end(); }
00164     const double* end() const { return _data.end(); }
00165     
00166     void zero() { std::fill(_data.begin(), _data.end(), 0); }
00167         
00168     void uniform() {
00169       std::fill(_data.begin(), _data.end(),
00170                 log(1.0/_data.size()));
00171     }
00172  
00173     void uniform(double value) {
00174       std::fill(_data.begin(), _data.end(), value);
00175     } 
00176 
00177     
00178     //! ensure that sum_x this(x) = 1 
00179     void normalize() {
00180       // Compute the max value
00181       double max_value = logP(0);
00182       for(size_t i = 0; i < _data.size(); ++i) 
00183         max_value = std::max(max_value, _data[i] );
00184       // scale and compute normalizing constant
00185       double Z = 0.0;
00186       for(size_t i = 0; i < _data.size(); ++i)
00187         Z += exp( _data[i] -= max_value );
00188       // assert( !std::isinf(Z) );
00189       // assert( !std::isnan(Z) );
00190       // assert( Z > 0.0);
00191       const double logZ(log(Z));
00192       ASSERT_FALSE( std::isinf(logZ) );
00193       ASSERT_FALSE( std::isnan(logZ) );
00194       // Normalize
00195       for(size_t i = 0; i < _data.size(); ++i) _data[i] -= logZ;
00196     } // End of normalize
00197     
00198 
00199     /** 
00200      * Ensure that the largest value in log form is zero.  This
00201      * prevents overflows on normalization. 
00202      */
00203     void shift_normalize() {
00204       // Compute the max value
00205       double max_value = logP(0);
00206       for(size_t i = 0; i < _data.size(); ++i) 
00207         max_value = std::max(max_value, _data[i]);
00208       for(size_t i = 0; i < _data.size(); ++i) _data[i] -= max_value;
00209     }
00210 
00211 
00212     /**
00213      * Return false if any of the entries are not finite 
00214      */
00215     bool is_finite() { 
00216       for(size_t i = 0; i < _data.size(); ++i) {
00217         const bool is_inf( std::isinf( _data[i] ) );
00218         const bool is_nan( std::isnan( _data[i] ) );
00219         if( __builtin_expect( is_inf || is_nan, 0) ) return false;
00220       }
00221       return true;
00222     }
00223 
00224 
00225     //! this(x) += other(x);
00226     inline table_factor& operator+=(const table_factor& other) {
00227       if(args() == other.args()) {
00228         ASSERT_EQ(_data.size(), other._data.size());
00229         // More verctorizable version
00230         for(size_t i = 0; i < _data.size(); ++i) 
00231           _data[i] = log( exp(_data[i]) + exp(other._data[i]) );
00232       } else { 
00233         for(assignment_type asg = args().begin(); asg < args().end(); ++asg) {
00234           logP(asg.linear_index()) =
00235             log( exp(logP(asg.linear_index())) + exp(other.logP(asg)) );
00236           // ASSERT_FALSE(std::isinf( logP(asg.linear_index()) ));
00237           // ASSERT_FALSE(std::isnan( logP(asg.linear_index()) ));
00238         }
00239       }
00240       return *this;
00241     }
00242 
00243     
00244 
00245     //! this(x) *= other(x);
00246     inline table_factor& operator*=(const table_factor& other) {
00247       if(args() == other.args()) {
00248         ASSERT_EQ(_data.size(), other._data.size());
00249         // More verctorizable version
00250         for(size_t i = 0; i < _data.size(); ++i) _data[i] += other._data[i];
00251       } else {
00252         for(assignment_type asg = args().begin(); asg < args().end(); ++asg) {
00253           logP(asg.linear_index()) += other.logP(asg); 
00254           // ASSERT_FALSE(std::isinf( logP(asg.linear_index()) ));
00255           // ASSERT_FALSE(std::isnan( logP(asg.linear_index()) ));
00256         }
00257       }
00258       return *this;
00259     }
00260 
00261     //! Create a table factor on the fly
00262     table_factor operator*(const table_factor& other) const {
00263       table_factor factor = *this;
00264       return factor *= other;
00265     }
00266 
00267     //! this(x) /= other(x);
00268     inline table_factor& operator/=(const table_factor& other) {
00269       if(args() == other.args()) {
00270         ASSERT_EQ(_data.size(), other._data.size());
00271          // More verctorizable version
00272         for(size_t i = 0; i < _data.size(); ++i) _data[i] -= other._data[i];
00273       } else { 
00274         for(assignment_type asg = args().begin(); asg < args().end(); ++asg) {
00275           logP(asg.linear_index()) -= other.logP(asg);
00276           // ASSERT_FALSE(std::isinf( logP(asg.linear_index()) ));
00277           // ASSERT_FALSE(std::isnan( logP(asg.linear_index()) ));
00278         }
00279       }
00280       return *this;
00281     }
00282 
00283     //! Create a table factor on the fly
00284     table_factor operator/(const table_factor& other) const {
00285       table_factor factor = *this;
00286       return factor /= other;
00287     }
00288 
00289     
00290     // Currently unused
00291     //! this(x) = sum_y joint(x,y) * other(y) 
00292     inline void convolve(const table_factor& joint,
00293                          const table_factor& other) {
00294       // ensure that both factors have the same domain
00295       ASSERT_EQ(args() + other.args(), joint.args());
00296       // Initialize the factor to zero so we can use it as an
00297       // accumulator
00298       uniform(0);
00299       for(assignment_type asg = joint.args().begin();
00300           asg < joint.args().end(); ++asg) {
00301         const double value =
00302           exp(joint.logP(asg.linear_index()) + other.logP(asg));
00303         ASSERT_FALSE(std::isinf( value ));
00304         ASSERT_FALSE(std::isnan( value ));
00305         logP(asg) += value;
00306       }
00307 
00308       for(size_t i = 0; i < _data.size(); ++i) {
00309         double& sum = _data[i];
00310         ASSERT_GE(sum, 0.0);
00311         if(sum == 0) sum = -std::numeric_limits<double>::max();
00312         else sum = log(sum);
00313       }
00314       
00315       // // ensure that both factors have the same domain
00316       // assert(args() + other.args() == joint.args());
00317       // for(assignment_type xasg = args().begin(); 
00318       //     xasg < args().end(); ++xasg) {
00319       //   double sum = 0;
00320       //   for(assignment_type yasg = other.args().begin(); 
00321       //       yasg < other.args().end(); ++yasg) {
00322       //     assignment_type joint_asg = xasg & yasg;
00323       //     sum += std::exp(joint.logP(joint_asg.linear_index()) + 
00324       //                     other.logP(yasg.linear_index()));
00325       //   }
00326       //   assert( !std::isinf(sum) );
00327       //   assert( !std::isnan(sum) );
00328       //   assert(sum >= 0.0);
00329       //   if(sum == 0) logP(xasg.linear_index()) = -std::numeric_limits<double>::max();
00330       //   else logP(xasg.linear_index()) = std::log(sum);
00331       // }
00332     }
00333     
00334 
00335     //! this(x) = other(x, y = asg) 
00336 //     inline void condition(const table_factor& other,
00337 //                           const assignment_type& asg) {
00338 //       assert(args() == other.args() - asg.args());
00339 //       for(assignment_type xasg = args().begin(); 
00340 //           xasg < args().end(); ++xasg) {
00341 //         assignment_type joint = xasg & asg;
00342 //         assert(joint.args() == other.args());
00343 //         logP(xasg.linear_index()) = other.logP(joint.linear_index());        
00344 //       }
00345 //     }
00346 
00347 
00348 
00349 
00350     //! this(x) = other(x, y = asg) 
00351     inline void condition(const table_factor& other,
00352                           const assignment_type& asg) {
00353       ASSERT_EQ(args(), other.args() - asg.args());
00354       
00355       // create a fast assignment starting from the '0' assignment
00356       // of args() and the conditioning assignment of asg
00357       fast_discrete_assignment<MAX_DIM> fastyasg(args().begin() & asg);
00358       // transpose the remaining assignments to the start
00359       fastyasg.transpose_to_start(args());
00360       
00361       for(assignment_type xasg = args().begin(); 
00362           xasg < args().end(); ++xasg) {
00363         logP(xasg.linear_index()) = other.logP(fastyasg.linear_index());        
00364         ++fastyasg;
00365       }
00366     }
00367 
00368 
00369 
00370 //     inline void times_condition(const table_factor& other,
00371 //                                 const assignment_type& asg) {
00372 //       //      assert(args() == other.args() - asg.args());
00373 //       if(asg.num_vars() == 0) {
00374 //         *this *= other;
00375 //       } else {
00376 //         for(assignment_type xasg = args().begin(); 
00377 //             xasg < args().end(); ++xasg) {
00378 //           assignment_type joint = xasg & asg;
00379 //           assert(joint.args() == other.args());
00380 //           logP(xasg.linear_index()) += other.logP(joint.linear_index());        
00381 //         }
00382 //       }
00383 //     }
00384 
00385 
00386     //! this(x) = this(x) other(x, y = asg) 
00387     inline void times_condition(const table_factor& other,
00388                                 const assignment_type& asg) {
00389       //      assert(args() == other.args() - asg.args());
00390       
00391       // create a fast assignment starting from the '0' assignment
00392       // of args() and the conditioning assignment of asg
00393       fast_discrete_assignment<MAX_DIM> fastyasg(args().begin() & asg);
00394       // transpose the remaining assignments to the start
00395       fastyasg.transpose_to_start(args());
00396       if(asg.num_vars() == 0) {
00397         *this *= other;
00398       } else {
00399         for(assignment_type xasg = args().begin(); 
00400             xasg < args().end(); ++xasg) {
00401           logP(xasg.linear_index()) += other.logP(fastyasg.linear_index());        
00402           ++fastyasg;
00403         }
00404       }
00405     }
00406    
00407     //! this(x) = sum_y joint(x,y) 
00408 //     inline void marginalize(const table_factor& joint) {
00409 //       // No need to marginalize
00410 //       if(args() == joint.args()) {
00411 //         // Just copy and return
00412 //         *this = joint;
00413 //         return;
00414 //       }
00415 //       // Compute the domain to remove
00416 //       domain_type ydom = joint.args() - args();
00417 //       assert(ydom.num_vars() > 0);
00418 //       
00419 //       // Loop over x
00420 //       for(assignment_type xasg = args().begin(); 
00421 //           xasg < args().end(); ++xasg) {
00422 //         double sum = 0;
00423 //         for(assignment_type yasg = ydom.begin(); 
00424 //             yasg < ydom.end(); ++yasg) {
00425 //           assignment_type joint_asg = xasg & yasg;
00426 //           sum += exp(joint.logP(joint_asg.linear_index()));
00427 //         }
00428 //         assert( !std::isinf(sum) );
00429 //         assert( !std::isnan(sum) );
00430 //         assert(sum >= 0.0);
00431 //         if(sum == 0) 
00432 //           logP(xasg.linear_index()) = -std::numeric_limits<double>::max();
00433 //         else logP(xasg.linear_index()) = log(sum);
00434 //       }
00435 //     }
00436 
00437    
00438     //! this(x) = sum_y joint(x,y) 
00439     inline void marginalize(const table_factor& joint) {
00440       // No need to marginalize
00441       if(args() == joint.args()) {
00442         // Just copy and return
00443         *this = joint;
00444         return;
00445       }
00446       // Compute the domain to remove
00447       domain_type ydom = joint.args() - args();
00448       ASSERT_GT(ydom.num_vars(), 0);
00449       
00450       fast_discrete_assignment<MAX_DIM> fastyasg(joint.args());
00451       fastyasg.transpose_to_start(ydom);
00452       // count the number of elements in ydom
00453       size_t numel = 1;
00454       for (size_t i = 0;i < ydom.num_vars(); ++i) {
00455         numel *= ydom.var(i).size();
00456       }
00457       // Loop over x
00458       for(assignment_type xasg = args().begin(); 
00459           xasg < args().end(); ++xasg) {
00460         double sum = 0;
00461         for(size_t i = 0;i < numel; ++i) {
00462           sum += exp(joint.logP(fastyasg.linear_index()));
00463           ++fastyasg;
00464         }
00465         ASSERT_FALSE( std::isinf(sum) );
00466         ASSERT_FALSE( std::isnan(sum) );
00467         ASSERT_GE(sum, 0.0);
00468         if(sum == 0) 
00469           logP(xasg.linear_index()) = -std::numeric_limits<double>::max();
00470         else logP(xasg.linear_index()) = log(sum);
00471       }
00472     }
00473     
00474 
00475     //! This = other * damping + this * (1-damping) 
00476     inline void damp(const table_factor& other, double damping) {
00477       // This factor must be over the same dimensions as the other
00478       // factor
00479       if(damping == 0) return;
00480       ASSERT_EQ(args(), other.args());  
00481       ASSERT_GT(damping, 0.0);
00482       ASSERT_LT(damping, 1.0);
00483       for(size_t i = 0; i < args().size(); ++i) {
00484         double val = damping * exp(other.logP(i)) + 
00485           (1-damping) * exp(logP(i));
00486         ASSERT_GE(val, 0);
00487         if(val == 0) logP(i) = -std::numeric_limits<double>::max();
00488         else logP(i) = log(val);
00489         ASSERT_FALSE( std::isinf(logP(i)) );
00490         ASSERT_FALSE( std::isnan(logP(i)) );
00491       }
00492     }
00493 
00494 
00495     //! compute the average l1 norm between to factors
00496     inline double l1_diff(const table_factor& other) const {
00497       // This factor must be over the same dimensions as the other
00498       // factor
00499       ASSERT_EQ(args(), other.args());  
00500       double sum = 0;
00501       for(size_t i = 0; i < args().size(); ++i) {
00502         sum += fabs(exp(other.logP(i)) - exp(logP(i)));
00503       }
00504       return sum / args().size();
00505     }
00506 
00507 
00508     //! compute the l1 norm in log space
00509     inline double l1_logdiff(const table_factor& other) const {
00510       ASSERT_EQ(args(), other.args());
00511       double sum = 0; 
00512       for(size_t i = 0; i < args().size(); ++i) {
00513         sum += fabs(other.logP(i) - logP(i));
00514       }
00515       return sum / args().size();
00516     }
00517 
00518 
00519     inline assignment_type max_asg() const {
00520       assignment_type max_asg = args().begin();
00521       double max_value = logP(max_asg.linear_index());
00522       for(assignment_type asg = args().begin(); 
00523           asg < args().end(); ++asg) {
00524         if(logP(asg.linear_index()) > max_value) {
00525           max_value = logP(asg.linear_index());
00526           max_asg = asg;
00527         }
00528       }
00529       return max_asg;
00530     }
00531 
00532     /**
00533      * Compute the expectation of the table factor
00534      */
00535     inline void expectation(std::vector<double>& values) const {
00536       values.clear();
00537       values.resize(num_vars(), 0);
00538       double sum = 0;
00539       for(assignment_type asg = args().begin(); 
00540           asg < args().end(); ++asg) {
00541         const double scale = exp(logP(asg.linear_index()));
00542         sum += scale;
00543         for(size_t i = 0; i < num_vars(); ++i) {
00544           values[i] += asg.asg_at(i) * scale;
00545         }
00546       }
00547       // Rescale for normalization
00548       for(size_t i = 0; i < num_vars(); ++i)  values[i] /= sum;
00549     } // end of expectation
00550 
00551 
00552     /**
00553      * Draw a sample from the table factor
00554      */
00555     inline assignment_type sample() const {
00556       ASSERT_GT(size(), 0);
00557       // This factor must be normalized
00558       const double t = random::rand01();
00559       ASSERT_GE( t, 0 );
00560       ASSERT_LT( t, 1 );
00561       double sum = 0;
00562       for(size_t i = 0; i < _data.size(); ++i) {
00563         sum += exp(  logP(i)  );
00564         if(t <= sum) return assignment_type(args(), i) ;
00565         ASSERT_LT(sum, 1);
00566       }
00567       // Unreachable
00568       throw("Invalid state reached in sample()");
00569       return assignment_type();
00570     } // end of sample
00571     
00572     /**
00573      * Construct a binary agreement factor
00574      */
00575     void set_as_agreement(double lambda) {
00576       ASSERT_EQ(num_vars(), 2);
00577       for(assignment_type asg = args().begin(); 
00578           asg < args().end(); ++asg) {
00579         const int diff = abs( int(asg.asg(0)) - int(asg.asg(1)) );
00580         if( diff > 0) logP(asg.linear_index()) = -lambda;
00581         else logP(asg.linear_index()) = 0;
00582       }
00583     } // end of set_as_agreement
00584     
00585 
00586 
00587     void set_as_laplace(double lambda) {
00588       ASSERT_EQ(num_vars(), 2);
00589       for(assignment_type asg = args().begin(); 
00590           asg < args().end(); ++asg) {
00591         const int diff = abs( int(asg.asg_at(0)) - int(asg.asg_at(1)) );
00592         logP(asg.linear_index()) = -diff * lambda;
00593       }
00594     } // end of set_as_laplace
00595 
00596     void load(iarchive& arc) {
00597       arc >> _args;
00598       arc >> _data;      
00599     }
00600 
00601     void save(oarchive& arc) const {
00602       arc << _args;
00603       arc << _data;      
00604     }
00605     
00606   private:
00607     domain_type _args;
00608     std::vector<double> _data;
00609   };  // End of unary factor
00610 
00611   
00612 }; // end of graphlab namespace
00613 
00614 
00615 
00616 
00617 
00618 
00619 
00620 template<size_t MAX_DIM>
00621 std::ostream& operator<<(std::ostream& out,
00622                          const graphlab::table_factor<MAX_DIM>& factor) {
00623   typedef graphlab::table_factor<MAX_DIM> factor_type;
00624   typedef typename factor_type::assignment_type assignment_type;
00625   out << "Table Factor: " << factor.args() << "{" << std::endl;
00626   for(assignment_type asg = factor.args().begin();
00627       asg < factor.args().end(); ++asg) {
00628     out << "\tLogP(" << asg << ")=" << factor.logP(asg) << std::endl;
00629   }
00630   return out << "}";
00631 }
00632 
00633 
00634 
00635 
00636 
00637 #include <graphlab/macros_undef.hpp>
00638 #endif
00639 
00640 
00641 
00642 
00643 
00644 
00645