MUQ  0.4.3
MixtureDistribution.cpp
Go to the documentation of this file.
2 
4 
5 using namespace muq::Utilities;
6 using namespace muq::Modeling;
7 
8 MixtureDistribution::MixtureDistribution(std::vector<std::shared_ptr<Distribution>> const& componentsIn,
9  Eigen::VectorXd const& probsIn) : Distribution(componentsIn.at(0)->varSize, componentsIn.at(0)->hyperSizes),
10  components(componentsIn), probs(probsIn)
11 {
12 
13  probs = probs / probs.sum();
14 
15  // Make sure the components and probabilities have the same size
16  if(components.size() != probs.size())
17  {
18  std::stringstream msg;
19  msg << "Could not construct MixtureDistribution. Number of components is " << components.size() << " but " << probs.size() << " probabilities were given.";
20  throw std::runtime_error(msg.str());
21  }
22 
23  // Make sure all the components have the same number and size of inputs
24  for(unsigned int i=1; i<components.size(); ++i)
25  {
26  if(components.at(i)->varSize != varSize){
27  std::stringstream msg;
28  msg << "Could not construct MixtureDistribution. Component " << i << " has a dimension of " << components.at(i)->varSize << " but component 0 has a dimension of " << varSize;
29  throw std::runtime_error(msg.str());
30  }
31 
32  if(components.at(i)->hyperSizes.size() != hyperSizes.size()){
33  std::stringstream msg;
34  msg << "Could not construct MixtureDistribution. Component " << i << " has " << components.at(i)->hyperSizes.size() << " hyperparameters but component 0 has " << hyperSizes.size() << " hyperparameters.";
35  throw std::runtime_error(msg.str());
36  }
37 
38  for(unsigned int j=0; j<hyperSizes.size(); ++j){
39  if(components.at(i)->hyperSizes(j) != hyperSizes(j)){
40  std::stringstream msg;
41  msg << "Could not construct MixtureDistribution. Hyperparameter " << j << " of component " << i << " has dimension " << components.at(i)->hyperSizes(j) << " but this hyperparameter in component 0 has dimension " << hyperSizes(j);
42  throw std::runtime_error(msg.str());
43  }
44  }
45  }
46 
47 }
48 
49 
51 {
52  double pdf = 0.0;
53  for(unsigned int i=0; i<components.size(); ++i)
54  pdf += probs(i)*std::exp(components.at(i)->LogDensity(inputs));
55 
56  return std::log(pdf);
57 }
58 
59 Eigen::VectorXd MixtureDistribution::GradLogDensityImpl(unsigned int wrt,
60  ref_vector<Eigen::VectorXd> const& inputs)
61 {
62  unsigned int gradDim = (wrt==0) ? varSize : hyperSizes(wrt-1);
63 
64  double pdf = 0.0;
65  Eigen::VectorXd grad_pdf = Eigen::VectorXd::Zero(gradDim);
66 
67  for(unsigned int i=0; i<components.size(); ++i){
68  double comp_pdf = std::exp(components.at(i)->LogDensity(inputs));
69  pdf += probs(i)*comp_pdf;
70  grad_pdf += probs(i)*comp_pdf * components.at(i)->GradLogDensity(wrt,inputs);
71  }
72 
73  return (1.0/pdf) * grad_pdf;
74 }
75 
76 
78 {
79  // Pick a component at random
80  int randInd = RandomGenerator::GetDiscrete(probs);
81 
82  // Return a sample of the random index
83  return components.at(randInd)->Sample(inputs);
84 }
const unsigned int varSize
Definition: Distribution.h:145
const Eigen::VectorXi hyperSizes
Definition: Distribution.h:146
virtual Eigen::VectorXd GradLogDensityImpl(unsigned int wrt, ref_vector< Eigen::VectorXd > const &inputs) override
virtual Eigen::VectorXd SampleImpl(ref_vector< Eigen::VectorXd > const &inputs) override
Sample the distribution.
std::vector< std::shared_ptr< Distribution > > components
virtual double LogDensityImpl(ref_vector< Eigen::VectorXd > const &inputs) override
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...
Definition: WorkPiece.h:37