libDAI
factorsp.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) 2002 Martijn Leisink [martijn@mbfys.kun.nl]
8  * Copyright (C) 2006-2009 Joris Mooij [joris dot mooij at libdai dot org]
9  * Copyright (C) 2002-2007 Radboud University Nijmegen, The Netherlands
10  */
11 
12 
15 
16 
17 #ifndef __defined_libdai_factorsp_h
18 #define __defined_libdai_factorsp_h
19 
20 
21 #include <iostream>
22 #include <functional>
23 #include <cmath>
24 #include <dai/probsp.h>
25 #include <dai/varset.h>
26 #include <dai/index.h>
27 #include <dai/util.h>
28 
29 
30 namespace dai {
31 
32 
34 
58 template <typename T, typename spvector_type>
59 class TFactorSp {
60  private:
65 
66  public:
68 
69 
70  TFactorSp ( T p = 1 ) : _vs(), _p(1,p) {}
71 
73  TFactorSp( const Var &v ) : _vs(v), _p(v.states()) {}
74 
76  TFactorSp( const VarSet& vars ) : _vs(vars), _p() {
78  }
79 
81  TFactorSp( const VarSet& vars, T p ) : _vs(vars), _p() {
83  }
84 
86 
90  template<typename S>
91  TFactorSp( const VarSet& vars, const std::vector<S> &x ) : _vs(vars), _p() {
92  DAI_ASSERT( x.size() == vars.nrStates() );
93  _p = TProbSp<T,spvector_type>( x.begin(), x.end(), x.size() );
94  }
95 
97 
100  TFactorSp( const VarSet& vars, const T* p ) : _vs(vars), _p() {
101  size_t N = BigInt_size_t( _vs.nrStates() );
102  _p = TProbSp<T,spvector_type>( p, p + N, N );
103  }
104 
106  TFactorSp( const VarSet& vars, const TProbSp<T,spvector_type> &p ) : _vs(vars), _p(p) {
107  DAI_ASSERT( _vs.nrStates() == _p.size() );
108  }
109 
111  TFactorSp( const std::vector<Var> &vars, const std::vector<T> &p ) : _vs(vars.begin(), vars.end(), vars.size()), _p(p.size()) {
112  BigInt nrStates = 1;
113  for( size_t i = 0; i < vars.size(); i++ )
114  nrStates *= vars[i].states();
115  DAI_ASSERT( nrStates == p.size() );
116  Permute permindex(vars);
117  for( size_t li = 0; li < p.size(); ++li )
118  _p.set( permindex.convertLinearIndex(li), p[li] );
119  }
121 
123 
124 
125  void set( size_t i, T val ) { _p.set( i, val ); }
126 
128  T get( size_t i ) const { return _p[i]; }
130 
132 
133 
134  const TProbSp<T,spvector_type>& p() const { return _p; }
135 
138 
140  T operator[] (size_t i) const { return _p[i]; }
141 
143  const VarSet& vars() const { return _vs; }
144 
146  VarSet& vars() { return _vs; }
147 
149 
151  size_t nrStates() const { return _p.size(); }
152 
154  T entropy() const { return _p.entropy(); }
155 
157  T max() const { return _p.max(); }
158 
160  T min() const { return _p.min(); }
161 
163  T sum() const { return _p.sum(); }
164 
166  T sumAbs() const { return _p.sumAbs(); }
167 
169  T maxAbs() const { return _p.maxAbs(); }
170 
172  bool hasNaNs() const { return _p.hasNaNs(); }
173 
175  bool hasNegatives() const { return _p.hasNegatives(); }
176 
178  T strength( const Var &i, const Var &j ) const;
179 
181  bool operator==( const TFactorSp<T,spvector_type>& y ) const {
182  return (_vs == y._vs) && (_p == y._p);
183  }
185 
187 
188 
190  // Note: the alternative (shorter) way of implementing this,
191  // return TFactorSp<T,spvector_type>( _vs, _p.abs() );
192  // is slower because it invokes the copy constructor of TProbSp<T>
194  x._vs = _vs;
195  x._p = -_p;
196  return x;
197  }
198 
202  x._vs = _vs;
203  x._p = _p.abs();
204  return x;
205  }
206 
210  x._vs = _vs;
211  x._p = _p.exp();
212  return x;
213  }
214 
216 
218  TFactorSp<T,spvector_type> log(bool zero=false) const {
220  x._vs = _vs;
221  x._p = _p.log(zero);
222  return x;
223  }
224 
226 
228  TFactorSp<T,spvector_type> inverse(bool zero=true) const {
230  x._vs = _vs;
231  x._p = _p.inverse(zero);
232  return x;
233  }
234 
236 
240  x._vs = _vs;
241  x._p = _p.normalized( norm );
242  return x;
243  }
245 
247 
248 
249  TFactorSp<T,spvector_type>& randomize() { _p.randomize(); return *this; }
250 
252  TFactorSp<T,spvector_type>& setUniform() { _p.setUniform(); return *this; }
253 
255  TFactorSp<T,spvector_type>& takeAbs() { _p.takeAbs(); return *this; }
256 
258  TFactorSp<T,spvector_type>& takeExp() { _p.takeExp(); return *this; }
259 
261 
263  TFactorSp<T,spvector_type>& takeLog( bool zero = false ) { _p.takeLog(zero); return *this; }
264 
266 
268  T normalize( ProbNormType norm=NORMPROB ) { return _p.normalize( norm ); }
270 
272 
273 
274  TFactorSp<T,spvector_type>& fill (T x) { _p.fill( x ); return *this; }
275 
277  TFactorSp<T,spvector_type>& operator+= (T x) { _p += x; return *this; }
278 
280  TFactorSp<T,spvector_type>& operator-= (T x) { _p -= x; return *this; }
281 
283  TFactorSp<T,spvector_type>& operator*= (T x) { _p *= x; return *this; }
284 
286  TFactorSp<T,spvector_type>& operator/= (T x) { _p /= x; return *this; }
287 
289  TFactorSp<T,spvector_type>& operator^= (T x) { _p ^= x; return *this; }
291 
293 
294 
296  // Note: the alternative (shorter) way of implementing this,
297  // TFactorSp<T,spvector_type> result(*this);
298  // result._p += x;
299  // is slower because it invokes the copy constructor of TFactorSp<T,spvector_type>
301  result._vs = _vs;
302  result._p = p() + x;
303  return result;
304  }
305 
309  result._vs = _vs;
310  result._p = p() - x;
311  return result;
312  }
313 
317  result._vs = _vs;
318  result._p = p() * x;
319  return result;
320  }
321 
325  result._vs = _vs;
326  result._p = p() / x;
327  return result;
328  }
329 
333  result._vs = _vs;
334  result._p = p() ^ x;
335  return result;
336  }
338 
340 
341 
342 
346  template<typename binOp> TFactorSp<T,spvector_type>& binaryOp( const TFactorSp<T,spvector_type> &g, binOp op ) {
347  if( _vs == g._vs ) // optimize special case
348  _p.pwBinaryOp( g._p, op );
349  else {
350  *this = pointwiseOp( *this, g, op );
351  // OPTIMIZE ME
352 /* TFactorSp<T,spvector_type> f(*this); // make a copy
353  _vs |= g._vs;
354  size_t N = _vs.nrStates();
355 
356  IndexFor i_f( f._vs, _vs );
357  IndexFor i_g( g._vs, _vs );
358 
359  _p.p().clear();
360  _p.p().reserve( N );
361  for( size_t i = 0; i < N; i++, ++i_f, ++i_g )
362  _p.p().push_back( op( f[i_f], g[i_g] ) );*/
363  }
364  return *this;
365  }
366 
368 
372  TFactorSp<T,spvector_type>& operator+= (const TFactorSp<T,spvector_type>& g) { return binaryOp( g, std::plus<T>() ); }
373 
375 
379  TFactorSp<T,spvector_type>& operator-= (const TFactorSp<T,spvector_type>& g) { return binaryOp( g, std::minus<T>() ); }
380 
382 
387  // Note that the following implementation is slow, because it doesn't exploit the special case of value 0
388  // return binaryOp( g, std::multiplies<T>() );
389  if( _vs == g._vs ) // optimize special case
390  _p.pwBinaryOp( g._p, std::multiplies<T>() );
391  else
392  *this = pointwiseOp( *this, g, std::multiplies<T>(), p().def() == (T)0 && g.p().def() == (T)0 );
393  return *this;
394  }
395 
397 
403 
405 
406 
407 
411  template<typename binOp> TFactorSp<T,spvector_type> binaryTr( const TFactorSp<T,spvector_type> &g, binOp op ) const {
412  // OPTIMIZE ME
413  return pointwiseOp( *this, g, op );
414  // Note that to prevent a copy to be made, it is crucial
415  // that the result is declared outside the if-else construct.
416 /* TFactorSp<T,spvector_type> result;
417  if( _vs == g._vs ) { // optimize special case
418  result._vs = _vs;
419  result._p = _p.pwBinaryTr( g._p, op );
420  } else {
421  result._vs = _vs | g._vs;
422  size_t N = result._vs.nrStates();
423 
424  IndexFor i_f( _vs, result.vars() );
425  IndexFor i_g( g._vs, result.vars() );
426 
427  result._p.p().clear();
428  result._p.p().reserve( N );
429  for( size_t i = 0; i < N; i++, ++i_f, ++i_g )
430  result._p.p().push_back( op( _p[i_f], g[i_g] ) );
431  }
432  return result;*/
433  }
434 
436 
441  return binaryTr(g,std::plus<T>());
442  }
443 
445 
450  return binaryTr(g,std::minus<T>());
451  }
452 
454 
459  return pointwiseOp( *this, g, std::multiplies<T>(), p().def() == (T)0 && g.p().def() == (T)0 );
460  }
461 
463 
468  return binaryTr(g,fo_divides0<T>());
469  }
471 
473 
474 
475 
486  TFactorSp<T,spvector_type> slice( const VarSet& vars, size_t varsState ) const;
487 
489 
495  DAI_ASSERT( vars >> _vs );
496  if( _vs == vars )
497  return *this;
498  else
499  return (*this) * TFactorSp<T,spvector_type>(vars / _vs, (T)1);
500  }
501 
503  TFactorSp<T,spvector_type> marginal(const VarSet &vars, bool normed=true) const;
504 
506  TFactorSp<T,spvector_type> maxMarginal(const VarSet &vars, bool normed=true) const;
508 };
509 
510 
511 template<typename T, typename spvector_type> TFactorSp<T,spvector_type> TFactorSp<T,spvector_type>::slice( const VarSet& vars, size_t varsState ) const {
512  DAI_ASSERT( vars << _vs );
513  VarSet varsrem = _vs / vars;
514 
515  TFactorSp<T,spvector_type> result( varsrem, p().def() );
516  for( typename TProbSp<T,spvector_type>::const_iterator it = p().begin(); it != p().end(); it++ ) {
517  State s( _vs, it->first );
518  size_t vars_s = BigInt_size_t( s( vars ) );
519  if( vars_s == varsState )
520  result.set( BigInt_size_t( s(varsrem) ), it->second );
521  }
522 
523  /* SLOW BECAUSE IT ITERATES OVER ALL VALUES */
524  // OPTIMIZE ME
525 /* TFactorSp<T,spvector_type> res( varsrem, T(0) );
526  IndexFor i_vars (vars, _vs);
527  IndexFor i_varsrem (varsrem, _vs);
528  for( size_t i = 0; i < nrStates(); i++, ++i_vars, ++i_varsrem )
529  if( (size_t)i_vars == varsState )
530  res.set( i_varsrem, _p[i] );
531 
532  if( !((result.p() <= res.p()) && (res.p() <= result.p())) ) {
533  std::cerr << result << std::endl;
534  std::cerr << res << std::endl;
535  DAI_ASSERT( ((result.p() <= res.p()) && (res.p() <= result.p())) );
536  }*/
537 
538  return result;
539 }
540 
541 
542 template<typename T, typename spvector_type> TFactorSp<T,spvector_type> TFactorSp<T,spvector_type>::marginal(const VarSet &vars, bool normed) const {
543  VarSet res_vars = vars & _vs;
544 
545  DAI_ASSERT( !isnan(p().def()) );
546 
547  VarSet rem(_vs / res_vars);
548  TFactorSp<T,spvector_type> result( res_vars, rem.nrStates().get_d() * p().def() );
549  for( typename TProbSp<T,spvector_type>::const_iterator it = p().begin(); it != p().end(); it++ ) {
550  State s(_vs, it->first);
551  size_t res_vars_s = BigInt_size_t( s( res_vars) );
552  result.set( res_vars_s, result[res_vars_s] - p().def() + it->second );
553  }
554 
555  /* SLOW BECAUSE IT ITERATES OVER ALL VALUES
556  TFactorSp<T,spvector_type> res( res_vars, 0.0 );
557  IndexFor i_res( res_vars, _vs );
558  for( size_t i = 0; i < _p.size(); i++, ++i_res )
559  res.set( i_res, res[i_res] + _p[i] );
560 
561  if( !((result.p() <= res.p()) && (res.p() <= result.p())) ) {
562  std::cerr << result << std::endl;
563  std::cerr << res << std::endl;
564  DAI_ASSERT( ((result.p() <= res.p()) && (res.p() <= result.p())) );
565  }
566  */
567 
568  if( normed )
569  result.normalize( NORMPROB );
570 
571  return result;
572 }
573 
574 
575 template<typename T, typename spvector_type> TFactorSp<T,spvector_type> TFactorSp<T,spvector_type>::maxMarginal(const VarSet &vars, bool normed) const {
576  VarSet res_vars = vars & _vs;
577 
578  VarSet rem(_vs / res_vars);
579  TFactorSp<T,spvector_type> result( res_vars, p().def() );
580  for( typename TProbSp<T,spvector_type>::const_iterator it = p().begin(); it != p().end(); it++ ) {
581  State s( _vs, it->first );
582  size_t res_vars_s = BigInt_size_t( s( res_vars ) );
583  if( it->second > result[res_vars_s] )
584  result.set( res_vars_s, it->second );
585  }
586 
587  /* SLOW BECAUSE IT ITERATES OVER ALL VALUES */
588 /*
589  TFactorSp<T,spvector_type> res( res_vars, 0.0 );
590  IndexFor i_res( res_vars, _vs );
591  for( size_t i = 0; i < _p.size(); i++, ++i_res )
592  if( _p[i] > res._p[i_res] )
593  res.set( i_res, _p[i] );
594 
595  if( !((result.p() <= res.p()) && (res.p() <= result.p())) ) {
596  std::cerr << result << std::endl;
597  std::cerr << res << std::endl;
598  DAI_ASSERT( ((result.p() <= res.p()) && (res.p() <= result.p())) );
599  }
600 */
601  if( normed )
602  result.normalize( NORMPROB );
603 
604  return result;
605 }
606 
607 
608 template<typename T, typename spvector_type> T TFactorSp<T,spvector_type>::strength( const Var &i, const Var &j ) const {
609  DAI_DEBASSERT( _vs.contains( i ) );
610  DAI_DEBASSERT( _vs.contains( j ) );
611  DAI_DEBASSERT( i != j );
612  VarSet ij(i, j);
613 
614  T max = 0.0;
615  for( size_t alpha1 = 0; alpha1 < i.states(); alpha1++ )
616  for( size_t alpha2 = 0; alpha2 < i.states(); alpha2++ )
617  if( alpha2 != alpha1 )
618  for( size_t beta1 = 0; beta1 < j.states(); beta1++ )
619  for( size_t beta2 = 0; beta2 < j.states(); beta2++ )
620  if( beta2 != beta1 ) {
621  size_t as = 1, bs = 1;
622  if( i < j )
623  bs = i.states();
624  else
625  as = j.states();
626  T f1 = slice( ij, alpha1 * as + beta1 * bs ).p().divide( slice( ij, alpha2 * as + beta1 * bs ).p() ).max();
627  T f2 = slice( ij, alpha2 * as + beta2 * bs ).p().divide( slice( ij, alpha1 * as + beta2 * bs ).p() ).max();
628  T f = f1 * f2;
629  if( f > max )
630  max = f;
631  }
632 
633  return std::tanh( 0.25 * std::log( max ) );
634 }
635 
636 
638 
646 template<typename T, typename spvector_type, typename binaryOp> TFactorSp<T,spvector_type> pointwiseOp( const TFactorSp<T,spvector_type> &f, const TFactorSp<T,spvector_type> &g, binaryOp op, bool fast=false ) {
647  if( f.vars() == g.vars() ) { // optimizate special case
648  TFactorSp<T,spvector_type> result( f.vars() );
649  result.p() = f.p().pwBinaryTr( g.p(), op );
650  return result;
651  } else {
652  // Union of variables
653  VarSet un( f.vars() | g.vars() );
654  // Intersection of variables
655  VarSet is( f.vars() & g.vars() );
656  // Result factor
657  TFactorSp<T,spvector_type> result( un, op( f.p().def(), g.p().def() ) );
658 
659  if( fast ) {
660  // For all non-default states of f and all non-default states of g
661  for( typename TProbSp<T,spvector_type>::const_iterator fit = f.p().begin(); fit != f.p().end(); fit++ ) {
662  // calculate state of f
663  State fs( f.vars(), fit->first );
664  for( typename TProbSp<T,spvector_type>::const_iterator git = g.p().begin(); git != g.p().end(); git++ ) {
665  // calculate state of g
666  State gs( g.vars(), git->first );
667  // check whether these states are compatible
668  bool compatible = true;
669  for( typename VarSet::const_iterator v = is.begin(); v != is.end() && compatible; v++ )
670  if( fs(*v) != gs(*v) )
671  compatible = false;
672  if( compatible ) {
673  State fgs = fs;
674  fgs.insert( gs.begin(), gs.end() );
675  result.set( BigInt_size_t(fgs(un)), op( fit->second, git->second ) );
676  }
677  }
678  }
679  } else {
680  // For all non-default states of f and all states of g
681  for( typename TProbSp<T,spvector_type>::const_iterator fit = f.p().begin(); fit != f.p().end(); fit++ ) {
682  State fs( f.vars(), fit->first );
683  for( State g_minus_f_s(g.vars() / f.vars()); g_minus_f_s.valid(); g_minus_f_s++ ) {
684  State fgs = g_minus_f_s.get();
685  fgs.insert( fs.begin(), fs.end() );
686  result.set( BigInt_size_t(fgs(un)), op( fit->second, g[BigInt_size_t(fgs(g.vars()))] ) );
687  }
688  }
689  // For all states of f and all non-default states of g
690  for( typename TProbSp<T,spvector_type>::const_iterator git = g.p().begin(); git != g.p().end(); git++ ) {
691  State gs( g.vars(), git->first );
692  for( State f_minus_g_s(f.vars() / g.vars()); f_minus_g_s.valid(); f_minus_g_s++ ) {
693  State fgs = f_minus_g_s.get();
694  fgs.insert( gs.begin(), gs.end() );
695  result.set( BigInt_size_t(fgs(un)), op( f[BigInt_size_t(fgs(f.vars()))], git->second ) );
696  }
697  }
698  }
699 
700  /* SLOW BECAUSE IT ITERATES OVER ALL VALUES */
701 /* TFactorSp<T,spvector_type> resultold( un, op( f.p().def(), g.p().def() ) );
702  IndexFor i1(f.vars(), result.vars());
703  IndexFor i2(g.vars(), result.vars());
704 
705  for( size_t i = 0; i < result.states(); i++, ++i1, ++i2 )
706  resultold.set(i, op( f[i1], g[i2] ));
707 
708  if( !((result.p() <= resultold.p()) && (resultold.p() <= result.p())) ) {
709  std::cerr << result << std::endl;
710  std::cerr << resultold << std::endl;
711  DAI_ASSERT( ((result.p() <= resultold.p()) && (resultold.p() <= result.p())) );
712  }
713 */
714 
715  return result;
716  }
717 }
718 
719 
721 
723 template<typename T, typename spvector_type> std::ostream& operator<< (std::ostream& os, const TFactorSp<T,spvector_type>& f) {
724 // os << "(" << f.vars() << ", " << f.p() << ")";
725  os << "(" << f.vars() << ", (";
726  for( size_t i = 0; i < f.nrStates(); i++ )
727  os << (i == 0 ? "" : ", ") << f[i];
728  os << "))";
729  return os;
730 }
731 
732 
734 
737 template<typename T, typename spvector_type> T dist( const TFactorSp<T,spvector_type> &f, const TFactorSp<T,spvector_type> &g, ProbDistType dt ) {
738  if( f.vars().empty() || g.vars().empty() )
739  return -1;
740  else {
741  DAI_DEBASSERT( f.vars() == g.vars() );
742  return dist( f.p(), g.p(), dt );
743  }
744 }
745 
746 
748 
751 template<typename T, typename spvector_type> TFactorSp<T,spvector_type> max( const TFactorSp<T,spvector_type> &f, const TFactorSp<T,spvector_type> &g ) {
752  DAI_ASSERT( f.vars() == g.vars() );
753  return TFactorSp<T,spvector_type>( f.vars(), max( f.p(), g.p() ) );
754 }
755 
756 
758 
761 template<typename T, typename spvector_type> TFactorSp<T,spvector_type> min( const TFactorSp<T,spvector_type> &f, const TFactorSp<T,spvector_type> &g ) {
762  DAI_ASSERT( f.vars() == g.vars() );
763  return TFactorSp<T,spvector_type>( f.vars(), min( f.p(), g.p() ) );
764 }
765 
766 
768 
771 template<typename T, typename spvector_type> T MutualInfo(const TFactorSp<T,spvector_type> &f) {
772  DAI_ASSERT( f.vars().size() == 2 );
773  VarSet::const_iterator it = f.vars().begin();
774  Var i = *it; it++; Var j = *it;
775  TFactorSp<T,spvector_type> projection = f.marginal(i) * f.marginal(j);
776  return dist( f.normalized(), projection, DISTKL );
777 }
778 
779 
780 } // end of namespace dai
781 
782 
783 #endif