Sep 18 2009

Monte-Carlo Integration using Thrust

Bored. Wrote a numerical integrator using Thrust for fun.

Solves, numerically, the integral from 0 to 1 for (x^2)*cos(x).

x*x*cos(x)

Analytically, we can solve and get: 2*cos(1) – sin(1) = 0.239133627

So, the code is as follows:

#include <vector_functions.h>
 
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
 
#include <thrust/generate.h>
#include <thrust/transform.h>
#include <thrust/count.h>
 
#include <cstdlib>
#include <math.h>
 
float2 bottomLeft;
float2 topRight;
 
__device__
float f(float x) {
	return (x*x*__cosf(x));
}
 
struct above_below_function {
	__device__ 
	float operator()(float2 p) const {
		return (p.y < f(p.x)) ? 1 : 0;
	}
};
 
float2 make_random_float2(){
	return make_float2( (rand() / (float)RAND_MAX) * (float)(topRight.x - bottomLeft.x) + (float)bottomLeft.x,
						(rand() / (float)RAND_MAX) * (float)(topRight.y - bottomLeft.y) + (float)bottomLeft.y);
}
 
int main() {
	srand(time(0));
 
	bottomLeft.x = 0;
	bottomLeft.y = 0;
 
	topRight.x = 1;
	topRight.y = 1;
 
	int numPoints = 10000000;
 
	// find the area of our bounding square
	float area = (topRight.x - bottomLeft.x) * (topRight.y - bottomLeft.y);
 
	// generate our points
	thrust::host_vector<float2> h_locations(numPoints);		
	thrust::generate(h_locations.begin(), h_locations.end(), make_random_float2);
 
	// create two device vectors -- one for our locations, and another to create a count
	thrust::device_vector<float2> d_locations = h_locations;
	thrust::device_vector<unsigned int> d_boolean(numPoints);
 
	// for each element, if the y is below f(x), then put a 1 in the array.  otherwise, put a 0
	thrust::transform(d_locations.begin(), d_locations.end(), d_boolean.begin(), above_below_function());
 
	int total = thrust::count(d_boolean.begin(), d_boolean.end(), 1);
 
	std::cout << "Area under curve: " << area * (total / (float)numPoints) << std::endl;
 
	return 0;
}

The solutions? Here are a few sample runs…
Area under curve: 0.239177
Area under curve: 0.238916
Area under curve: 0.239181
Area under curve: 0.239129

Pretty accurate, and pretty damn fast too.

  • Share/Bookmark