faif
Fusion.hpp
1 #ifndef FAIF_FUSION_HPP
2 #define FAIF_FUSION_HPP
3 
4 #include <vector>
5 #include <ostream>
6 #include <map>
7 #include <iterator>
8 #include <algorithm>
9 #include <numeric>
10 #include <limits>
11 #include <functional>
12 #include <boost/bind.hpp>
13 
14 #include "Belief.hpp"
15 
16 namespace faif {
17 
18  namespace ml {
19 
20  /**
21  \brief typedef's for Dempster-Shafer combination rule (for fusion) and some internal (helping) methods
22  */
23  template<typename Belief> struct FusionInternal {
24 
25  // /< attribute id representation in fusion
26  typedef typename Belief::ValueId AttrIdd;
27 
28  //collection of pair (AttrIdd, Probability)
29  typedef typename Belief::Beliefs Beliefs;
30 
31  // the helping type - internal for fusion calculations
32  typedef std::map<AttrIdd, std::vector<Probability> > Evidence;
33 
34  //the helping function - return the initial key-value pair for evidence container
35  static typename Evidence::value_type InitTransformFunction(const Belief& in) {
36  std::vector<Probability> v;
37  v.push_back(in.getProbability());
38  return typename Evidence::value_type(in.getValue(), v);
39  }
40 
41  };
42 
43  //the helping functor - complete the evidence records by adding the probabilities from given vector
44  template<typename Belief>
45  struct AddEvidenceFunctor : public std::unary_function<void, typename Belief::Beliefs> {
46 
47  typedef typename FusionInternal<Belief>::Evidence Evidence;
48  typedef typename FusionInternal<Belief>::Beliefs Beliefs;
49  typedef typename FusionInternal<Belief>::AttrIdd AttrIdd;
50 
51  Evidence& evidence_;
52 
53  AddEvidenceFunctor(Evidence& evidence) : evidence_(evidence) {}
54 
55  void operator()(const Beliefs& probs) {
56  //adds the probability to the evidence - try to find the item and read the probability. If item not found NaN is added.
57  for(typename Evidence::iterator i = evidence_.begin(); i != evidence_.end(); ++i ) {
58  Probability probability_ = std::numeric_limits<Probability>::quiet_NaN();
59  typename Beliefs::const_iterator found =
60  std::find_if(probs.begin(), probs.end(),
61  boost::bind(std::equal_to<AttrIdd>(), boost::bind(&Belief::getValue, _1), i->first ) );
62  if( found != probs.end() )
63  probability_ = found->getProbability();
64  //put the found probability
65  i->second.push_back(probability_);
66  }
67  // std::for_each( evidence_.begin(), evidence_.end(), boost::bind(AddEvidenceFunctor<Belief>::AddProbFunction, _1, probs) );
68 
69 
70 
71  //look for NaN and change the NaN value to (1.0 - sum)/count , where 'count' is number of NaN values
72  Probability sum = 0.0;
73  int count = 0; //number of NaN
74  for(typename Evidence::const_iterator i = evidence_.begin(); i != evidence_.end(); ++i ) {
75  const Probability& v = i->second.back();
76  if ( v == v ) { //if not is NaN
77  sum += v;
78  } else { // found NaN
79  ++count;
80  }
81  }
82  //update the NaN to (1.0 - sum)/ count
83  if(count > 0) {
84  Probability probForUnknown = (1.0 - sum)/static_cast<Probability>(count);
85  if(probForUnknown < 0)
86  probForUnknown = 0;
87  for(typename Evidence::iterator i = evidence_.begin(); i != evidence_.end(); ++i ) {
88  Probability& v = i->second.back();
89  if ( v != v ) //if NaN
90  v = probForUnknown;
91  }
92  }
93  }
94  private:
95  AddEvidenceFunctor& operator=(const AddEvidenceFunctor&); //forbidden
96  };
97 
98  // the helping class - return the probabilities divided by sum (so they summarizes to 1)
99  template<typename Belief, typename EvidenceValue>
100  struct NormalizationFunctor : std::binary_function<Belief, Probability, EvidenceValue> {
101 
102  NormalizationFunctor(Probability sum) : sum_(sum) {}
103 
104  Belief operator()(const Probability& prob, const EvidenceValue& evidence) {
105  return Belief(evidence.first, prob / sum_ );
106  }
107  Probability sum_;
108  };
109 
110  // } //namespace
111 
112  /** \brief connect categories using the Dempster-Shafer combination rule, e.g.
113  bel(cat) = bel1(cat) * bel2(cat) * ... * beln(cat) / SUM(bel)
114  **/
115  template<typename Belief> typename Belief::Beliefs fusion(const typename std::vector<typename Belief::Beliefs>& input) {
116 
117  BOOST_CONCEPT_ASSERT((BeliefConcept<Belief>));
118 
119  typedef typename FusionInternal<Belief>::Evidence Evidence;
120  typedef typename FusionInternal<Belief>::Beliefs Beliefs;
121 
122  Beliefs output;
123 
124  if(input.empty() )
125  return output; //empty output
126 
127  Evidence evidence;
128  const Beliefs& front = input.front(); //assert: input front exists
129  std::transform( front.begin(), front.end(), std::inserter(evidence, evidence.begin() ), FusionInternal<Belief>::InitTransformFunction );
130  AddEvidenceFunctor<Belief> add_evidence(evidence);
131  std::for_each( ++input.begin(), input.end(), add_evidence );
132 
133  std::vector<Probability> combination;
134  for(typename Evidence::const_iterator i = evidence.begin(); i != evidence.end(); ++i ) {
135  const std::vector<Probability>& in = i->second;
136  combination.push_back( std::accumulate(in.begin(), in.end(), 1.0, std::multiplies<Probability>() ) );
137  }
138  Probability sum = std::accumulate(combination.begin(), combination.end(), 0.0);
139  // normalize the probability to get sum of probabilities connected with AttrIdd equal to 1
141  std::transform( combination.begin(), combination.end(), evidence.begin(), std::back_inserter(output), nfunctor );
142  return output;
143  }
144 
145  } //namespace ml
146 } //namespace faif
147 
148 #endif //FAIF_FUSION_HPP
Belief::Beliefs fusion(const typename std::vector< typename Belief::Beliefs > &input)
connect categories using the Dempster-Shafer combination rule, e.g. bel(cat) = bel1(cat) * bel2(cat) ...
Definition: Fusion.hpp:115
Definition: Chain.h:17
Definition: Fusion.hpp:100
Definition: Fusion.hpp:45
the belief concept
Definition: Belief.hpp:22
typedef&#39;s for Dempster-Shafer combination rule (for fusion) and some internal (helping) methods ...
Definition: Fusion.hpp:23
belief is value id with probability
Definition: Belief.hpp:41