PMF.cpp
Go to the documentation of this file.
1 /************************************************************************
2  * Copyright (C) 2012 Eindhoven University of Technology (TU/e). *
3  * All rights reserved. *
4  ************************************************************************
5  * Redistribution and use in source and binary forms, with or without *
6  * modification, are permitted provided that the following conditions *
7  * are met: *
8  * *
9  * 1. Redistributions of source code must retain the above *
10  * copyright notice, this list of conditions and the following *
11  * disclaimer. *
12  * *
13  * 2. Redistributions in binary form must reproduce the above *
14  * copyright notice, this list of conditions and the following *
15  * disclaimer in the documentation and/or other materials *
16  * provided with the distribution. *
17  * *
18  * THIS SOFTWARE IS PROVIDED BY TU/e "AS IS" AND ANY EXPRESS OR *
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *
21  * ARE DISCLAIMED. IN NO EVENT SHALL TU/e OR CONTRIBUTORS BE LIABLE *
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
28  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
29  * DAMAGE. *
30  * *
31  * The views and conclusions contained in the software and *
32  * documentation are those of the authors and should not be *
33  * interpreted as representing official policies, either expressed or *
34  * implied, of TU/e. *
35  ************************************************************************/
36 
37 #include "problib/pdfs/PMF.h"
38 
39 using namespace pbl;
40 
41 PMF::PMF(int domain_size) : PDF(1, PDF::DISCRETE), ptr_(new PMFStruct(domain_size)) {
42 }
43 
44 PMF::PMF(const PMF& pmf) : PDF(1, PDF::DISCRETE), ptr_(pmf.ptr_) {
45  if (ptr_) {
46  ++ptr_->n_ptrs_;
47  }
48 }
49 
51  --ptr_->n_ptrs_;
52 
53  if (ptr_->n_ptrs_ == 0) {
54  delete ptr_;
55  }
56 }
57 
58 PMF& PMF::operator=(const PMF& other) {
59  if (this != &other) {
60  if (ptr_) {
61  --ptr_->n_ptrs_;
62  if (ptr_->n_ptrs_ == 0) {
63  delete ptr_;
64  }
65  }
66 
67  ptr_ = other.ptr_;
68  ++ptr_->n_ptrs_;
69 
70  dimensions_ = other.dimensions_;
71  }
72  return *this;
73 }
74 
75 PMF* PMF::clone() const {
76  return new PMF(*this);
77 }
78 
80  if (ptr_->n_ptrs_ > 1) {
81  --ptr_->n_ptrs_;
82  ptr_ = new PMFStruct(*ptr_);
83  }
84 }
85 
86 double PMF::getProbability(const std::string& value) const {
87  return getProbability(value, ptr_->domain_size_);
88 }
89 
90 double PMF::getProbability(const std::string& value, int domain_size) const {
92  if (it != ptr_->pmf_.end()) {
93  return (*it).second;
94  }
95  // if now probability is known for this value, calculate its probability
96  // based on a uniform distribution over all unknown values.
97  return getProbabilityUnknown(domain_size);
98 }
99 
100 void PMF::setProbability(const std::string& value, double p) {
101  cloneStruct();
102 
104  if (it != ptr_->pmf_.end()) {
105  ptr_->total_prob_ -= (*it).second;
106  (*it).second = p;
107  } else {
108  ptr_->pmf_[value] = p;
109  }
110  ptr_->total_prob_ += p;
111 }
112 
113 void PMF::setExact(const std::string& value) {
114  if (ptr_->n_ptrs_ > 1) {
115  --ptr_->n_ptrs_;
117  } else {
118  ptr_->pmf_.clear();
119  }
120  ptr_->pmf_[value] = 1.0;
121  ptr_->total_prob_ = 1.0;
122 }
123 
124 void PMF::getValues(std::vector<std::string>& values) const {
125  for(std::map<std::string, double>::const_iterator it = ptr_->pmf_.begin(); it != ptr_->pmf_.end(); ++it) {
126  values.push_back((*it).first);
127  }
128 }
129 
130 void PMF::getProbabilities(std::vector<double>& probabilities) const {
131  for(std::map<std::string, double>::const_iterator it = ptr_->pmf_.begin(); it != ptr_->pmf_.end(); ++it) {
132  probabilities.push_back((*it).second);
133  }
134 }
135 
136 bool PMF::getExpectedValue(std::string& v) const {
137  double p_max = 0;
138  for(std::map<std::string, double>::const_iterator it = ptr_->pmf_.begin(); it != ptr_->pmf_.end(); ++it) {
139  if ((*it).second > p_max) {
140  v = (*it).first;
141  p_max = (*it).second;
142  }
143  }
144 
145  if (ptr_->domain_size_ > 0 && p_max < getProbabilityUnknown(ptr_->domain_size_)) {
146  v = "";
147  return false;
148  }
149 
150  return true;
151 }
152 
153 double PMF::getLikelihood(const PDF& pdf) const {
154  assert_msg(pdf.type() == PDF::DISCRETE, "PMF: Likelihood can only be calculated with another PMF.");
155 
156  const PMF* pmf = static_cast<const pbl::PMF*>(&pdf);
157  return getLikelihood(*pmf);
158 }
159 
160 double PMF::getLikelihood(const PMF& other) const {
161  int my_domain_size = ptr_->domain_size_;
162  int other_domain_size = other.ptr_->domain_size_;
163 
164  assert(my_domain_size == -1 || other_domain_size == -1 || my_domain_size == other_domain_size);
165  int domain_size = std::max(my_domain_size, other_domain_size);
166 
167  // determine which pmf has the most determined values, and which one less
168  const PMF* small_pmf = this;
169  const PMF* big_pmf = &other;
170  if (this->ptr_->pmf_.size() > other.ptr_->pmf_.size()) {
171  small_pmf = &other;
172  big_pmf = this;
173  }
174 
175  // determine the likelihood based on all determined values in small_pmf
176  double likelihood = 0;
177  double big_p_total_match = 0; // keeps track of the total probability of all values in big_pmf
178  // that are matched to small_pmf
179  for(std::map<std::string, double>::const_iterator it = small_pmf->ptr_->pmf_.begin(); it != small_pmf->ptr_->pmf_.end(); ++it) {
180  double big_p_v = big_pmf->getProbability((*it).first, domain_size);
181  likelihood += big_p_v * (*it).second;
182  big_p_total_match += big_p_v;
183  }
184 
185  // if the determined values in small_pdf do NOT add up to probability 1, AND
186  // we have not yet matched all values in big_pmf with a total probability of 1, it means
187  // we still need to match the undetermined values in small_pmf and big_pmf. ASSUME a
188  // UNIFORM DISTRIBUTION over the undetermined values in both small_pmf and big_pmf
189  if (small_pmf->ptr_->total_prob_ < 1 && big_p_total_match < 1) {
190  // determine the number of unmatched values. Since we used small_pmf as a basis for
191  // matching above (we matched all its determined values), the number of unmatched values
192  // equals the domain size MINUS the number of determined values
193  int num_unmatched_values = (domain_size - small_pmf->ptr_->pmf_.size());
194  assert(num_unmatched_values > 0);
195 
196  // determine the average probability of an unknown value in big_pmf, assuming
197  // a uniform distribution over all unknown values.
198  double big_p_unknown = (1 - big_p_total_match) / num_unmatched_values;
199  // determine the probability of an unknown value in small_pmf, assuming
200  // a uniform distribution over all unknown values
201  double small_p_unknown = (1 - small_pmf->ptr_->total_prob_) / num_unmatched_values;
202 
203  // add to the likelihood the SUM of big_p_unknown * small_p_unknown over all
204  // unmatches values, which equals num_unmatched_values * big_p_unknown * small_p_unknown
205  likelihood += num_unmatched_values * big_p_unknown * small_p_unknown;
206  }
207 
208  return likelihood;
209 }
210 
214 void PMF::update(const pbl::PMF& other) {
215  assert(this->ptr_->domain_size_ == -1 || other.ptr_->domain_size_ == -1
216  || this->ptr_->domain_size_ == other.ptr_->domain_size_);
217 
218  cloneStruct();
219 
220  this->ptr_->domain_size_ = std::max(this->ptr_->domain_size_, other.ptr_->domain_size_);
221 
222  // calculate likelihood
223  double likelihood = getLikelihood(other);
224 
225  // calculate the current probability of unknown values
226  double p_unknown = getProbabilityUnknown(this->ptr_->domain_size_);
227 
228  std::set<std::string> updated_values;
229 
230  ptr_->total_prob_ = 0;
231  for(std::map<std::string, double>::iterator it = ptr_->pmf_.begin(); it != ptr_->pmf_.end(); ++it) {
232  double new_prob = (*it).second * other.getProbability((*it).first, this->ptr_->domain_size_) / likelihood;
233  (*it).second = new_prob;
234  ptr_->total_prob_ += new_prob;
235  updated_values.insert((*it).first);
236  }
237 
238  for(std::map<std::string, double>::const_iterator it = other.ptr_->pmf_.begin(); it != other.ptr_->pmf_.end(); ++it) {
239  if (updated_values.find((*it).first) == updated_values.end()) {
240  double new_prob = p_unknown * (*it).second / likelihood;
241  ptr_->pmf_[(*it).first] = new_prob;
242  ptr_->total_prob_ += new_prob;
243  }
244  }
245 }
246 
247 void PMF::setDomainSize(int domain_size) {
248  cloneStruct();
249  ptr_->domain_size_ = domain_size;
250 }
251 
252 int PMF::getDomainSize() const {
253  return ptr_->domain_size_;
254 }
255 
258 }
259 
260 double PMF::getProbabilityUnknown(int domain_size) const {
261  if (ptr_->total_prob_ == 1) return 0;
262  assert(domain_size > 0);
263  if (domain_size == (int)ptr_->pmf_.size()) return 0;
264  return (1 - ptr_->total_prob_) / (domain_size - ptr_->pmf_.size());
265 }
266 
268  if (ptr_->total_prob_ == 1) return;
269 
270  assert(ptr_->total_prob_ > 0);
271 
272  cloneStruct();
273 
274  for(std::map<std::string, double>::iterator it = ptr_->pmf_.begin(); it != ptr_->pmf_.end(); ++it) {
275  (*it).second /= ptr_->total_prob_;
276  }
277 
278  ptr_->domain_size_ = ptr_->pmf_.size();
279 
280  ptr_->total_prob_ = 1;
281 }
282 
283 double PMF::getDensity(const arma::vec& v) const {
284  assert_msg(false, "Cannot get density of a PMF");
285  return 0;
286 }
287 
288 double PMF::getMaxDensity() const {
289  assert_msg(false, "Cannot get max density of a PMF");
290  return 0;
291 }
292 
293 std::string PMF::toString(const std::string& indent) const {
294  std::stringstream ss;
295  ss << indent << "PMF(" << ptr_->domain_size_ << ")[";
296 
298  if (it != ptr_->pmf_.end()) {
299  ss << " " << (*it).first << " : " << (*it).second;
300  ++it;
301  for(; it != ptr_->pmf_.end(); ++it) {
302  ss << ", " << (*it).first << " : " << (*it).second;
303  }
304  }
305  ss << " ]";
306  return ss.str();
307 }
308 
309 /* * * * * * * * OBSOLETE * * * * * * * * */
310 
311 std::string PMF::getMostProbableValue() const {
312  std::string v;
313  getExpectedValue(v);
314  return v;
315 }
double getProbability(const std::string &value) const
Returns the probability of the given value.
Definition: PMF.cpp:86
std::string getMostProbableValue() const
Definition: PMF.cpp:311
eT value() const
PMF(int domain_size=-1)
Constructs a discrete probability distribution. The optional parameter domain size states the number ...
Definition: PMF.cpp:41
PDFType type() const
Definition: PDF.cpp:56
void cloneStruct()
Definition: PMF.cpp:79
int dimensions_
Definition: PDF.h:87
double getLikelihood(const PDF &pdf) const
Definition: PMF.cpp:153
double total_prob_
Definition: PMF.h:175
#define assert_msg(_Expression, _Msg)
Definition: globals.h:53
double getMaxDensity() const
Definition: PMF.cpp:288
iterator(field< oT > &in_M, const bool at_end=false)
void setExact(const std::string &value)
Set the probability of the given value to 1. All other values are given a probability of 0...
Definition: PMF.cpp:113
PMF & operator=(const PMF &other)
Assignment operator. The operation is cheap since it only copies a pointer. A deep clone will only be...
Definition: PMF.cpp:58
void normalize()
Definition: PMF.cpp:267
void setDomainSize(int domain_size)
Sets the domain size of this discrete distribution.
Definition: PMF.cpp:247
int domain_size_
Definition: PMF.h:173
const_iterator(const field< oT > &in_M, const bool at_end=false)
void getValues(std::vector< std::string > &values) const
Returns a vector of values for which a probability is specified.
Definition: PMF.cpp:124
std::string toString(const std::string &indent="") const
Represents the PMF as a string for easier console output.
Definition: PMF.cpp:293
bool getExpectedValue(std::string &v) const
Returns in parameter v the expected value for this distribution, i.e., the value with the highest pro...
Definition: PMF.cpp:136
void update(const pbl::PMF &pmf)
Definition: PMF.cpp:214
arma_warn_unused eT max() const
std::map< std::string, double > pmf_
Definition: PMF.h:177
int getDomainSize() const
Returns the domain size of this distribution.
Definition: PMF.cpp:252
void getProbabilities(std::vector< double > &probabilities) const
Returns all probabilities of the known values.
Definition: PMF.cpp:130
double getProbabilityUnknown() const
Definition: PMF.cpp:256
Definition: PDF.h:47
void setProbability(const std::string &value, double p)
Set the probability of a given value.
Definition: PMF.cpp:100
Col< double > vec
PMF * clone() const
Creates a clone of the object. The clone method is cheap since it only copies a pointer. A deep clone will only be created if the original object is modified.
Definition: PMF.cpp:75
virtual ~PMF()
Destructor.
Definition: PMF.cpp:50
This class represents a discrete probability distribution (or probability mass function). Currently, this PMF can only take strings as values.
Definition: PMF.h:52
double getDensity(const arma::vec &v) const
Definition: PMF.cpp:283
PMFStruct * ptr_
Definition: PMF.h:186


problib
Author(s): Sjoerd van den Dries, Jos Elfring
autogenerated on Fri Apr 16 2021 02:32:19