libDAI
probsp.h
Go to the documentation of this file.
1 /* This file is part of libDAI - http://www.libdai.org/
2  *
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.
6  *
7  * Copyright (C) 2006-2009 Joris Mooij [joris dot mooij at libdai dot org]
8  * Copyright (C) 2006-2007 Radboud University Nijmegen, The Netherlands
9  */
10 
11 
14 
15 
16 #ifndef __defined_libdai_probsp_h
17 #define __defined_libdai_probsp_h
18 
19 
20 #include <cmath>
21 #include <vector>
22 #include <ostream>
23 #include <algorithm>
24 #include <numeric>
25 #include <functional>
26 #include <dai/util.h>
27 #include <dai/exceptions.h>
28 #include <dai/fo.h>
29 
30 
31 namespace dai {
32 
33 
35 
43 template <typename T, typename spvector_type>
44 class TProbSp {
45  public:
47  typedef spvector_type container_type;
49 
50  private:
53 
54  public:
56 
57 
58  TProbSp() : _p() {}
59 
61  explicit TProbSp( size_t n ) : _p( n, (T)1 / n ) {}
62 
64  explicit TProbSp( size_t n, T p ) : _p( n, p ) {}
65 
67 
74  template <typename TIterator>
75  TProbSp( TIterator begin, TIterator end, size_t sizeHint, T def=0 ) : _p( begin, end, sizeHint, def ) {}
76 
78 
82  template <typename S>
83  TProbSp( const std::vector<S> &v, T def=0 ) : _p( v, v.size(), def ) {}
85 
87  typedef typename container_type::const_iterator const_iterator;
89  typedef typename container_type::iterator iterator;
91  typedef typename container_type::const_reverse_iterator const_reverse_iterator;
93  typedef typename container_type::reverse_iterator reverse_iterator;
94 
96 
97 
98  iterator begin() { return _p.begin(); }
100  const_iterator begin() const { return _p.begin(); }
101 
103  iterator end() { return _p.end(); }
105  const_iterator end() const { return _p.end(); }
106 
108  reverse_iterator rbegin() { return _p.rbegin(); }
110  const_reverse_iterator rbegin() const { return _p.rbegin(); }
111 
113  reverse_iterator rend() { return _p.rend(); }
115  const_reverse_iterator rend() const { return _p.rend(); }
117 
119 
120  void resize( size_t sz ) {
121  _p.resize( sz );
122  }
124 
126 
127 
128  T get( size_t i ) const { return _p[i]; }
129 
131  void set( size_t i, T val ) { _p.set( i, val ); }
133 
135 
136 
137  const container_type& p() const { return _p; }
138 
140  container_type& p() { return _p; }
141 
143  T operator[]( size_t i ) const { return get(i); }
144 
146  size_t size() const { return _p.size(); }
147 
149  size_t nrDef() const { return _p.nrDef(); }
150 
152  size_t nrNonDef() const { return _p.nrNonDef(); }
153 
155  T def() const { return _p.def(); }
156 
158  void setDef( T def ) { _p.setDef( def ); }
159 
161 
169  template<typename unOp> T accumulateSum( T init, unOp op ) const {
170  T t = op(init);
171  for( const_iterator it = begin(); it != end(); it++ )
172  t += op(it->second);
173  t += nrDef() * op(def());
174  return t;
175  }
176 
178 
186  template<typename unOp> T accumulateMax( T init, unOp op, bool minimize ) const {
187  T t = op(init);
188  if( minimize ) {
189  for( const_iterator it = begin(); it != end(); it++ )
190  t = std::min( t, op(it->second) );
191  if( nrDef() )
192  t = std::min( t, op(def()) );
193  } else {
194  for( const_iterator it = begin(); it != end(); it++ )
195  t = std::max( t, op(it->second) );
196  if( nrDef() )
197  t = std::max( t, op(def()) );
198  }
199  return t;
200  }
201 
203  T entropy() const { return -accumulateSum( (T)0, fo_plog0p<T>() ); }
204 
206  T max() const { return accumulateMax( (T)(-INFINITY), fo_id<T>(), false ); }
207 
209  T min() const { return accumulateMax( (T)INFINITY, fo_id<T>(), true ); }
210 
212  T sum() const { return accumulateSum( (T)0, fo_id<T>() ); }
213 
215  T sumAbs() const { return accumulateSum( (T)0, fo_abs<T>() ); }
216 
218  T maxAbs() const { return accumulateMax( (T)0, fo_abs<T>(), false ); }
219 
221  bool hasNaNs() const {
222  if( isnan( def() ) && nrDef() )
223  return true;
224  else {
225  bool foundnan = false;
226  for( const_iterator it = begin(); it != end(); it++ )
227  if( isnan( it->second ) ) {
228  foundnan = true;
229  break;
230  }
231  return foundnan;
232  }
233  }
234 
236  bool hasNegatives() const {
237  if( (def() < 0) && nrDef() )
238  return true;
239  else {
240  bool foundnegative = false;
241  for( const_iterator it = begin(); it != end(); it++ )
242  if( it->second < 0 ) {
243  foundnegative = true;
244  break;
245  }
246  return foundnegative;
247  }
248  }
249 
251  std::pair<size_t,T> argmax() const {
252  T max;
253  size_t arg;
254  DAI_ASSERT( size() );
255  if( nrDef() == size() ) {
256  max = def();
257  arg = 0;
258  } else if( nrDef() > 0 ) {
259  max = begin()->second;
260  arg = begin()->first;
261  size_t i = 0;
262  size_t argdef = 0;
263  for( const_iterator it = begin(); it != end(); it++ ) {
264  if( it->second > max ) {
265  max = it->second;
266  arg = it->first;
267  }
268  if( it->first != i )
269  argdef = i;
270  i = it->first + 1;
271  }
272  if( def() > max ) {
273  max = def();
274  arg = argdef;
275  }
276  } else {
277  max = begin()->second;
278  arg = begin()->first;
279  for( const_iterator it = begin(); it != end(); it++ )
280  if( it->second > max ) {
281  max = it->second;
282  arg = it->first;
283  }
284  }
285  return std::make_pair( arg, max );
286  }
287 
289  size_t draw() {
290  Real x = rnd_uniform() * sum();
291  T s = 0;
292  for( size_t i = 0; i < size(); i++ ) {
293  s += get(i);
294  if( s > x )
295  return i;
296  }
297  return( size() - 1 );
298  }
299 
301 
303  bool operator<( const this_type& q ) const {
304  DAI_DEBASSERT( size() == q.size() );
305  for( size_t i = 0; i < size(); i++ ) {
306  T a = get(i);
307  T b = q.get(i);
308  if( a > b )
309  return false;
310  if( a < b )
311  return true;
312  }
313  return false;
314  }
315 
317  bool operator==( const this_type& q ) const {
318  if( size() != q.size() )
319  return false;
320  return _p == q._p;
321  }
323 
325 
326 
327  template<typename unaryOp> this_type pwUnaryTr( unaryOp op ) const {
328  this_type r;
329  r.setDef( op( def() ) );
330  r._p.resize( size() );
331  for( const_iterator it = begin(); it != end(); it++ ) {
332  T new_val = op( it->second );
333  if( new_val != r.def() )
334  r._p.push_back( it->first, new_val );
335  }
336  return r;
337  }
338 
340  this_type operator- () const { return pwUnaryTr( std::negate<T>() ); }
341 
343  this_type abs() const { return pwUnaryTr( fo_abs<T>() ); }
344 
346  this_type exp() const { return pwUnaryTr( fo_exp<T>() ); }
347 
349 
351  this_type log(bool zero=false) const {
352  if( zero )
353  return pwUnaryTr( fo_log0<T>() );
354  else
355  return pwUnaryTr( fo_log<T>() );
356  }
357 
359 
361  this_type inverse(bool zero=true) const {
362  if( zero )
363  return pwUnaryTr( fo_inv0<T>() );
364  else
365  return pwUnaryTr( fo_inv<T>() );
366  }
367 
369 
371  this_type normalized( ProbNormType norm = dai::NORMPROB ) const {
372  T Z = 0;
373  if( norm == dai::NORMPROB )
374  Z = sum();
375  else if( norm == dai::NORMLINF )
376  Z = maxAbs();
377  if( Z == (T)0 ) {
378  DAI_THROW(NOT_NORMALIZABLE);
379  return *this;
380  } else
381  return pwUnaryTr( std::bind2nd( std::divides<T>(), Z ) );
382  }
384 
386 
387 
388  template<typename unaryOp> this_type& pwUnaryOp( unaryOp op ) {
389  setDef( op( def() ) );
390  for( iterator it = begin(); it != end(); ) {
391  T new_val = op( it->second );
392  if( new_val != def() ) {
393  it->second = new_val;
394  it++;
395  } else
396  it = _p.erase( it );
397  }
398  return *this;
399  }
400 
403  setDef( 0 );
404  for( size_t i = 0; i < size(); i++ )
405  set( i, (T)rnd_uniform() );
406  return *this;
407  }
408 
411  setDef( (T)1 / size() );
412  _p.clearNonDef();
413  return *this;
414  }
415 
417  this_type& takeAbs() { return pwUnaryOp( fo_abs<T>() ); }
418 
420  this_type& takeExp() { return pwUnaryOp( fo_exp<T>() ); }
421 
423 
425  this_type& takeLog(bool zero=false) {
426  if( zero ) {
427  return pwUnaryOp( fo_log0<T>() );
428  } else
429  return pwUnaryOp( fo_log<T>() );
430  }
431 
433 
435  T normalize( ProbNormType norm = dai::NORMPROB ) {
436  T Z = 0;
437  if( norm == dai::NORMPROB )
438  Z = sum();
439  else if( norm == dai::NORMLINF )
440  Z = maxAbs();
441  if( Z == (T)0 )
442  DAI_THROW(NOT_NORMALIZABLE);
443  else
444  *this /= Z;
445  return Z;
446  }
448 
450 
451 
452  this_type& fill( T x ) {
453  setDef( x );
454  _p.clearNonDef();
455  return *this;
456  }
457 
460  if( x != 0 )
461  return pwUnaryOp( std::bind2nd( std::plus<T>(), x ) );
462  else
463  return *this;
464  }
465 
468  if( x != 0 )
469  return pwUnaryOp( std::bind2nd( std::minus<T>(), x ) );
470  else
471  return *this;
472  }
473 
476  if( x != 1 )
477  return pwUnaryOp( std::bind2nd( std::multiplies<T>(), x ) );
478  else
479  return *this;
480  }
481 
484  if( x != 1 )
485  return pwUnaryOp( std::bind2nd( fo_divides0<T>(), x ) );
486  else
487  return *this;
488  }
489 
492  if( x != (T)1 )
493  return pwUnaryOp( std::bind2nd( fo_pow<T>(), x) );
494  else
495  return *this;
496  }
498 
500 
501 
502  this_type operator+ (T x) const { return pwUnaryTr( std::bind2nd( std::plus<T>(), x ) ); }
503 
505  this_type operator- (T x) const { return pwUnaryTr( std::bind2nd( std::minus<T>(), x ) ); }
506 
508  this_type operator* (T x) const { return pwUnaryTr( std::bind2nd( std::multiplies<T>(), x ) ); }
509 
511  this_type operator/ (T x) const { return pwUnaryTr( std::bind2nd( fo_divides0<T>(), x ) ); }
512 
514  this_type operator^ (T x) const { return pwUnaryTr( std::bind2nd( fo_pow<T>(), x ) ); }
516 
518 
519 
520 
524  template<typename binaryOp> this_type& pwBinaryOp( const this_type &q, binaryOp op ) {
525  DAI_DEBASSERT( size() == q.size() );
526  this_type p(*this);
527  setDef( op( p.def(), q.def() ) );
528  for( typename this_type::const_iterator it = p.begin(); it != p.end(); it++ ) {
529  T new_val = op( it->second, q[it->first] );
530  set( it->first, new_val );
531  }
532  for( typename this_type::const_iterator it = q.begin(); it != q.end(); it++ ) {
533  T new_val = op( p[it->first], it->second );
534  set( it->first, new_val );
535  }
536  return *this;
537  }
538 
540 
542  this_type& operator+= (const this_type & q) { return pwBinaryOp( q, std::plus<T>() ); }
543 
545 
547  this_type& operator-= (const this_type & q) { return pwBinaryOp( q, std::minus<T>() ); }
548 
550 
552  this_type& operator*= (const this_type & q) { return pwBinaryOp( q, std::multiplies<T>() ); }
553 
555 
558  this_type& operator/= (const this_type & q) { return pwBinaryOp( q, fo_divides0<T>() ); }
559 
561 
564  this_type& divide (const this_type & q) { return pwBinaryOp( q, std::divides<T>() ); }
565 
567 
569  this_type& operator^= (const this_type & q) { return pwBinaryOp( q, fo_pow<T>() ); }
571 
573 
574 
575 
579  template<typename binaryOp> this_type pwBinaryTr( const this_type &q, binaryOp op ) const {
580  DAI_DEBASSERT( size() == q.size() );
581  this_type result;
582  result.setDef( op( def(), q.def() ) );
583  result._p.resize( size() );
584  for( typename this_type::const_iterator it = begin(); it != end(); it++ ) {
585  T new_val = op( it->second, q[it->first] );
586  if( new_val != result.def() )
587  result._p.push_back(it->first, new_val);
588  }
589  for( typename this_type::const_iterator it = q.begin(); it != q.end(); it++ ) {
590  T new_val = op( get(it->first), it->second );
591  if( new_val != result.def() )
592  result.set( it->first, new_val );
593  }
594  return result;
595  }
596 
598 
600  this_type operator+ ( const this_type& q ) const { return pwBinaryTr( q, std::plus<T>() ); }
601 
603 
605  this_type operator- ( const this_type& q ) const { return pwBinaryTr( q, std::minus<T>() ); }
606 
608 
610  this_type operator* ( const this_type &q ) const { return pwBinaryTr( q, std::multiplies<T>() ); }
611 
613 
616  this_type operator/ ( const this_type &q ) const { return pwBinaryTr( q, fo_divides0<T>() ); }
617 
619 
622  this_type divided_by( const this_type &q ) const { return pwBinaryTr( q, std::divides<T>() ); }
623 
625 
627  this_type operator^ ( const this_type &q ) const { return pwBinaryTr( q, fo_pow<T>() ); }
629 
631 
633  template<typename binOp1, typename binOp2> T innerProduct( const this_type &q, T init, binOp1 binaryOp1, binOp2 binaryOp2 ) const {
634  DAI_DEBASSERT( size() == q.size() );
635  // OPTIMIZE ME
636  T result = init;
637  for( size_t i = 0; i < size(); i++ )
638  result = binaryOp1( result, binaryOp2( get(i), q.get(i) ) );
639  return result;
640  }
641 };
642 
643 
645 
648 template<typename T, typename spvector_type> T dist( const TProbSp<T,spvector_type>& p, const TProbSp<T,spvector_type>& q, ProbDistType dt ) {
649  switch( dt ) {
650  case DISTL1:
651  return p.innerProduct( q, (T)0, std::plus<T>(), fo_absdiff<T>() );
652  case DISTLINF:
653  return p.innerProduct( q, (T)0, fo_max<T>(), fo_absdiff<T>() );
654  case DISTTV:
655  return p.innerProduct( q, (T)0, std::plus<T>(), fo_absdiff<T>() ) / 2;
656  case DISTKL:
657  return p.innerProduct( q, (T)0, std::plus<T>(), fo_KL<T>() );
658  case DISTHEL:
659  return p.innerProduct( q, (T)0, std::plus<T>(), fo_Hellinger<T>() ) / 2;
660  default:
661  DAI_THROW(UNKNOWN_ENUM_VALUE);
662  return INFINITY;
663  }
664 }
665 
666 
668 
670 template<typename T, typename spvector_type> std::ostream& operator<< (std::ostream& os, const TProbSp<T,spvector_type>& p) {
671  os << p.p();
672  return os;
673 }
674 
675 
677 
680 template<typename T, typename spvector_type> TProbSp<T,spvector_type> min( const TProbSp<T,spvector_type> &a, const TProbSp<T,spvector_type> &b ) {
681  return a.pwBinaryTr( b, fo_min<T>() );
682 }
683 
684 
686 
689 template<typename T, typename spvector_type> TProbSp<T,spvector_type> max( const TProbSp<T,spvector_type> &a, const TProbSp<T,spvector_type> &b ) {
690  return a.pwBinaryTr( b, fo_max<T>() );
691 }
692 
693 
694 } // end of namespace dai
695 
696 
697 #endif