Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple MC Integrate Feature #163

Merged
merged 36 commits into from
Oct 3, 2021
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
18582ee
Simple MC integration 1st commit
surajchoubey Jun 6, 2021
386a253
.gitignore updated test/build
surajchoubey Jun 6, 2021
a96f4eb
added build to .gitignore
surajchoubey Jun 9, 2021
09c0109
Simple MC integration hpp draft
surajchoubey Jun 9, 2021
ee6e631
removed testing mess
surajchoubey Jun 9, 2021
671d414
minor VT reps fixes
surajchoubey Jun 9, 2021
6c4f676
minor eigen fixes2
surajchoubey Jun 10, 2021
cc3cf5f
cleaning + volType enum added
surajchoubey Jun 11, 2021
8e4a377
updated .gitignore for build
surajchoubey Jun 13, 2021
37d6104
tests ready for check
surajchoubey Jun 13, 2021
2949acb
Merge branch 'GeomScale:develop' into simple-MC-integrate
surajchoubey Jun 13, 2021
b49256f
all 6 tests passing
surajchoubey Jun 13, 2021
e7cea91
Merge branch 'simple-MC-integrate' of https://github.com/warmachine86…
surajchoubey Jun 13, 2021
1e6471e
removed user-def dir
surajchoubey Jun 19, 2021
1b0cd55
Cleaned up + fixed petty errors
surajchoubey Jun 20, 2021
364c9eb
implemented uni bill walks + removed hmc
surajchoubey Jun 23, 2021
11783b1
simple mc uniform walks completed
surajchoubey Jun 23, 2021
78c83d2
Vector<Point> to store points added
surajchoubey Jun 23, 2021
9d7a5d5
added feature for VPOLYTOPE
surajchoubey Jun 24, 2021
d6f0bc2
removed inbuilt sampling + added uniform walks
surajchoubey Jun 24, 2021
e3b892f
put walk_len + e to params
surajchoubey Jun 26, 2021
85963a5
Added CHECK() + test_values()
surajchoubey Jun 29, 2021
200f019
Added [-1,1]^n as default limits
surajchoubey Jun 29, 2021
3176dd2
added tests for simple_mc_integrate
surajchoubey Jun 30, 2021
91373bf
added Limits datatype
surajchoubey Jun 30, 2021
10cc6e8
minor fix in naming tests simple mc
surajchoubey Jun 30, 2021
977541f
minor fixes in dims
surajchoubey Jun 30, 2021
92503ff
fixed polytope dim match
surajchoubey Jul 1, 2021
8385366
fixed polytope dim-2
surajchoubey Jul 1, 2021
740279d
fixed indent
surajchoubey Jul 3, 2021
e26e424
added tests birkhoff, prod-simplex, simplex, cross
surajchoubey Jul 7, 2021
e4e6da4
testing wrt latte
surajchoubey Jul 8, 2021
17f5b2f
fixed walks
surajchoubey Jul 8, 2021
5b35e7d
lowered N for tests + VolumeWalkType added
surajchoubey Aug 1, 2021
bb0b394
fixed rectangle tests
surajchoubey Aug 1, 2021
808a5f8
Merge branch 'develop' into simple-MC-integrate
vissarion Sep 30, 2021
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

test/build
examples/build
.vscode
test/Testing/Temporary/CTestCostData.txt
*.log
.Rproj.user
Expand Down
194 changes: 194 additions & 0 deletions include/integration/simple_MC_integration.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// VolEsti (volume computation and sampling library)

// Copyright (c) 2012-2021 Vissarion Fisikopoulos
// Copyright (c) 2018-2021 Apostolos Chalkis

// Contributed and/or modified by Suraj Choubey, as part of Google Summer of Code 2021 program.

// Licensed under GNU LGPL.3, see LICENCE file

#ifndef SIMPLE_MC_INTEGRATION_HPP
#define SIMPLE_MC_INTEGRATION_HPP

#include <iostream>
#include <fstream>
#include <random>
#include <vector>
#include "convex_bodies/hpolytope.h"
#include "Eigen/Eigen"
#include "generators/known_polytope_generators.h"
#include "boost_random_number_generator.hpp"
#include "cartesian_geom/cartesian_kernel.h"
#include "random_walks/random_walks.hpp"
#include "volume/volume_sequence_of_balls.hpp"
#include "volume/volume_cooling_gaussians.hpp"
#include "volume/volume_cooling_balls.hpp"
#include "misc.h"

typedef double NT;
typedef Cartesian<NT> Kernel;
typedef typename Kernel::Point Point;
typedef std::vector<Point> Points;
typedef HPolytope<Point> HPOLYTOPE;
Copy link
Member

@vissarion vissarion Jul 26, 2021

Choose a reason for hiding this comment

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

this is not a special type so calling it Hpolytope instead of capitilize, is OK

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed HPOLYTOPE -> Hpolytope

typedef boost::mt19937 RNGType;
typedef BoostRandomNumberGenerator<RNGType, NT> RandomNumberGenerator;
typedef typename HPolytope<Point>::MT MT;
typedef typename HPolytope<Point>::VT VT;

typedef const unsigned int Uint; // positive constant value for no of samples & dimensions
enum volType { CB , CG , SOB }; // Volume type for polytope

// To check if two n-dimensional points ensure valid limits in integration
bool validLimits(Point LL, Point UL){
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this method throw an exception instead of giving an output to stdout?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is meant to check if UL[i] >= LL[i]

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thank you! What I meant was that these errors should be printed on stderr, which you do below.

if( UL.dimension() == LL.dimension() ) {
for ( int i = 0 ; i< LL.dimension() ; i++){
if( LL[i] > UL[i]){
std::cout << "Invalid integration limits\n";
return false;
}
}
return true;
}else{
std::cout << "Invalid integration limits\n";
return false;
}
}

// Hyper-Rectangle volume calculator in n-dimensions
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
NT hyperRectVolume(Point LL, Point UL){
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
NT product=1;
if(validLimits(LL,UL)){
for(int i=0; i<LL.dimension(); ++i){
product = product * ( UL[i] - LL[i] );
}
return product;
}
else return 0;
}

// To sample a point between two n-dimensional points using inbuilt random sampling
// Point samplerBWLimits(Point LL, Point UL){
// Point sample_point(LL.dimension());
// for(int i=0; i<LL.dimension(); ++i){
// sample_point.set_coord(i , LL[i] + (NT)(rand()) / ((NT)(RAND_MAX/(UL[i] - LL[i]))) );
// }
// return sample_point;
// }

// Simple MC Integration over Hyper-Rectangles
template
<
typename WalkType=BallWalk,
typename Functor
>
void simple_mc_integrate(Functor Fx, Uint N ,Point LL, Point UL, int walk_length=10, NT e=0.1){
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this function take a generic polytope as an argument?
You can create an extra function which is more user-friendly: ie it takes Point LL and Point UL and then calls this function.

Moreover, please check the spacing in the code which is not consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well not actually simple_mc_integrate() is designed to take integration limits as Points. (This is come up with thought to ease the user)

simple_mc_polytope_integrate() is designed to take generic polytope as argument.

Uint dim=LL.dimension();
NT sum = 0;
if(validLimits(LL,UL)){

// Creating an MT & VT for HPolytope(Hyper-Rectangle) for integration limits using LL & UL
MT mt(dim*2,dim);
VT vt(dim*2);
for(int i=0 ; i<dim ; i++){
mt(i,i)=1;
vt(i)=UL[i];
mt(dim+i,i)=-1;
vt(dim+i)=LL[i]*-1;
}

// Initialization of H-Polytope and setting up params for random walks
HPOLYTOPE P(dim,mt,vt);
// P.print();
std::pair<Point, NT> inner_ball = P.ComputeInnerBall();
RandomNumberGenerator rng(1);
Point x0 = inner_ball.first;
typename WalkType::template Walk<HPOLYTOPE, RandomNumberGenerator> walk(P,x0,rng);

for (int i = 0; i <=N; i++ ) {
walk.apply(P,x0,walk_length,rng);
sum = sum + Fx(x0);
}
NT volume = hyperRectVolume(LL,UL);
std::cout << "Volume of the subspace: " << volume << std::endl;
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
std::cout << "Integral Value: " << volume * sum / N << "\n";
}else{
std::cout << "Invalid integration limits\n";
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
}
}


// Simple MC Integration Over Polytopes
const Point origin(0);
template
<
typename WalkType=BallWalk,
typename Polytope=HPOLYTOPE,
typename RNG=RandomNumberGenerator,
typename Functor
>
void simple_mc_polytope_integrate(Functor Fx,Polytope &P, Uint N, volType vT=SOB, int walk_length=1, NT e=0.1 ,Point Origin=origin){

Uint dim = P.dimension();
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved

// Check if origin is shifted
if(Origin.dimension() == 0 ){
Origin.set_dimension(dim);
Origin.set_to_origin();
}

// Volume calculation for HPolytope
vissarion marked this conversation as resolved.
Show resolved Hide resolved
NT volume=0;

switch(vT){
case CB:
volume = volume_cooling_balls<BallWalk, RNG, Polytope>(P, e, walk_length).second;
break;
case CG:
volume = volume_cooling_gaussians<GaussianBallWalk, RNG, Polytope>(P, e, walk_length);
break;
case SOB:
volume = volume_sequence_of_balls<BallWalk, RNG, Polytope>(P, e, walk_length);
break;
default:
std::cout << "Error in volume type: CB / SOB / CG" << std::endl;
volume = 0;
break;
}

// Volume of the Polytope
std::cout << "Volume of the Polytope = " << volume << std::endl;

// For implementing Uniform Walks
RNG rng(1);
std::pair<Point, NT> inner_ball = P.ComputeInnerBall();
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
Point x0 = inner_ball.first;
typename WalkType::template Walk<Polytope,RNG> walk(P,x0,rng);

// For storing sampled points
Points points;
NT sum=0;

// Applying and walking through Uniform Walks + Storing Points in Vector<Point>
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
for (int i = 0; i < N; i++ ){
walk.apply(P,x0,walk_length,rng);
sum+=Fx(x0+Origin);

// points.push_back(x0+Origin);
// (x0+Origin).print();
}

// To print sampled points
// for(auto i_th_point : points){
// i_th_point.print();
// }

/*
Core idea of Monte Carlo Integration algorithm used here : https://en.wikipedia.org/wiki/Monte_Carlo_integration#Overview
*/

// Integration Value
std::cout << "Integral Value over Polytope = " << volume * sum / N << std::endl;

}

#endif
3 changes: 3 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ else ()
include_directories (BEFORE ../include/generators)
include_directories (BEFORE ../include/volume)
include_directories (BEFORE ../include)
include_directories (BEFORE ../include/integration)
include_directories (BEFORE ../include/convex_bodies)
include_directories (BEFORE ../include/convex_bodies/spectrahedra)
include_directories (BEFORE ../include/annealing)
Expand Down Expand Up @@ -258,6 +259,7 @@ else ()
add_test(NAME logconcave_sampling_test_uld
COMMAND logconcave_sampling_test -tc=uld)

add_executable (simple_mc_integration simple_mc_integration.cpp $<TARGET_OBJECTS:test_main>)

TARGET_LINK_LIBRARIES(new_volume_example ${LP_SOLVE})
TARGET_LINK_LIBRARIES(volume_sob_hpolytope ${LP_SOLVE})
Expand All @@ -272,6 +274,7 @@ else ()
TARGET_LINK_LIBRARIES(mcmc_diagnostics_test ${LP_SOLVE})
TARGET_LINK_LIBRARIES(benchmarks_sob ${LP_SOLVE})
TARGET_LINK_LIBRARIES(benchmarks_cg ${LP_SOLVE})
TARGET_LINK_LIBRARIES(simple_mc_integration ${LP_SOLVE})
TARGET_LINK_LIBRARIES(benchmarks_cb ${LP_SOLVE})
TARGET_LINK_LIBRARIES(ode_solvers_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3})
TARGET_LINK_LIBRARIES(boundary_oracles_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3})
Expand Down
81 changes: 81 additions & 0 deletions test/simple_mc_integration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "doctest.h"
#include "simple_MC_integration.hpp"
#include "Eigen/Eigen"
#include <vector>
#include "cartesian_geom/cartesian_kernel.h"
#include "hpolytope.h"
#include "known_polytope_generators.h"
#include "ode_solvers/oracle_functors.hpp"
#include "random_walks/random_walks.hpp"
#include <iostream>
#include <fstream>
#include "misc.h"

typedef double NT;
typedef Cartesian<NT> Kernel;
typedef typename Kernel::Point Point;
typedef std::vector<Point> Points;
typedef HPolytope<Point> HPOLYTOPE;
typedef VPolytope<Point> VPOLYTOPE;
typedef boost::mt19937 RNGType;
typedef BoostRandomNumberGenerator<RNGType, NT> RandomNumberGenerator;

NT exp_N_Dim(Point X){
return exp(-X.squared_length()) ;
}

void call_test_simple_mc_over_hyperrectangle(){
srand(time(0));
std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER HYPER-RECTANGLES USING UNIFORM WALKS\n";

std::vector<NT> ll{-1,-1};
std::vector<NT> ul{1,1};
Point LL(2,ll), UL(2,ul);
simple_mc_integrate(exp_N_Dim,10000,LL,UL);

std::vector<NT> ll1{0,0};
std::vector<NT> ul1{2,2};
Point LL1(2,ll1), UL1(2,ul1);
simple_mc_integrate(exp_N_Dim,10000,LL1,UL1);


surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
}

void call_test_simple_mc_over_polytope(){
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
std::cout << "\nTESTS FOR SIMPLE MC INTEGRATION OVER H-POLYTOPES USING UNIFORM SAMPLING\n";

// H-Polytope Integration Test:1 for 2D Polytope around the origin
HPOLYTOPE HP = generate_cube<HPOLYTOPE>(2, false);
simple_mc_polytope_integrate<BilliardWalk,HPOLYTOPE>(exp_N_Dim, HP, 10000, SOB, 10, 0.01);

// H-Polytope Integration Test:2 for 2D Polytope shifted to (1,1) from origin
std::vector<NT> origin{1,1};
Point newOrigin(2,origin);
simple_mc_polytope_integrate<BilliardWalk,HPOLYTOPE>(exp_N_Dim, HP, 10000, SOB, 1, 0.01, newOrigin);

// H-Polytope Integration Test:3
HPOLYTOPE HP1 = generate_cube<HPOLYTOPE>(4, false);
simple_mc_polytope_integrate<BilliardWalk,HPOLYTOPE>(exp_N_Dim, HP1, 10000, SOB);

// V-Polytope Integration Test:4
VPOLYTOPE VP = generate_cross<VPOLYTOPE>(2, true);
surajchoubey marked this conversation as resolved.
Show resolved Hide resolved
simple_mc_polytope_integrate<BilliardWalk,VPOLYTOPE>(exp_N_Dim, VP, 10000, CB);

// Polytope Integration Test:3 Reading a HPolytope from ine file for 20 Dimensions
// std::string fileName("cube10.ine");
// std::ifstream inp;
// std::vector<std::vector<NT> > Pin;
// inp.open(fileName, std::ifstream::in);
// read_pointset(inp,Pin);
// HPOLYTOPE HP2(Pin);
// SimpleMCPolytopeIntegrate(exp_N_dim, HP2, 15000, SOB);
// inp.close();
}

TEST_CASE("simple_mc_integration_over_hyperrectangles") {
call_test_simple_mc_over_hyperrectangle();
}

TEST_CASE("simple_mc_integration_over_polytopes") {
call_test_simple_mc_over_polytope();
}