1 /* This file is part of libDAI - http://www.libdai.org/
3 * libDAI is licensed under the terms of the GNU General Public License version
4 * 2, or (at your option) any later version. libDAI is distributed without any
5 * warranty. See the file COPYING for more details.
7 * Copyright (C) 2006-2009 Joris Mooij [joris dot mooij at libdai dot org]
8 * Copyright (C) 2006-2007 Radboud University Nijmegen, The Netherlands
13 /// \brief Defines TProb<T> and Prob classes
14 /// \todo Rename to Vector<T>
17 #ifndef __defined_libdai_prob_h
18 #define __defined_libdai_prob_h
28 #include <dai/exceptions.h>
34 /// Represents a vector with entries of type \a T.
35 /** A TProb<T> is a std::vector<T> with an interface designed for dealing with probability mass functions.
36 * It is mainly used for representing measures on a finite outcome space, e.g., the probability
37 * distribution of a discrete random variable.
38 * \tparam T Should be a scalar that is castable from and to double and should support elementary arithmetic operations.
40 template <typename T
> class TProb
{
46 /// Iterator over entries
47 typedef typename
std::vector
<T
>::iterator iterator
;
48 /// Const iterator over entries
49 typedef typename
std::vector
<T
>::const_iterator const_iterator
;
51 /// Enumerates different ways of normalizing a probability measure.
53 * - NORMPROB means that the sum of all entries should be 1;
54 * - NORMLINF means that the maximum absolute value of all entries should be 1.
56 typedef enum { NORMPROB
, NORMLINF
} NormType
;
57 /// Enumerates different distance measures between probability measures.
59 * - DISTL1 is the L-1 distance (sum of absolute values of pointwise difference);
60 * - DISTLINF is the L-inf distance (maximum absolute value of pointwise difference);
61 * - DISTTV is the Total Variation distance;
62 * - DISTKL is the Kullback-Leibler distance.
64 typedef enum { DISTL1
, DISTLINF
, DISTTV
, DISTKL
} DistType
;
66 /// Default constructor
69 /// Construct uniform distribution over n outcomes, i.e., a vector of length n with each entry set to 1/n
70 explicit TProb( size_t n
) : _p(std::vector
<T
>(n
, 1.0 / n
)) {}
72 /// Construct vector of length n with each entry set to p
73 explicit TProb( size_t n
, Real p
) : _p(n
, (T
)p
) {}
75 /// Construct vector from a range
76 /** \tparam Iterator Iterates over instances that can be cast to T.
77 * \param begin Points to first instance to be added.
78 * \param end Points just beyond last instance to be added.
79 * \param sizeHint For efficiency, the number of entries can be speficied by sizeHint.
81 template <typename Iterator
>
82 TProb( Iterator begin
, Iterator end
, size_t sizeHint
=0 ) : _p() {
83 _p
.reserve( sizeHint
);
84 _p
.insert( _p
.begin(), begin
, end
);
87 /// Construct vector from a vector
88 /** \tparam S type of elements in v
89 * \param v vector used for initialization
92 TProb( const std::vector
<S
> &v
) : _p() {
93 _p
.reserve( v
.size() );
94 _p
.insert( _p
.begin(), v
.begin(), v
.end() );
97 /// Returns a const reference to the vector
98 const std::vector
<T
> & p() const { return _p
; }
100 /// Returns a reference to the vector
101 std::vector
<T
> & p() { return _p
; }
103 /// Returns a copy of the i'th entry
104 T
operator[]( size_t i
) const {
112 /// Returns reference to the i'th entry
113 T
& operator[]( size_t i
) { return _p
[i
]; }
115 /// Returns iterator pointing to first entry
116 iterator
begin() { return _p
.begin(); }
118 /// Returns const iterator pointing to first entry
119 const_iterator
begin() const { return _p
.begin(); }
121 /// Returns iterator pointing beyond last entry
122 iterator
end() { return _p
.end(); }
124 /// Returns const iterator pointing beyond last entry
125 const_iterator
end() const { return _p
.end(); }
127 /// Sets all entries to x
128 TProb
<T
> & fill(T x
) {
129 std::fill( _p
.begin(), _p
.end(), x
);
133 /// Draws all entries i.i.d. from a uniform distribution on [0,1)
134 TProb
<T
> & randomize() {
135 std::generate(_p
.begin(), _p
.end(), rnd_uniform
);
139 /// Returns length of the vector, i.e., the number of entries
140 size_t size() const {
144 /// Sets entries that are smaller than epsilon to 0
145 TProb
<T
>& makeZero( Real epsilon
) {
146 for( size_t i
= 0; i
< size(); i
++ )
147 if( fabs(_p
[i
]) < epsilon
)
152 /// Set all entries to 1.0/size()
153 TProb
<T
>& setUniform () {
158 /// Sets entries that are smaller than epsilon to epsilon
159 TProb
<T
>& makePositive( Real epsilon
) {
160 for( size_t i
= 0; i
< size(); i
++ )
161 if( (0 < (Real
)_p
[i
]) && ((Real
)_p
[i
] < epsilon
) )
166 /// Multiplies each entry with scalar x
167 TProb
<T
>& operator*= (T x
) {
168 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::bind2nd( std::multiplies
<T
>(), x
) );
172 /// Returns product of *this with scalar x
173 TProb
<T
> operator* (T x
) const {
174 TProb
<T
> prod( *this );
179 /// Divides each entry by scalar x
180 TProb
<T
>& operator/= (T x
) {
181 DAI_DEBASSERT( x
!= 0.0 );
182 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::bind2nd( std::divides
<T
>(), x
) );
186 /// Returns quotient of *this and scalar x
187 TProb
<T
> operator/ (T x
) const {
188 TProb
<T
> quot( *this );
193 /// Adds scalar x to each entry
194 TProb
<T
>& operator+= (T x
) {
195 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::bind2nd( std::plus
<T
>(), x
) );
199 /// Returns sum of *this and scalar x
200 TProb
<T
> operator+ (T x
) const {
201 TProb
<T
> sum( *this );
206 /// Subtracts scalar x from each entry
207 TProb
<T
>& operator-= (T x
) {
208 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::bind2nd( std::minus
<T
>(), x
) );
212 /// Returns difference of *this and scalar x
213 TProb
<T
> operator- (T x
) const {
214 TProb
<T
> diff( *this );
219 /// Lexicographical comparison (sizes should be identical)
220 bool operator<= (const TProb
<T
> & q
) const {
221 DAI_DEBASSERT( size() == q
.size() );
222 for( size_t i
= 0; i
< size(); i
++ )
223 if( !(_p
[i
] <= q
[i
]) )
228 /// Pointwise multiplication with q (sizes should be identical)
229 TProb
<T
>& operator*= (const TProb
<T
> & q
) {
230 DAI_DEBASSERT( size() == q
.size() );
231 std::transform( _p
.begin(), _p
.end(), q
._p
.begin(), _p
.begin(), std::multiplies
<T
>() );
235 /// Return product of *this with q (sizes should be identical)
236 TProb
<T
> operator* (const TProb
<T
> & q
) const {
237 DAI_DEBASSERT( size() == q
.size() );
238 TProb
<T
> prod( *this );
243 /// Pointwise addition with q (sizes should be identical)
244 TProb
<T
>& operator+= (const TProb
<T
> & q
) {
245 DAI_DEBASSERT( size() == q
.size() );
246 std::transform( _p
.begin(), _p
.end(), q
._p
.begin(), _p
.begin(), std::plus
<T
>() );
250 /// Returns sum of *this and q (sizes should be identical)
251 TProb
<T
> operator+ (const TProb
<T
> & q
) const {
252 DAI_DEBASSERT( size() == q
.size() );
253 TProb
<T
> sum( *this );
258 /// Pointwise subtraction of q (sizes should be identical)
259 TProb
<T
>& operator-= (const TProb
<T
> & q
) {
260 DAI_DEBASSERT( size() == q
.size() );
261 std::transform( _p
.begin(), _p
.end(), q
._p
.begin(), _p
.begin(), std::minus
<T
>() );
265 /// Return *this minus q (sizes should be identical)
266 TProb
<T
> operator- (const TProb
<T
> & q
) const {
267 DAI_DEBASSERT( size() == q
.size() );
268 TProb
<T
> diff( *this );
273 /// Pointwise division by q, where division by 0 yields 0 (sizes should be identical)
274 TProb
<T
>& operator/= (const TProb
<T
> & q
) {
275 DAI_DEBASSERT( size() == q
.size() );
276 for( size_t i
= 0; i
< size(); i
++ ) {
285 /// Pointwise division by q, where division by 0 yields +Inf (sizes should be identical)
286 TProb
<T
>& divide (const TProb
<T
> & q
) {
287 DAI_DEBASSERT( size() == q
.size() );
288 std::transform( _p
.begin(), _p
.end(), q
._p
.begin(), _p
.begin(), std::divides
<T
>() );
292 /// Returns quotient of *this with q (sizes should be identical)
293 TProb
<T
> operator/ (const TProb
<T
> & q
) const {
294 DAI_DEBASSERT( size() == q
.size() );
295 TProb
<T
> quot( *this );
300 /// Returns pointwise inverse
301 /** If zero==true; uses 1/0==0, otherwise 1/0==Inf.
303 TProb
<T
> inverse(bool zero
=true) const {
305 inv
._p
.reserve( size() );
307 for( size_t i
= 0; i
< size(); i
++ )
308 inv
._p
.push_back( _p
[i
] == 0.0 ? 0.0 : 1.0 / _p
[i
] );
310 for( size_t i
= 0; i
< size(); i
++ )
311 inv
._p
.push_back( 1.0 / _p
[i
] );
315 /// Raises entries to the power a
316 TProb
<T
>& operator^= (Real a
) {
318 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::bind2nd( std::ptr_fun
<T
, Real
, T
>(std::pow
), a
) );
322 /// Returns *this raised to the power a
323 TProb
<T
> operator^ (Real a
) const {
324 TProb
<T
> power(*this);
329 /// Returns pointwise signum
330 TProb
<T
> sgn() const {
332 x
._p
.reserve( size() );
333 for( size_t i
= 0; i
< size(); i
++ ) {
344 /// Returns pointwise absolute value
345 TProb
<T
> abs() const {
347 x
._p
.reserve( size() );
348 for( size_t i
= 0; i
< size(); i
++ )
349 x
._p
.push_back( _p
[i
] < 0 ? (-_p
[i
]) : _p
[i
] );
353 /// Applies exp pointwise
354 const TProb
<T
>& takeExp() {
355 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::ptr_fun
<T
, T
>(std::exp
) );
359 /// Applies log pointwise
360 /** If zero==true, uses log(0)==0; otherwise, log(0)==-Inf.
362 const TProb
<T
>& takeLog(bool zero
=false) {
364 for( size_t i
= 0; i
< size(); i
++ )
365 _p
[i
] = ( (_p
[i
] == 0.0) ? 0.0 : std::log( _p
[i
] ) );
367 std::transform( _p
.begin(), _p
.end(), _p
.begin(), std::ptr_fun
<T
, T
>(std::log
) );
371 /// Returns pointwise exp
372 TProb
<T
> exp() const {
378 /// Returns pointwise log
379 /** If zero==true, uses log(0)==0; otherwise, log(0)==-Inf.
381 TProb
<T
> log(bool zero
=false) const {
387 /// Returns sum of all entries
389 T Z
= std::accumulate( _p
.begin(), _p
.end(), (T
)0 );
393 /// Return sum of absolute value of all entries
396 for( size_t i
= 0; i
< size(); i
++ )
397 s
+= fabs( (Real
) _p
[i
] );
401 /// Returns maximum absolute value of all entries
404 for( size_t i
= 0; i
< size(); i
++ ) {
405 Real mag
= fabs( (Real
) _p
[i
] );
412 /// Returns maximum value of all entries
414 T Z
= *std::max_element( _p
.begin(), _p
.end() );
418 /// Returns minimum value of all entries
420 T Z
= *std::min_element( _p
.begin(), _p
.end() );
424 /// Returns {arg,}maximum value
425 std::pair
<size_t,T
> argmax() const {
428 for( size_t i
= 1; i
< size(); i
++ ) {
434 return std::make_pair(arg
,max
);
437 /// Normalizes vector using the specified norm
438 T
normalize( NormType norm
=NORMPROB
) {
440 if( norm
== NORMPROB
)
442 else if( norm
== NORMLINF
)
445 DAI_THROW(NOT_NORMALIZABLE
);
451 /// Returns normalized copy of *this, using the specified norm
452 TProb
<T
> normalized( NormType norm
= NORMPROB
) const {
453 TProb
<T
> result(*this);
454 result
.normalize( norm
);
458 /// Returns true if one or more entries are NaN
459 bool hasNaNs() const {
460 bool foundnan
= false;
461 for( typename
std::vector
<T
>::const_iterator x
= _p
.begin(); x
!= _p
.end(); x
++ )
469 /// Returns true if one or more entries are negative
470 bool hasNegatives() const {
471 return (std::find_if( _p
.begin(), _p
.end(), std::bind2nd( std::less
<Real
>(), 0.0 ) ) != _p
.end());
474 /// Returns entropy of *this
475 Real
entropy() const {
477 for( size_t i
= 0; i
< size(); i
++ )
478 S
-= (_p
[i
] == 0 ? 0 : _p
[i
] * std::log(_p
[i
]));
482 /// Returns a random index, according to the (normalized) distribution described by *this
484 double x
= rnd_uniform() * sum();
486 for( size_t i
= 0; i
< size(); i
++ ) {
491 return( size() - 1 );
496 /// Returns distance of p and q (sizes should be identical), measured using distance measure dt
499 template<typename T
> Real
dist( const TProb
<T
> &p
, const TProb
<T
> &q
, typename TProb
<T
>::DistType dt
) {
500 DAI_DEBASSERT( p
.size() == q
.size() );
503 case TProb
<T
>::DISTL1
:
504 for( size_t i
= 0; i
< p
.size(); i
++ )
505 result
+= fabs((Real
)p
[i
] - (Real
)q
[i
]);
508 case TProb
<T
>::DISTLINF
:
509 for( size_t i
= 0; i
< p
.size(); i
++ ) {
510 Real z
= fabs((Real
)p
[i
] - (Real
)q
[i
]);
516 case TProb
<T
>::DISTTV
:
517 for( size_t i
= 0; i
< p
.size(); i
++ )
518 result
+= fabs((Real
)p
[i
] - (Real
)q
[i
]);
522 case TProb
<T
>::DISTKL
:
523 for( size_t i
= 0; i
< p
.size(); i
++ ) {
525 result
+= p
[i
] * (std::log(p
[i
]) - std::log(q
[i
]));
532 /// Writes a TProb<T> to an output stream
535 template<typename T
> std::ostream
& operator<< (std::ostream
& os
, const TProb
<T
>& P
) {
537 std::copy( P
.p().begin(), P
.p().end(), std::ostream_iterator
<T
>(os
, " ") );
543 /// Returns the TProb<T> containing the pointwise minimum of a and b (which should have equal size)
546 template<typename T
> TProb
<T
> min( const TProb
<T
> &a
, const TProb
<T
> &b
) {
547 DAI_ASSERT( a
.size() == b
.size() );
548 TProb
<T
> result( a
.size() );
549 for( size_t i
= 0; i
< a
.size(); i
++ )
558 /// Returns the TProb<T> containing the pointwise maximum of a and b (which should have equal size)
561 template<typename T
> TProb
<T
> max( const TProb
<T
> &a
, const TProb
<T
> &b
) {
562 DAI_ASSERT( a
.size() == b
.size() );
563 TProb
<T
> result( a
.size() );
564 for( size_t i
= 0; i
< a
.size(); i
++ )
573 /// Represents a vector with entries of type Real.
574 typedef TProb
<Real
> Prob
;
577 } // end of namespace dai