Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions tests/metropolis_hasting_producer_12.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// ---------------------------------------------------------------------
//
// Copyright (C) 2020 by the SampleFlow authors.
//
// This file is part of the SampleFlow library.
//
// The SampleFlow library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE.md at
// the top level directory of SampleFlow.
//
// ---------------------------------------------------------------------


// Test the Metropolis-Hastings producer with a diagonally elongated
// distribution.

#include <iostream>
#include <sampleflow/producers/metropolis_hastings.h>
#include <sampleflow/filters/conversion.h>
#include <sampleflow/consumers/mean_value.h>
#include <valarray>
#include <random>
#include <cmath>


using SampleType = std::valarray<double>;


double log_likelihood (const SampleType &x)
{
std::valarray<double> mu = {0, 0};
std::valarray<double> cov = {{1, 1.5}, {1.5, 3}};

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't compile. But you can just do

  double mu[2] = {0,0};
  double cov[2][2] = {{1,1.5}, {1.5,3}};

Have you checked whether this really corresponds to positive definite matrix?

// FIXME: what's the correct way to do these matrix operations?
return -0.5 * (ln(|cov|) + (x - mu)^T @ cov^-1 @ (x - mu) + k * ln(2 * pi));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, the log_likelihood doesn't have to be normalized, so you can remove the ln(|cov|) factor along with the ln(2*pi) one.

Second, just multiply it out:

Suggested change
return -0.5 * (ln(|cov|) + (x - mu)^T @ cov^-1 @ (x - mu) + k * ln(2 * pi));
return -0.5 * ( (x[0]-mu[0])*cov[0][0]*(x[0]-mu[0]) +
(x[0]-mu[0])*cov[0][1]*(x[1]-mu[1]) +
(x[1]-mu[1])*cov[1][0]*(x[0]-mu[0]) +
(x[1]-mu[1])*cov[1][1]*(x[1]-mu[1]) +

That's not elegant, but it'll do for this test.

}


std::pair<SampleType,double> perturb (const SampleType &x)
{
// FIXME: how to sample MVN(x, cov)?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed today, you don't have to :-)

static std::mt19937 rng;
std::normal_distribution<double> distribution(0, 1);
SampleType y = x;
for (auto &el : y)
y += distribution(rng);
return {y, 1.0};
}


int main ()
{
SampleFlow::Producers::MetropolisHastings<SampleType> mh_sampler;
SampleFlow::Producers::CovarianceMatrix<SampleType> cov_matrix;
SampleFlow::Consumers::MeanValue<SampleType> mean_value;
cov_matrix.connect_to_producer(mh_sampler);
mean_value.connect_to_producer(mh_sampler);
// Sample, starting at an asymmetric point, and creating 100,000 samples
mh_sampler.sample({5, -1}, &log_likelihood, &perturb, 100000);
std::cout << "Mean value = " << mean_value.get() << std::endl;
}