MUQ  0.4.3
InverseGammaProposal.cpp
Go to the documentation of this file.
3 
7 
11 
13 
14 namespace pt = boost::property_tree;
15 using namespace muq::Modeling;
16 using namespace muq::SamplingAlgorithms;
17 using namespace muq::Utilities;
18 
20 
21 InverseGammaProposal::InverseGammaProposal(pt::ptree pt,
22  std::shared_ptr<AbstractSamplingProblem> prob) : MCMCProposal(pt,prob),
23  alpha(ExtractAlpha(prob,pt.get<std::string>("InverseGammaNode"))),
24  beta(ExtractBeta(prob,pt.get<std::string>("InverseGammaNode"))),
25  gaussInfo(ExtractGaussInfo(prob,pt.get<std::string>("GaussianNode"))),
26  varModel(ExtractVarianceModel(prob,pt.get<std::string>("GaussianNode"),pt.get<std::string>("InverseGammaNode"))),
27  gaussMean(ExtractMean(prob,pt.get<std::string>("GaussianNode")))
28 {
29 }
30 
31 
32 Eigen::VectorXd InverseGammaProposal::GetGaussianInput(std::shared_ptr<SamplingState> const& currentState) const
33 {
34  // Extract the model inputs from the sampling state
36  for(auto& ind : std::get<1>(gaussInfo)){
37  inputs.push_back(std::cref(currentState->state.at(ind)));
38  }
39 
40  // Evaluate the model
41  return std::get<0>(gaussInfo)->Evaluate(inputs).at(std::get<2>(gaussInfo));
42 }
43 
44 
45 std::shared_ptr<SamplingState> InverseGammaProposal::Sample(std::shared_ptr<SamplingState> const& currentState) {
46 
47  // the mean of the proposal is the current point
48  std::vector<Eigen::VectorXd> props = currentState->state;
49  Eigen::VectorXd gaussState = GetGaussianInput(currentState);
50 
51  Eigen::VectorXd varOnes = Eigen::VectorXd::Ones(varModel->outputSizes(0));
52  Eigen::VectorXd varZeros = Eigen::VectorXd::Zero(varModel->inputSizes(0));
53 
54  Eigen::VectorXd newAlpha = alpha + 0.5*varModel->Gradient(0,0,varZeros,varOnes);
55  Eigen::VectorXd newBeta = beta + 0.5*varModel->Gradient(0,0,varZeros, (gaussState - gaussMean).array().pow(2).matrix().eval());
56 
57  props.at(blockInd) = InverseGamma(newAlpha, newBeta).Sample();
58 
59  // store the new state in the output
60  return std::make_shared<SamplingState>(props, 1.0);
61 }
62 
63 double InverseGammaProposal::LogDensity(std::shared_ptr<SamplingState> const& currState,
64  std::shared_ptr<SamplingState> const& propState) {
65  Eigen::VectorXd gaussState = GetGaussianInput(currState);
66  Eigen::VectorXd const& sigmaState = propState->state.at(blockInd);
67 
68  Eigen::VectorXd varOnes = Eigen::VectorXd::Ones(varModel->outputSizes(0));
69  Eigen::VectorXd varZeros = Eigen::VectorXd::Zero(varModel->inputSizes(0));
70 
71  Eigen::VectorXd newAlpha = alpha + 0.5*varModel->Gradient(0,0,varZeros,varOnes);
72 
73  Eigen::VectorXd newBeta = beta + 0.5*varModel->Gradient(0,0,varZeros, (gaussState - gaussMean).array().pow(2).matrix().eval());
74 
75  return InverseGamma(newAlpha, newBeta).LogDensity(sigmaState);
76 }
77 
78 Eigen::VectorXd InverseGammaProposal::ExtractMean(std::shared_ptr<AbstractSamplingProblem> prob,
79  std::string const& gaussNode)
80 {
81  // Cast the abstract base class into a sampling problem
82  std::shared_ptr<SamplingProblem> prob2 = std::dynamic_pointer_cast<SamplingProblem>(prob);
83  if(prob2==nullptr){
84  throw std::runtime_error("Could not downcast AbstractSamplingProblem to SamplingProblem.");
85  }
86 
87  // From the sampling problem, extract the ModPiece and try to cast it to a ModGraphPiece
88  std::shared_ptr<ModPiece> targetDens = prob2->GetDistribution();
89  std::shared_ptr<ModGraphPiece> targetDens2 = std::dynamic_pointer_cast<ModGraphPiece>(targetDens);
90  if(targetDens2==nullptr){
91  throw std::runtime_error("Could not downcast target density to ModGraphPiece.");
92  }
93 
94  // Get the graph
95  auto graph = targetDens2->GetGraph();
96 
97  // Get the Gaussian node
98  auto gaussPiece = graph->GetPiece(gaussNode);
99  if(gaussPiece==nullptr){
100  throw std::runtime_error("Could not find " + gaussNode + " node.");
101  }
102 
103  // try to cast the gaussPiece to a density
104  auto dens = std::dynamic_pointer_cast<Density>(gaussPiece);
105  if(dens==nullptr){
106  throw std::runtime_error("Could not convert specified Gausssian ModPiece to Density.");
107  }
108 
109  auto gaussDist = std::dynamic_pointer_cast<Gaussian>(dens->GetDistribution());
110  if(gaussDist==nullptr){
111  throw std::runtime_error("Could not cast Gausssian ModPiece to Gaussian.");
112  }
113 
114  return gaussDist->GetMean();
115 }
116 
117 std::shared_ptr<InverseGamma> InverseGammaProposal::ExtractInverseGamma(std::shared_ptr<AbstractSamplingProblem> prob, std::string const& igNode)
118 {
119  // Cast the abstract base class into a sampling problem
120  std::shared_ptr<SamplingProblem> prob2 = std::dynamic_pointer_cast<SamplingProblem>(prob);
121  if(prob2==nullptr){
122  throw std::runtime_error("Could not downcast AbstractSamplingProblem to SamplingProblem.");
123  }
124 
125  // From the sampling problem, extract the ModPiece and try to cast it to a ModGraphPiece
126  std::shared_ptr<ModPiece> targetDens = prob2->GetDistribution();
127  std::shared_ptr<ModGraphPiece> targetDens2 = std::dynamic_pointer_cast<ModGraphPiece>(targetDens);
128  if(targetDens2==nullptr){
129  throw std::runtime_error("Could not downcast target density to ModGraphPiece.");
130  }
131 
132  // Get the graph
133  auto graph = targetDens2->GetGraph();
134 
135  // Get the Gaussian node
136  auto piece = graph->GetPiece(igNode);
137  if(piece==nullptr){
138  throw std::runtime_error("Could not find " + igNode + " node.");
139  }
140 
141  // try to cast the gaussPiece to a density
142  auto dens = std::dynamic_pointer_cast<Density>(piece);
143  if(dens==nullptr){
144  throw std::runtime_error("Could not convert specified InverseGamma ModPiece to Density.");
145  }
146 
147  auto dist = std::dynamic_pointer_cast<InverseGamma>(dens->GetDistribution());
148  if(dist==nullptr){
149  throw std::runtime_error("Could not convert specified InverseGamma ModPiece to InverseGamma distribution.");
150  }
151 
152  return dist;
153 }
154 
155 Eigen::VectorXd InverseGammaProposal::ExtractAlpha(std::shared_ptr<AbstractSamplingProblem> prob, std::string const& igNode)
156 {
157  return ExtractInverseGamma(prob,igNode)->alpha;
158 }
159 
160 Eigen::VectorXd InverseGammaProposal::ExtractBeta(std::shared_ptr<AbstractSamplingProblem> prob, std::string const& igNode)
161 {
162  return ExtractInverseGamma(prob,igNode)->beta;
163 }
164 
165 std::tuple<std::shared_ptr<muq::Modeling::ModPiece>, std::vector<int>, int> InverseGammaProposal::ExtractGaussInfo(std::shared_ptr<AbstractSamplingProblem> prob, std::string const& gaussNode)
166 {
167 
168  // Cast the abstract base class into a sampling problem
169  std::shared_ptr<SamplingProblem> prob2 = std::dynamic_pointer_cast<SamplingProblem>(prob);
170  if(prob2==nullptr){
171  throw std::runtime_error("Could not downcast AbstractSamplingProblem to SamplingProblem.");
172  }
173 
174  // From the sampling problem, extract the ModPiece and try to cast it to a ModGraphPiece
175  std::shared_ptr<ModPiece> targetDens = prob2->GetDistribution();
176  std::shared_ptr<ModGraphPiece> targetDens2 = std::dynamic_pointer_cast<ModGraphPiece>(targetDens);
177  if(targetDens2==nullptr){
178  throw std::runtime_error("Could not downcast target density to ModGraphPiece.");
179  }
180 
181  // Get the graph
182  auto graph = targetDens2->GetGraph();
183 
184  // Get a pointer to the input to the Gaussian piece
185  std::string inputName = graph->GetParent(gaussNode,0);
186 
187  std::shared_ptr<ModPiece> gaussInputPiece;
188  std::vector<int> inputInds;
189  if(inputName==gaussNode+"_0"){
190  auto piece = std::dynamic_pointer_cast<ModPiece>(graph->GetPiece(gaussNode));
191  assert(piece!=nullptr);
192 
193  gaussInputPiece = std::make_shared<IdentityOperator>(piece->inputSizes(0));
194  inputInds = std::vector<int>{0};
195  }else{
196  auto graphPiece = targetDens2->GetSubModel(inputName);
197  inputInds = targetDens2->MatchInputs(graphPiece);
198  gaussInputPiece = std::dynamic_pointer_cast<ModPiece>(graphPiece);
199  }
200 
201 
202  // Make sure we were able to match all the inputs
203  for(auto& ind : inputInds){
204  if(ind<0){
205  throw std::runtime_error("Something went wrong in constructing Gaussian input model and not all inputs could be matched to the original graph.");
206  }
207  }
208 
209  // Figure out which output of the parent node is passed to the Gaussian
210  int gaussInd;
211  for(auto edge : graph->GetEdges(inputName, gaussNode)){
212  if(edge.second==0){
213  gaussInd=edge.first;
214  break;
215  }
216  }
217 
218  return std::make_tuple(gaussInputPiece, inputInds, gaussInd);
219 }
220 
221 std::shared_ptr<muq::Modeling::ModPiece> InverseGammaProposal::ExtractVarianceModel(std::shared_ptr<AbstractSamplingProblem> prob, std::string const& gaussNode, std::string const& igNode)
222 {
223  std::shared_ptr<SamplingProblem> prob2 = std::dynamic_pointer_cast<SamplingProblem>(prob);
224  if(prob2==nullptr){
225  throw std::runtime_error("Could not downcast AbstractSamplingProblem to SamplingProblem.");
226  }
227 
228  // From the sampling problem, extract the ModPiece and try to cast it to a ModGraphPiece
229  std::shared_ptr<ModPiece> targetDens = prob2->GetDistribution();
230  std::shared_ptr<ModGraphPiece> targetDens2 = std::dynamic_pointer_cast<ModGraphPiece>(targetDens);
231  if(targetDens2==nullptr){
232  throw std::runtime_error("Could not downcast target density to ModGraphPiece.");
233  }
234 
235  // Get the graph
236  auto graph = targetDens2->GetGraph();
237 
238  // Get a pointer to the variance input to the Gaussian piece
239  std::string inputName = graph->GetParent(gaussNode,1);
240  auto varPiece = targetDens2->GetSubModel(inputName);
241 
242  // Make sure there is only one input
243  if(varPiece->inputSizes.size()!=1){
244  throw std::runtime_error("The Gaussian variance can only depend on one input parameter.");
245  }
246 
247  if(varPiece->outputSizes.size()!=1){
248  throw std::runtime_error("The Gaussian variance can only have one output.");
249  }
250 
251  // Make sure the input to the variance piece matches the input to the hyper prior
252  auto hyperPrior = targetDens2->GetSubModel(igNode);
253  std::vector<int> sharedInds = varPiece->MatchInputs(hyperPrior);
254 
255  if((sharedInds.size()!=1)||(sharedInds.at(0)<0)){
256  throw std::runtime_error("Something is strange with the WorkGraph. Could not match the input of the hyperprior with a path to the variance of the Gaussian node.");
257  }
258 
259  return varPiece;
260 }
REGISTER_MCMC_PROPOSAL(InverseGammaProposal) InverseGammaProposal
virtual double LogDensity(ref_vector< Eigen::VectorXd > const &inputs)
Evaluate the log-density.
Eigen::VectorXd Sample(ref_vector< Eigen::VectorXd > const &inputs)
Sample the distribution.
Defines a proposal using the analytic conditional Inverse Gamma distribution for the variance of a Ga...
const Eigen::VectorXd alpha
The prior value of alpha.
virtual Eigen::VectorXd GetGaussianInput(std::shared_ptr< SamplingState > const &currentState) const
virtual std::shared_ptr< SamplingState > Sample(std::shared_ptr< SamplingState > const &currentState) override
static std::shared_ptr< muq::Modeling::ModPiece > ExtractVarianceModel(std::shared_ptr< AbstractSamplingProblem > prob, std::string const &gaussNode, std::string const &igNode)
const Eigen::VectorXd beta
The prior value of beta.
std::tuple< std::shared_ptr< muq::Modeling::ModPiece >, std::vector< int >, int > gaussInfo
The index of the Gaussian block.
static Eigen::VectorXd ExtractMean(std::shared_ptr< AbstractSamplingProblem > prob, std::string const &gaussNode)
std::shared_ptr< muq::Modeling::ModPiece > varModel
A ModPiece containing an orthogonal matrix mapping the parameters to Gaussian variance.
virtual double LogDensity(std::shared_ptr< SamplingState > const &currState, std::shared_ptr< SamplingState > const &propState) override
static std::tuple< std::shared_ptr< muq::Modeling::ModPiece >, std::vector< int >, int > ExtractGaussInfo(std::shared_ptr< AbstractSamplingProblem > prob, std::string const &gaussNode)
static Eigen::VectorXd ExtractBeta(std::shared_ptr< AbstractSamplingProblem > prob, std::string const &igNode)
static Eigen::VectorXd ExtractAlpha(std::shared_ptr< AbstractSamplingProblem > prob, std::string const &igNode)
const Eigen::VectorXd gaussMean
The mean of the Gaussian distribution.
static std::shared_ptr< muq::Modeling::InverseGamma > ExtractInverseGamma(std::shared_ptr< AbstractSamplingProblem > prob, std::string const &igNode)
std::shared_ptr< AbstractSamplingProblem > prob
Definition: MCMCProposal.h:81
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...
Definition: WorkPiece.h:37
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.h:3956