Initial import
This commit is contained in:
commit
56a50eead3
820 changed files with 192077 additions and 0 deletions
124
libLSS/samplers/rgen/gsl_miser.hpp
Normal file
124
libLSS/samplers/rgen/gsl_miser.hpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*+
|
||||
ARES/HADES/BORG Package -- ./libLSS/samplers/rgen/gsl_miser.hpp
|
||||
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
|
||||
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
|
||||
|
||||
Additional contributions from:
|
||||
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
|
||||
|
||||
+*/
|
||||
#ifndef __GSL_RANDOM_NUMBER_MISER_HPP
|
||||
#define __GSL_RANDOM_NUMBER_MISER_HPP
|
||||
|
||||
#include <gsl/gsl_rng.h>
|
||||
#include <gsl/gsl_randist.h>
|
||||
#include <gsl/gsl_monte.h>
|
||||
#include <gsl/gsl_monte_miser.h>
|
||||
#include <cstring>
|
||||
#include "libLSS/tools/errors.hpp"
|
||||
#include "libLSS/samplers/core/random_number.hpp"
|
||||
#include "libLSS/samplers/rgen/gsl_random_number.hpp"
|
||||
|
||||
namespace LibLSS {
|
||||
|
||||
/**
|
||||
* This is an adaptor class for the MISER integrator in GSL.
|
||||
* It handles the life cycle of the MISER object, and support for a generic
|
||||
* functor for the integrand.
|
||||
*/
|
||||
class GSL_Miser {
|
||||
protected:
|
||||
gsl_monte_miser_state *state;
|
||||
size_t Nd;
|
||||
|
||||
template<typename Functor>
|
||||
struct MiserCall {
|
||||
Functor f;
|
||||
|
||||
MiserCall(Functor g) : f(g) {}
|
||||
};
|
||||
|
||||
template<typename Functor>
|
||||
static double adaptor_functor(double *x, size_t, void *params)
|
||||
{
|
||||
MiserCall<Functor> *c = (MiserCall<Functor> *) params;
|
||||
|
||||
return c->f(x);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param dim number of dimensions over which the integration will occur.
|
||||
*/
|
||||
GSL_Miser(size_t dim)
|
||||
: state(0), Nd(dim) {
|
||||
state = gsl_monte_miser_alloc(dim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~GSL_Miser() {
|
||||
gsl_monte_miser_free(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrate the provided integrand over some range, with a maximum number of calls. A bound
|
||||
* on the maximum error is returned.
|
||||
* Here is a use example:
|
||||
*
|
||||
* @code
|
||||
* // ...
|
||||
* size_t calls = 10;
|
||||
* double xl[2] = {0, 0};
|
||||
* double xu[2] = {1, 2};
|
||||
* double value;
|
||||
*
|
||||
* GSL_Miser miser(2); // 2-dimensions
|
||||
* value = miser.integrate(rng, [](double *x) {
|
||||
* // do something with x[0], x[1]
|
||||
* return x[0]*x[0] + x[1]*x[1]; // for example sum(x^2)
|
||||
* }, xl, xu, calls, abserr);
|
||||
* //...
|
||||
* @endcode
|
||||
*
|
||||
* @param rng Class adapting the GSL random number generator
|
||||
* @param f Functor representing the integrand. It must have one pointer to double and return a double.
|
||||
* @param xl lower bound for integration (N-dimension contiguous C-array)
|
||||
* @param xu upper bound for integration
|
||||
* @param calls maximum number of calls
|
||||
* @param abserr return medium for estimated maximum absolute error
|
||||
*
|
||||
*/
|
||||
// Only valid for GSL
|
||||
template<typename Functor,typename A>
|
||||
double integrate(GSL_RandomNumber& rng, Functor f, A& xl, A& xu, size_t calls, double &abserr) {
|
||||
gsl_monte_function mf;
|
||||
MiserCall<Functor> call(f);
|
||||
double result;
|
||||
int err;
|
||||
|
||||
mf.f = &adaptor_functor<Functor>;
|
||||
mf.dim = Nd;
|
||||
mf.params = &call;
|
||||
|
||||
if ((err = gsl_monte_miser_integrate(&mf, &xl[0], &xu[0], Nd, calls, rng.rng, state, &result, &abserr)) != GSL_SUCCESS)
|
||||
error_helper<ErrorGSL>(boost::format("Error while doing monte carlo integration: error code = %d ") % err);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a multi-threaded random number generator deriving from a base "Rng".
|
||||
* This is a helper class to unwrap the GSL base class for the random number generation.
|
||||
* @see integrate(GSL_RandomNumber& rng, Functor f, A& xl, A& xu, size_t calls, double &abserr)
|
||||
*/
|
||||
template<typename Rng, typename Functor, typename A>
|
||||
double integrate(RandomNumberThreaded<Rng>& rng, Functor f, A& xl, A& xu, size_t calls, double &abserr) {
|
||||
return integrate(rng.base(), f, xl, xu, calls, abserr);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
91
libLSS/samplers/rgen/gsl_random_number.hpp
Normal file
91
libLSS/samplers/rgen/gsl_random_number.hpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*+
|
||||
ARES/HADES/BORG Package -- ./libLSS/samplers/rgen/gsl_random_number.hpp
|
||||
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
|
||||
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
|
||||
|
||||
Additional contributions from:
|
||||
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
|
||||
|
||||
+*/
|
||||
#ifndef __GSL_RANDOM_NUMBER_HPP
|
||||
#define __GSL_RANDOM_NUMBER_HPP
|
||||
|
||||
#include <gsl/gsl_rng.h>
|
||||
#include <gsl/gsl_randist.h>
|
||||
#include <cstring>
|
||||
#include "libLSS/tools/errors.hpp"
|
||||
#include "libLSS/samplers/core/random_number.hpp"
|
||||
|
||||
namespace LibLSS {
|
||||
|
||||
class GSL_RandomNumber: public RandomNumber
|
||||
{
|
||||
public:
|
||||
gsl_rng *rng;
|
||||
|
||||
GSL_RandomNumber() :
|
||||
rng(gsl_rng_alloc(gsl_rng_mt19937)) {
|
||||
}
|
||||
|
||||
~GSL_RandomNumber() {
|
||||
gsl_rng_free(rng);
|
||||
}
|
||||
|
||||
virtual double uniform() {
|
||||
return gsl_rng_uniform(rng);
|
||||
}
|
||||
|
||||
virtual double unitexp() {
|
||||
return gsl_ran_exponential(rng, 1.);
|
||||
}
|
||||
|
||||
virtual void seed(unsigned long i) {
|
||||
Console::instance().print<LOG_DEBUG>(boost::format("GSL: Changing random number generation seed with %ld") % i);
|
||||
gsl_rng_set(rng, i);
|
||||
}
|
||||
|
||||
virtual unsigned long get() {
|
||||
return gsl_rng_get(rng);
|
||||
}
|
||||
|
||||
using RandomNumber::poisson;
|
||||
using RandomNumber::gaussian;
|
||||
using RandomNumber::gamma;
|
||||
using RandomNumber::negative_binomial;
|
||||
|
||||
virtual unsigned int poisson(double mean) {
|
||||
return gsl_ran_poisson(rng, mean);
|
||||
}
|
||||
|
||||
virtual unsigned int negative_binomial(double p, double n) {
|
||||
return gsl_ran_negative_binomial(rng, p, n);
|
||||
}
|
||||
|
||||
virtual double gamma(double a, double b) {
|
||||
return gsl_ran_gamma(rng, a, b);
|
||||
}
|
||||
|
||||
virtual void save(H5_CommonFileGroup& g) {
|
||||
boost::multi_array<char, 1> out(boost::extents[gsl_rng_size(rng)]);
|
||||
::memcpy(out.origin(), gsl_rng_state(rng), gsl_rng_size(rng));
|
||||
CosmoTool::hdf5_write_array(g, "state", out);
|
||||
}
|
||||
|
||||
virtual void restore(H5_CommonFileGroup& g, bool flexible) {
|
||||
size_t sz = gsl_rng_size(rng);
|
||||
boost::multi_array<char, 1> in;
|
||||
|
||||
CosmoTool::hdf5_read_array(g, "state", in);
|
||||
|
||||
|
||||
if (in.shape()[0] != sz) {
|
||||
error_helper<ErrorIO>("Could not read state in GSL_RandomNumber");
|
||||
}
|
||||
memcpy(gsl_rng_state(rng), in.origin(), sz);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
231
libLSS/samplers/rgen/slice_sweep.hpp
Normal file
231
libLSS/samplers/rgen/slice_sweep.hpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*+
|
||||
ARES/HADES/BORG Package -- ./libLSS/samplers/rgen/slice_sweep.hpp
|
||||
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
|
||||
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
|
||||
|
||||
Additional contributions from:
|
||||
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
|
||||
|
||||
+*/
|
||||
#ifndef _LIBLSS_SLICE_SWEEP_HPP
|
||||
#define _LIBLSS_SLICE_SWEEP_HPP
|
||||
|
||||
#include "libLSS/mpi/generic_mpi.hpp"
|
||||
#include <cmath>
|
||||
|
||||
// These algorithms are described in https://www.aquila-consortium.org/wiki/index.php/File:Slice_sampling_Neal_97.pdf
|
||||
|
||||
|
||||
namespace LibLSS {
|
||||
|
||||
namespace slice_details {
|
||||
template<typename LogLikelihood>
|
||||
double request(MPI_Communication *comm, LogLikelihood lh, double a, int ROOT) {
|
||||
int job = 1;
|
||||
comm->broadcast_t(&job, 1, ROOT);
|
||||
comm->broadcast_t(&a, 1, ROOT);
|
||||
return lh(a);
|
||||
}
|
||||
|
||||
inline void shutdown(MPI_Communication *comm, double a, int ROOT) {
|
||||
int job = 0;
|
||||
comm->broadcast_t(&job, 1, ROOT);
|
||||
comm->broadcast_t(&a, 1, ROOT);
|
||||
}
|
||||
|
||||
inline int grab_job(MPI_Communication *comm, double& a, int ROOT) {
|
||||
int job;
|
||||
comm->broadcast_t(&job, 1, ROOT);
|
||||
comm->broadcast_t(&a, 1, ROOT);
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Random, typename LogLikelihood>
|
||||
double slice_sweep(MPI_Communication *comm, Random& rng, LogLikelihood lh, double a0, double step, int ROOT = 0)
|
||||
{
|
||||
Console::instance().print<LOG_DEBUG>("Doing slicesweep EARLY init");
|
||||
if (comm->rank() != ROOT) {
|
||||
double v;
|
||||
while (slice_details::grab_job(comm, v, ROOT)) {
|
||||
lh(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
Console::instance().print<LOG_DEBUG>("Doing slicesweep init");
|
||||
double logp0 = slice_details::request(comm, lh, a0, ROOT);
|
||||
double logu = logp0 + std::log(1-rng.uniform());//draw from (0,1], to avoid log(0)
|
||||
Console::instance().c_assert(!std::isnan(logu), "logu must not be a NaN");
|
||||
double rr = rng.uniform();
|
||||
double al = a0 - rr*step;
|
||||
double ar = a0 + (1-rr)*step;
|
||||
|
||||
Console::instance().print<LOG_DEBUG>(boost::format("First loop (logu = %lg)") % logu);
|
||||
while (true) {
|
||||
double logpl = slice_details::request(comm, lh, al, ROOT);
|
||||
if (logpl < logu)
|
||||
break;
|
||||
al -= step;
|
||||
}
|
||||
|
||||
Console::instance().print<LOG_DEBUG>("Second loop");
|
||||
while (true) {
|
||||
double logpr = slice_details::request(comm, lh, ar, ROOT);
|
||||
if (logpr < logu)
|
||||
break;
|
||||
ar += step;
|
||||
}
|
||||
|
||||
Console::instance().print<LOG_DEBUG>("Last loop");
|
||||
while (true) {
|
||||
double a1 = rng.uniform() * (ar - al) + al;
|
||||
double logp1 = slice_details::request(comm, lh, a1, ROOT);
|
||||
|
||||
if (logp1 > logu) {
|
||||
slice_details::shutdown(comm, a1, ROOT);
|
||||
return a1;
|
||||
} else {
|
||||
// Shrink bracket
|
||||
if (a1 > a0)
|
||||
ar = a1;
|
||||
else
|
||||
al = a1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Random, typename LogLikelihood>
|
||||
double slice_sweep(Random& rng, LogLikelihood lh, double a0, double step)
|
||||
{
|
||||
double logp0 = lh(a0);
|
||||
double logu = logp0 + std::log(1-rng.uniform());//draw from (0,1], to avoid log(0)
|
||||
Console::instance().c_assert(!std::isnan(logu), "logu must not be a NaN");
|
||||
double rr = rng.uniform();
|
||||
double al = a0 - rr*step;
|
||||
double ar = a0 + (1-rr)*step;
|
||||
|
||||
while (true) {
|
||||
double logpl = lh(al);
|
||||
if (logpl < logu)
|
||||
break;
|
||||
al -= step;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
double logpr = lh(ar);
|
||||
if (logpr < logu)
|
||||
break;
|
||||
ar += step;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
double a1 = rng.uniform() * (ar - al) + al;
|
||||
double logp1 = lh(a1);
|
||||
|
||||
if (logp1 > logu) {
|
||||
return a1;
|
||||
} else {
|
||||
// Shrink bracket
|
||||
if (a1 > a0)
|
||||
ar = a1;
|
||||
else
|
||||
al = a1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Random, typename LogLikelihood>
|
||||
double slice_sweep_double(MPI_Communication *comm, Random& rng, LogLikelihood lh, double a0, double step, int ROOT = 0)
|
||||
{
|
||||
ConsoleContext<LOG_DEBUG> ctx("slicesweep_double");
|
||||
|
||||
if (comm->rank() != ROOT) {
|
||||
double v;
|
||||
while (slice_details::grab_job(comm, v, ROOT)) {
|
||||
lh(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
ctx.print("INIT");
|
||||
// Find the initial likelihood and the slice level
|
||||
double logp0 = slice_details::request(comm, lh, a0, ROOT);
|
||||
double logu = logp0 + std::log(1-rng.uniform());//draw from (0,1], to avoid log(0)
|
||||
Console::instance().c_assert(!std::isnan(logu), "logu must not be a NaN");
|
||||
|
||||
double rr = rng.uniform();
|
||||
double al = a0 - rr*step;
|
||||
double ar = a0 + (1-rr)*step;
|
||||
|
||||
ctx.print(boost::format("Step defining loop (logu = %lg)") % logu);
|
||||
double logpl = slice_details::request(comm, lh, al, ROOT);
|
||||
double logpr = slice_details::request(comm, lh, ar, ROOT);
|
||||
while (logpl >= logu || logpr >= logu) {
|
||||
double v= rng.uniform();
|
||||
if (v < 0.5) {
|
||||
al -= (ar - al);
|
||||
logpl = slice_details::request(comm, lh, al, ROOT);
|
||||
ctx.print(boost::format("new al=%g, logpl = %g") % al % logpl);
|
||||
} else {
|
||||
ar += (ar - al);
|
||||
logpr = slice_details::request(comm, lh, ar, ROOT);
|
||||
ctx.print(boost::format("new ar=%g, logpr = %g") % ar % logpr);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.print("Sampling loop");
|
||||
while (true) {
|
||||
double a1 = rng.uniform() * (ar - al) + al;
|
||||
double logp1 = slice_details::request(comm, lh, a1, ROOT);
|
||||
|
||||
if (logp1 > logu) {
|
||||
double ar_hat = ar;
|
||||
double al_hat = al;
|
||||
double logpl_hat = slice_details::request(comm, lh, al_hat, ROOT);
|
||||
double logpr_hat = slice_details::request(comm, lh, ar_hat, ROOT);
|
||||
bool not_accepted = false;
|
||||
|
||||
ctx.print(boost::format("Got a candidate at a1=%g") % a1);
|
||||
|
||||
while ((ar_hat - al_hat) > (1.1*step) && !not_accepted) {
|
||||
double am = 0.5 * (ar_hat+al_hat);
|
||||
|
||||
bool D = ((a0 < am && a1 >= am) || (a0 >= am && a1 < am));
|
||||
|
||||
if (a1 < am) {
|
||||
ar_hat = am;
|
||||
logpr_hat = slice_details::request(comm, lh, ar_hat, ROOT);
|
||||
} else {
|
||||
al_hat = am;
|
||||
logpl_hat = slice_details::request(comm, lh, al_hat, ROOT);
|
||||
}
|
||||
|
||||
ctx.print(boost::format("ar_hat=%lg, al_hat=%lg, logpl_hat=%lg, logpr_hat=%lg, D=%d") % ar_hat % al_hat % logpl_hat % logpr_hat % D);
|
||||
|
||||
if (D && logu >= logpl_hat && logu >= logpr_hat) {
|
||||
// Not acceptable. Try again.
|
||||
ctx.print("Not good");
|
||||
not_accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Go back outside
|
||||
if (not_accepted)
|
||||
continue;
|
||||
|
||||
slice_details::shutdown(comm, a1, ROOT);
|
||||
return a1;
|
||||
} else {
|
||||
// Shrink bracket
|
||||
if (a1 > a0)
|
||||
ar = a1;
|
||||
else
|
||||
al = a1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue