Improved tokenizeString
[libdai.git] / include / dai / util.h
index 480c3ef..b1378be 100644 (file)
@@ -4,14 +4,13 @@
  *  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
  */
 
 
 /// \file
 /// \brief Defines general utility functions and adds an abstraction layer for platform-dependent functionality
-/// \todo Improve documentation
 
 
 #ifndef __defined_libdai_util_h
 #include <iostream>
 #include <boost/foreach.hpp>
 #include <boost/functional/hash.hpp>
+#include <boost/lexical_cast.hpp>
 #include <algorithm>
+#include <cerrno>
+
+#include <dai/exceptions.h>
 
 
 #if defined(WINDOWS)
-    #include <map>
+    #include <boost/tr1/unordered_map.hpp> // only present in boost 1.37 and higher
 #elif defined(CYGWIN)
-    #include <boost/tr1/unordered_map.hpp>
+    #include <boost/tr1/unordered_map.hpp> // only present in boost 1.37 and higher
+#elif defined(MACOSX)
+    #include <boost/tr1/unordered_map.hpp> // only present in boost 1.37 and higher
 #else
-    #include <tr1/unordered_map>
+    #include <tr1/unordered_map> // only present in modern GCC distributions
 #endif
 
 
 #define DAI_DMSG(str) do {} while(0)
 #endif
 
-/// Produces accessor and mutator methods according to the common pattern.
-/** Example:
- *  \code DAI_ACCMUT(size_t& maxIter(), { return props.maxiter; }); \endcode
- *  \todo At the moment, only the mutator appears in doxygen documentation.
- */
-#define DAI_ACCMUT(x,y)                     \
-      x y;                                  \
-      const x const y;
-
-/// Macro to give error message \a stmt if props.verbose>=\a n
-#define DAI_IFVERB(n, stmt) if(props.verbose>=n) { cerr << stmt; }
+/// Macro to write message \a stmt to \c std::cerr if \a props.verbose >= \a n
+#define DAI_IFVERB(n, stmt) if(props.verbose>=n) { std::cerr << stmt; }
 
 
 #ifdef WINDOWS
-    /// Returns true if argument is NAN (Not A Number)
-    bool isnan( double x );
-
     /// Returns inverse hyperbolic tangent of argument
     double atanh( double x );
 
     double log1p( double x );
 
     /// Define INFINITY
-    #define INFINITY (std::numeric_limits<double>::infinity())
+    #define INFINITY (std::numeric_limits<Real>::infinity())
 #endif
 
 
 namespace dai {
 
 
-/// Real number (alias for double, which could be changed to long double if necessary)
+/// Real number (alias for \c double, which could be changed to <tt>long double</tt> if necessary)
 typedef double Real;
 
+/// Returns true if argument is NAN (Not A Number)
+bool isnan( Real x );
+
 /// Returns logarithm of \a x
 inline Real log( Real x ) {
     return std::log(x);
 }
 
+/// Returns logarithm of \a x, or 0 if \a x == 0
+inline Real log0( Real x ) {
+    return x ? std::log(x) : 0;
+}
+
 /// Returns exponent of \a x
 inline Real exp( Real x ) {
     return std::exp(x);
 }
 
+/// Returns \a to the power \a y
+inline Real pow( Real x, Real y ) {
+    errno = 0;
+    Real result = std::pow(x, y);
+    DAI_DEBASSERT( errno == 0 );
+    return result;
+}
+
 
-#ifdef WINDOWS
-    /// hash_map is an alias for std::map.
-    /** Since there is no TR1 unordered_map implementation available yet, we fall back on std::map.
-     */
-    template <typename T, typename U, typename H = boost::hash<T> >
-        class hash_map : public std::map<T,U> {};
-#else
-    /// hash_map is an alias for std::tr1::unordered_map.
-    /** We use the (experimental) TR1 unordered_map implementation included in modern GCC distributions.
-     */
-    template <typename T, typename U, typename H = boost::hash<T> >
-        class hash_map : public std::tr1::unordered_map<T,U,H> {};
-#endif
+/// hash_map is an alias for \c std::tr1::unordered_map.
+/** We use the (experimental) TR1 unordered_map implementation included in modern GCC distributions or in boost versions 1.37 and higher.
+ */
+template <typename T, typename U, typename H = boost::hash<T> >
+    class hash_map : public std::tr1::unordered_map<T,U,H> {};
 
 
 /// Returns wall clock time in seconds
@@ -135,16 +136,30 @@ Real rnd_uniform();
 /// Returns a real number from a standard-normal distribution
 Real rnd_stdnormal();
 
-/// Returns a random integer in interval [min, max]
+/// Returns a random integer in interval [\a min, \a max]
 int rnd_int( int min, int max );
 
-/// Returns a random integer in the half-open interval \f$[0,n)\f$
-inline int rnd( int n) {
+/// Returns a random integer in the half-open interval [0, \a n)
+inline int rnd( int n ) {
     return rnd_int( 0, n-1 );
 }
 
 
-/// Writes a std::vector to a std::ostream
+/// Converts a variable of type \a T to a \c std::string by using a \c boost::lexical_cast
+template<class T>
+std::string toString( const T& x ) {
+    return boost::lexical_cast<std::string>(x);
+}
+
+
+/// Converts a variable of type std::string to \a T by using a \c boost::lexical_cast
+template<class T>
+T fromString( const std::string& x ) {
+    return boost::lexical_cast<T>(x);
+}
+
+
+/// Writes a \c std::vector<> to a \c std::ostream
 template<class T>
 std::ostream& operator << (std::ostream& os, const std::vector<T> & x) {
     os << "(";
@@ -154,17 +169,17 @@ std::ostream& operator << (std::ostream& os, const std::vector<T> & x) {
     return os;
 }
 
-/// Writes a std::set to a std::ostream
+/// Writes a \c std::set<> to a \c std::ostream
 template<class T>
 std::ostream& operator << (std::ostream& os, const std::set<T> & x) {
     os << "{";
-   for( typename std::set<T>::const_iterator it = x.begin(); it != x.end(); it++ )
+    for( typename std::set<T>::const_iterator it = x.begin(); it != x.end(); it++ )
         os << (it != x.begin() ? ", " : "") << *it;
     os << "}";
     return os;
 }
 
-/// Writes a std::map to a std::ostream
+/// Writes a \c std::map<> to a \c std::ostream
 template<class T1, class T2>
 std::ostream& operator << (std::ostream& os, const std::map<T1,T2> & x) {
     os << "{";
@@ -174,14 +189,14 @@ std::ostream& operator << (std::ostream& os, const std::map<T1,T2> & x) {
     return os;
 }
 
-/// Writes a std::pair to a std::ostream
+/// Writes a \c std::pair<> to a \c std::ostream
 template<class T1, class T2>
 std::ostream& operator << (std::ostream& os, const std::pair<T1,T2> & x) {
     os << "(" << x.first << ", " << x.second << ")";
     return os;
 }
 
-/// Concatenate two vectors
+/// Concatenates two vectors
 template<class T>
 std::vector<T> concat( const std::vector<T>& u, const std::vector<T>& v ) {
     std::vector<T> w;
@@ -193,59 +208,37 @@ std::vector<T> concat( const std::vector<T>& u, const std::vector<T>& v ) {
     return w;
 }
 
-/// Split a string into tokens
+/// Split a string into tokens delimited by one of the characters in \a delim
+/** \param s the string to be split into tokens
+ *  \param singleDelim if \c true, any single delimiter forms a boundary between two tokens; 
+ *         if \c false, a maximal group of consecutive delimiters forms a boundary between two tokens
+ *  \param delim delimiter characters
+ */
+std::vector<std::string> tokenizeString( const std::string& s, bool singleDelim, const std::string& delim="\t\n" );
+
+
+/// Split a string into tokens delimited by one of the characters in \a delim
+/** \deprecated Please use dai::tokenizeString( const std::string&, bool, const std::string& ) instead
+ */
 void tokenizeString( const std::string& s, std::vector<std::string>& outTokens, const std::string& delim="\t\n" );
 
-/// Used to keep track of the progress made by iterative algorithms
-class Diffs : public std::vector<double> {
-    private:
-        size_t _maxsize;
-        double _def;
-        std::vector<double>::iterator _pos;
-        std::vector<double>::iterator _maxpos;
-    public:
-        /// Constructor
-        Diffs(long maxsize, double def) : std::vector<double>(), _maxsize(maxsize), _def(def) {
-            this->reserve(_maxsize);
-            _pos = begin();
-            _maxpos = begin();
-        }
-        /// Returns maximum difference encountered
-        double maxDiff() {
-            if( size() < _maxsize )
-                return _def;
-            else
-                return( *_maxpos );
-        }
-        /// Register new difference x
-        void push(double x) {
-            if( size() < _maxsize ) {
-                push_back(x);
-                _pos = end();
-                if( size() > 1 ) {
-                    if( *_maxpos < back() ) {
-                        _maxpos = end();
-                        _maxpos--;
-                    }
-                } else {
-                    _maxpos = begin();
-                }
-            } else {
-                if( _pos == end() )
-                    _pos = begin();
-                if( _maxpos == _pos ) {
-                    *_pos++ = x;
-                    _maxpos = max_element(begin(),end());
-                } else {
-                    if( x > *_maxpos )
-                        _maxpos = _pos;
-                    *_pos++ = x;
-                }
-            }
-        }
-        /// Return maximum number of differences stored
-        size_t maxSize() { return _maxsize; }
-};
+
+/// Enumerates different ways of normalizing a probability measure.
+/**
+ *  - NORMPROB means that the sum of all entries should be 1;
+ *  - NORMLINF means that the maximum absolute value of all entries should be 1.
+ */
+typedef enum { NORMPROB, NORMLINF } ProbNormType;
+
+/// Enumerates different distance measures between probability measures.
+/**
+ *  - DISTL1 is the \f$\ell_1\f$ distance (sum of absolute values of pointwise difference);
+ *  - DISTLINF is the \f$\ell_\infty\f$ distance (maximum absolute value of pointwise difference);
+ *  - DISTTV is the total variation distance (half of the \f$\ell_1\f$ distance);
+ *  - DISTKL is the Kullback-Leibler distance (\f$\sum_i p_i (\log p_i - \log q_i)\f$).
+ *  - DISTHEL is the Hellinger distance (\f$\frac{1}{2}\sum_i (\sqrt{p_i}-\sqrt{q_i})^2\f$).
+ */
+typedef enum { DISTL1, DISTLINF, DISTTV, DISTKL, DISTHEL } ProbDistType;
 
 
 } // end of namespace dai