Skip to content

Commit

Permalink
Testing importance sampling in 3 dimensions. In 1 it works, in 3 it i…
Browse files Browse the repository at this point in the history
…s not clear yet.
  • Loading branch information
adolfomunoz committed May 3, 2024
1 parent ace2b7f commit 556ff04
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 34 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ add_executable(test-random-sequence main/compilation-tests/random-sequence.cc)
add_executable(test-concat main/compilation-tests/concat.cc)
add_executable(test-covariance main/compilation-tests/covariance.cc)
add_executable(test-inverse main/compilation-tests/inverse.cc)
add_executable(test-region-sample main/compilation-tests/region-sample.cc)
add_executable(test-region-sample-3d main/compilation-tests/region-sample-3d.cc)

##########
# FOR DOCUMENTATION
Expand Down
61 changes: 61 additions & 0 deletions main/compilation-tests/region-sample-3d.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "../../src/newton-cotes/region.h"
#include "../../src/multidimensional-range.h"
#include <random>
#include <string>
#include <iomanip>
#include <cmath>

int main(int argc, char** argv) {
std::size_t bins = 3, samples = 100;
std::array<float,3> xmin{0,0,0}, xmax{1,1,1};

for (int i = 0;i<(argc-1);++i) {
if (std::string(argv[i])=="-bins") bins = std::atoi(argv[++i]);
else if (std::string(argv[i])=="-samples") samples = std::atoi(argv[++i]);
else if (std::string(argv[i])=="-xmin") {
xmin[0] = std::atof(argv[++i]);
xmin[1] = std::atof(argv[++i]);
xmin[2] = std::atof(argv[++i]);
}
else if (std::string(argv[i])=="-xmax") {
xmax[0] = std::atof(argv[++i]);
xmax[1] = std::atof(argv[++i]);
xmax[2] = std::atof(argv[++i]);
}
}

auto f = [] (std::array<float,3> x) {
return std::sin(0.5*x[0]*M_PI) + std::cos(0.5*x[1]*M_PI) + x[2];
};

auto r = viltrum::region(f,viltrum::simpson, viltrum::range_primary<3>());

std::vector<float> probs(bins*bins*bins,0), hist(bins*bins*bins,0);

std::array<float,3> dx;
for (std::size_t c = 0; c<3; ++c) dx[c] = (xmax[c]-xmin[c])/bins;
for (auto p : viltrum::multidimensional_range(std::array<size_t,3>{bins,bins,bins})) {
std::array<float,3> x;
for (std::size_t c = 0; c<3; ++c) x[c] = (float(p[c])+0.5)*dx[c] + xmin[c];
probs[p[0]+bins*p[1]+bins*bins*p[2]] = r.pdf_subrange(x,viltrum::range(xmin,xmax));
}

std::random_device rd;
std::mt19937 rng(rd());
std::uniform_real_distribution<float> dist(0,1);
for (std::size_t i = 0; i<samples; ++i) {
std::array<float,3> smp;
for (std::size_t c = 0; c<3; ++c) smp[c]=dist(rng);
auto x = r.sample_subrange(smp,viltrum::range(xmin,xmax));
std::array<std::size_t,3> p;
for (std::size_t c = 0; c<3; ++c) p[c] = bins*(x[c]-xmin[c])/(xmax[c]-xmin[c]);
hist[p[0]+bins*p[1]+bins*bins*p[2]] += float(bins*bins*bins)/float(samples);
}

float tot = 0;
for (float x : probs) { tot+=x; std::cout<<std::setw(6)<<std::setprecision(3)<<x<<" "; }
std::cout<<" [ "<<std::setw(6)<<std::setprecision(3)<<tot<< " ] "<<std::endl;
tot = 0;
for (float x : hist) { tot+=x; std::cout<<std::setw(6)<<std::setprecision(3)<<x<<" "; }
std::cout<<" [ "<<std::setw(6)<<std::setprecision(3)<<tot<< " ] "<<std::endl;
}
53 changes: 53 additions & 0 deletions main/compilation-tests/region-sample.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "../../src/newton-cotes/region.h"
#include <random>
#include <string>
#include <iomanip>

int main(int argc, char** argv) {
float p0 = 1, p1 = 0.2, p2 = 1;
std::size_t bins = 6, samples = 100;
float xmin = 0.0, xmax = 1.0;

for (int i = 0;i<(argc-1);++i) {
if (std::string(argv[i])=="-bins") bins = std::atoi(argv[++i]);
else if (std::string(argv[i])=="-samples") samples = std::atoi(argv[++i]);
else if (std::string(argv[i])=="-p0") p0 = std::atof(argv[++i]);
else if (std::string(argv[i])=="-p1") p1 = std::atof(argv[++i]);
else if (std::string(argv[i])=="-p2") p2 = std::atof(argv[++i]);
else if (std::string(argv[i])=="-xmin") xmin = std::atof(argv[++i]);
else if (std::string(argv[i])=="-xmax") xmax = std::atof(argv[++i]);
}

auto f = [p0,p1,p2] (std::array<float,1> x) {
return p0+(-3*p0+4*p1-p2)*x[0] + (2*p0-4*p1+2*p2)*x[0]*x[0];
};

auto r = viltrum::region(f,viltrum::simpson, viltrum::range(0.0f,1.0f));

std::vector<float> probs(bins,0), hist(bins,0);

float dx = (xmax-xmin)/bins;
for (std::size_t i = 0; i<bins; ++i) {
std::array<float,1> x;
x[0] = (float(i)+0.5)*dx + xmin;
probs[i] = r.pdf_subrange(x,viltrum::range(xmin,xmax));
}

std::random_device rd;
std::mt19937 rng(rd());
std::uniform_real_distribution<float> dist(0,1);
for (std::size_t i = 0; i<samples; ++i) {
std::array<float,1> smp;
smp[0]=dist(rng);
auto x = r.sample_subrange(smp,viltrum::range(xmin,xmax));
std::size_t bin = bins*(x[0]-xmin)/(xmax-xmin);
hist[bin] += float(bins)/float(samples);
}

float tot = 0;
for (float x : probs) { tot+=x; std::cout<<std::setw(6)<<std::setprecision(3)<<x<<" "; }
std::cout<<" [ "<<std::setw(6)<<std::setprecision(3)<<tot<< " ] "<<std::endl;
tot = 0;
for (float x : hist) { tot+=x; std::cout<<std::setw(6)<<std::setprecision(3)<<x<<" "; }
std::cout<<" [ "<<std::setw(6)<<std::setprecision(3)<<tot<< " ] "<<std::endl;
}
48 changes: 30 additions & 18 deletions src/newton-cotes/region.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ class Region {
}

private:
template<typename MA, std::size_t DIMSUB>
template<typename MA, std::size_t DIMSUB, typename Norm = NormDefault>
Float sample_sub(const MA& ma,
const Float& s, const std::array<Float,DIMSUB>& a, const std::array<Float,DIMSUB>& b) const {
const Float& s, const std::array<Float,DIMSUB>& a, const std::array<Float,DIMSUB>& b,
const Norm& norm = Norm()) const {
if constexpr (MA::dimensions > DIMSUB)
return sample_sub(ma.fold(quadrature,DIMSUB),s,a,b);
else if constexpr (MA::dimensions > 1)
Expand All @@ -185,43 +186,54 @@ class Region {
},MA::dimensions-1),s,a,b);
else
return ma.fold([&] (const auto& v) {
return quadrature.sample_normalized(s,a[0],b[0],v); }).value();
return quadrature.sample_normalized(s,a[0],b[0],v,norm); }).value();
}

template<typename MA, std::size_t DIMSUB>
template<typename MA, std::size_t DIMSUB, typename Norm = NormDefault>
std::array<Float,DIMSUB> sample_subrange_i(const MA& ma,
const std::array<Float,DIMSUB>& sol_i,
const std::array<Float,DIMSUB>& s, const std::array<Float,DIMSUB>& a,
const std::array<Float,DIMSUB>& b) const {
const std::array<Float,DIMSUB>& b,
const Norm& norm = Norm()) const {
if constexpr (MA::dimensions > DIMSUB)
return sample_subrange_i(ma.fold(quadrature,DIMSUB),sol_i,s,a,b);
return sample_subrange_i(ma.fold(quadrature,DIMSUB),sol_i,s,a,b,norm);
else {
std::array<Float,DIMSUB> sol = sol_i;
sol[MA::dimensions-1] = sample_sub(ma,s[MA::dimensions-1],a,b);
sol[MA::dimensions-1] = sample_sub(ma,s[MA::dimensions-1],a,b,norm);
if constexpr (MA::dimensions == 1)
return sol;
else
sample_subrange_i(
return sample_subrange_i(
ma.fold([&] (const auto& v) {
quadrature.at(sol[MA::dimensions-1],v);
},MA::dimensions-1),sol,s,a,b);
return quadrature.at(sol[MA::dimensions-1],v);
},MA::dimensions-1),sol,s,a,b,norm);
}
}
public:
template<std::size_t DIMSUB>
template<std::size_t DIMSUB,typename Norm = NormDefault>
std::array<Float,DIMSUB> sample_subrange(const std::array<Float,DIMSUB>& s, const std::array<Float,DIMSUB>& a,
const std::array<Float,DIMSUB>& b) const {
const std::array<Float,DIMSUB>& b, const Norm& norm = Norm()) const {
static_assert(DIM>=DIMSUB,"Cannot calculate the subrange sample for that many dimensions, as the region has less dimensions");
std::array<Float,DIMSUB> sol;
return range().pos_from_range(
sample_subrabge_i(data,sol,s,range().pos_in_range(a),range().pos_in_range(b)));
sample_subrange_i(data,sol,s,range().pos_in_range(a),range().pos_in_range(b),norm));
}

template<std::size_t DIMSUB>
std::array<Float,DIMSUB> pdf_subrange(const std::array<Float,DIMSUB>& pos, const std::array<Float,DIMSUB>& a,
const std::array<Float,DIMSUB>& b) const {
template<std::size_t DIMSUB,typename Norm = NormDefault>
std::array<Float,DIMSUB> sample_subrange(const std::array<Float,DIMSUB>& s, const Range<Float,DIMSUB>& range, const Norm& norm = Norm()) const {
return this->sample_subrange(s,range.min(),range.max(),norm);
}

template<std::size_t DIMSUB,typename Norm = NormDefault>
Float pdf_subrange(const std::array<Float,DIMSUB>& pos, const std::array<Float,DIMSUB>& a,
const std::array<Float,DIMSUB>& b,const Norm& norm = Norm()) const {
static_assert(DIM>=DIMSUB,"Cannot calculate the subrange pdf for that many dimensions, as the region has less dimensions");
return this->approximation_at(pos)/this->integral_subrange(a,b);
return Range(a,b).volume()*norm(this->approximation_at(pos))/(norm(this->integral_subrange(a,b)));
}

template<std::size_t DIMSUB,typename Norm = NormDefault>
Float pdf_subrange(const std::array<Float,DIMSUB>& pos, const Range<Float,DIMSUB>& range, const Norm& norm = Norm()) const {
return this->pdf_subrange(pos,range.min(),range.max(),norm);
}

template<typename F>
Expand Down Expand Up @@ -314,7 +326,7 @@ auto region(const F& f, const Q& q,
}

template<typename Float, typename F, typename Q, std::size_t DIM>
auto region(const F& f, const Q& q, const Range<Float,DIM> range) {
auto region(const F& f, const Q& q, const Range<Float,DIM>& range) {
return Region<Float,Q,DIM,std::decay_t<decltype(f(range.min()))>>(f,q,range);
}

Expand Down
24 changes: 8 additions & 16 deletions src/newton-cotes/rules.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <array>
#include "../control-variates/norm.h"

namespace viltrum {

Expand Down Expand Up @@ -95,17 +96,8 @@ struct Simpson {

//I had to create this function, otherwise c++ returns -nans for a cube root of a negative number, even though
//it's a cube root
float cuberoot(float x){
float cube_root;
if(x < 0)
{
x = abs(x);
cube_root = pow(x,1./3.)*(-1);
}
else{
cube_root = pow(x,1./3.);
}
return cube_root;
constexpr static float cuberoot(float x) {
return (x<0)?(-1*pow(-x,1./3.)):pow(x,1./3.);
}

//Name cdf, inv_cdf and sample_normalized as you wish
Expand All @@ -116,8 +108,7 @@ struct Simpson {
}

template<typename Float, typename T>
constexpr std::vector<T> inv_cdf(Float x, const std::array<T,samples>& points)
{
constexpr std::vector<T> inv_cdf(Float x, const std::array<T,samples>& points) const {
std::vector<T> solutions;

auto coeff = coefficients(points);
Expand Down Expand Up @@ -150,12 +141,13 @@ struct Simpson {
b -> Maximum range value
p -> Polynomial sample points
*/
template<typename Float, typename T>
constexpr T sample_normalized(Float s, Float a, Float b, const std::array<T,samples>& p){
template<typename Float, typename T, typename Norm = NormDefault>
constexpr T sample_normalized(Float s, Float a, Float b, const std::array<T,samples>& p,
const Norm& norm = Norm()) const {
auto cdf_a = cdf(a,p); //Just to save time (I don't know if compilers does this already)

//Point where we are computing the inverse (s*(^F(b) - ^F(a)) + ^F(a))
auto x = s*(cdf(b,p) - cdf_a) + cdf_a;
auto x = norm(s*(cdf(b,p) - cdf_a) + cdf_a);
auto res = inv_cdf(x,p);

//There are some warnings in two strange scenarious, hope we don't have to see them printed
Expand Down

0 comments on commit 556ff04

Please sign in to comment.