Montecarlo integral optimization - c

I am using the montecarlo method as implemented in the gsl library. I need to compute many repetitions of this integral changing a parameter in the integrand. So I need to make my subroutine fast. It seems that the most time consuming part is the evaluation of the integrand at the random points. How could I make the evaluation faster in my specific case?
Here is a minimal example:
#include <gsl/gsl_rng.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_monte.h>
#include <gsl/gsl_monte_plain.h>
#include <gsl/gsl_monte_vegas.h>
double q=0.0;
double mu=0.001;
double eta=0.1;
double kF=1.0;
double Kcut=10;
long int Nmax=10000000;
int Nwu=1000000;
double w=1;
struct my_f_params { double y;};
double
g (double *k, size_t dim, void *p)
{
double A;
struct my_f_params * fp = (struct my_f_params *)p;
double PQ=q*q+k[1]*k[1]-2*q*k[1]*cos(k[3])+mu;
double QK=k[0]*k[0]+k[1]*k[1]-2*k[0]*k[1]* (cos(k[2])*cos(k[3])+cos(k[4])*sin(k[2])*sin(k[3]))+mu;
double KPQ=q*q+k[0]*k[0]+k[1]*k[1]+2*k[0]*cos(k[2])*(q-k[1]*cos(k[3]))+2*k[1]* (q*cos(k[3])+k[0]*cos(k[4])*sin(k[2])*sin(k[3]));
double denFreq=fp->y-0.5*(k[0]*k[0]+k[1]*k[1]+KPQ);
double vol=k[0]*k[0]*k[1]*k[1]*sin(k[2])*sin(k[3]);
if (sqrt(KPQ) < kF) {
A = vol*denFreq*(1/QK-1/PQ)/(QK*(pow(denFreq,2)+eta*eta));
}
else {
A = 0;
}
return A;
}
int
main (void)
{
double res, err;
double xl[5] = {0, kF, 0, 0, 0};
double xu[5] = {kF, Kcut, M_PI, M_PI, 2*M_PI};
const gsl_rng_type *T;
gsl_rng *r;
gsl_monte_function G;
size_t calls = Nmax;
gsl_rng_env_setup ();
struct my_f_params params;
T = gsl_rng_default;
r = gsl_rng_alloc (T);
params.y=w;
G.f=&g;
G.dim=5;
G.params=&params;
{
gsl_monte_vegas_state *s = gsl_monte_vegas_alloc (5);
gsl_monte_vegas_integrate (&G, xl, xu, 5, Nwu, r, s,&res, &err);
do
{
gsl_monte_vegas_integrate (&G, xl, xu, 5, calls/5, r, s,&res, &err);
}
while (fabs (gsl_monte_vegas_chisq (s) - 1.0) > 0.5);
gsl_monte_vegas_free (s);
}
printf ("%.6f %.6f %.6f\n", w,res,err);
gsl_rng_free (r);
return 0;
}

Expanding on Bob__'s comment, you can use sincos to compute the sin and cos of the same argument (k[2] and k[3]), and define a kF_sqr to be initialised in the main and use that in the g function to avoid the sqrt call. With these optimisations, a quick & dirty test on my machine showed a ~5% speed-up over your code.

Related

Efficient double integration in C with GSL

Consider the double integral
I = int int [(a^k)*b] da db
where we want to integrate for a between [0,1] and b between [0,1] and k is some constant. I am using the GSL numerical integration library but have a memory allocation issue.
My code is as follows
#include <stdlib.h>
#include <stdlib.h>
#include <math.h>
#include <gsl/gsl_integration.h>
double innerIntegrand(double a, void *params) {
double *cast_params = (double *) params;
double b = params[0];
double k = params[1];
return pow(a,k)*b;
}
I can then evaluate the inner integral for a given b (to get an outer integrand) as follows
double outerIntegrand(double b, void *params) {
// params = {holder for double b, k}
double *cast_params = (double *) params;
cast_params[0] = b;
// Allocate integration workspace
gsl_integration_workspace *giw = gsl_integration_workspace_alloc(100);
// Create GSL function
gsl_function F;
F.function = &innerIntegrand;
F.params = params;
// Initialise values to put the result in
double result;
double abserror;
// Perform integration
gsl_integration_qag(&F, 0, 1, 0.001, 0.001, 100, 1, giw, &result, &abserror);
// Free the integration workspace
gsl_integration_workspace_free(giw);
// Return result
return result
}
Note however I have to allocate and free the integration workspace within the function. This means it is done many times when evaluating the final integration function
double Integral(double k) {
// Create params
double *params = malloc(2*sizeof(double));
params[1] = k;
// Allocate integration workspace
gsl_integration_workspace *giw = gsl_integration_workspace_alloc(100);
// Create GSL function
gsl_function F;
F.function = &outerIntegrand;
F.params = params;
// Initialise values to put the result in
double result;
double abserror;
// Perform integration
gsl_integration_qag(&F, 0, 1, 0.001, 0.001, 100, 1, giw, &result, &abserror);
// Free the integration workspace
gsl_integration_workspace_free(giw);
// Free memory
free(params);
// Return result
return result
}
Ideally what I want is two global gsl_integration_workspace variables, one for the integral in outerIntegrand and another for the integral in Integral. However when I try to declare them as global values I receive a initializer element is not constant error.
Can anyone see a way to do this double integral without the repeated memory allocation and freeing? I was thinking we could also pass the workspace in through the params argument although it then starts to get quite messy.
I managed to build a decently looking program in C++ for double integration based on GSL, avoiding repeated allocations in a clean way. I used this well known function to play:
f(x,y)=exp(-x*x-y*y)
integrating it over all the plane (the result, pi, can easily be obtained by switching to polar coordinates).
It is trivial to modify it and add parameters by lambda capture.
#include <iostream>
#include <gsl/gsl_integration.h>
// Simple RAII wrapper
class IntegrationWorkspace {
gsl_integration_workspace * wsp;
public:
IntegrationWorkspace(const size_t n=1000):
wsp(gsl_integration_workspace_alloc(n)) {}
~IntegrationWorkspace() { gsl_integration_workspace_free(wsp); }
operator gsl_integration_workspace*() { return wsp; }
};
// Build gsl_function from lambda
template <typename F>
class gsl_function_pp: public gsl_function {
const F func;
static double invoke(double x, void *params) {
return static_cast<gsl_function_pp*>(params)->func(x);
}
public:
gsl_function_pp(const F& f) : func(f) {
function = &gsl_function_pp::invoke; //inherited from gsl_function
params = this; //inherited from gsl_function
}
operator gsl_function*(){return this;}
};
// Helper function for template construction
template <typename F>
gsl_function_pp<F> make_gsl_function(const F& func) {
return gsl_function_pp<F>(func);
}
int main() {
double epsabs = 1e-8;
double epsrel = 1e-8;
size_t limit = 100;
double result, abserr, inner_result, inner_abserr;
IntegrationWorkspace wsp1(limit);
IntegrationWorkspace wsp2(limit);
auto outer = make_gsl_function( [&](double x) {
auto inner = make_gsl_function( [&](double y) {return exp(-x*x-y*y);} );
gsl_integration_qagi(inner, epsabs, epsrel, limit, wsp1,
&inner_result, &inner_abserr);
return inner_result;
} );
gsl_integration_qagi(outer, epsabs, epsrel, limit, wsp2, &result, &abserr);
std::cout << result << std::endl;
}
This looks weird:
double innerIntegrand(double a, void *params) {
double *cast_params = (double *) params;
double b = params[0];
double k = params[1];
Is it correct to expect that (void *)param[0] and [1] correctly map to double b and k? How is proper offset to be calculated between void and double types?
Here some hints (do not expect working code below).
You may try something like:
double b = (double )*param;
double k = (double )*(param + sizeof(double));
But probably it would be better and safer to declare:
double Integral(double k) {
struct p {
double b;
double k;
} params;
params.k = k;
...
gsl_function F;
F.function = &outerIntegrand;
F.params = &params;
...
double outerIntegrand(double b, void *params) {
(struct p)params->b = b;
double innerIntegrand(double a, void *params) {
double b = (struct p)params->b;
double k = (struct p)params->k;
You may want to typdef the "struct p".

Avoid using global variables when using recursive functions in C

The code below uses a recursive function called interp, but I cannot find a way to avoid using global variables for iter and fxInterpolated. The full code listing (that performs N-dimensional linear interpolation) compiles straightforwardly with:
gcc NDimensionalInterpolation.c -o NDimensionalInterpolation -Wall -lm
The output for the example given is 2.05. The code works fine but I want to find alternatives for the global variables. Any help with this would be greatly appreciated. Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int linearInterpolation(double *, double **, double *, int);
double ** allocateDoubleMatrix(int, int);
double * allocateDoubleVector(int);
void interp(int, int, double *, double *, double *);
double mult(int, double, double *, double *);
/* The objectionable global
variables that I want to get rid of! */
int iter=0;
double fxInterpolated=0;
int main(int argc, char *argv[]){
double *fx, **a, *x;
int dims=2;
x=allocateDoubleVector(dims);
a=allocateDoubleMatrix(dims,2);
fx=allocateDoubleVector(dims*2);
x[0]=0.25;
x[1]=0.4;
a[0][0]=0;
a[0][1]=1;
a[1][0]=0;
a[1][1]=1;
fx[0]=1;
fx[1]=3;
fx[2]=2;
fx[3]=4;
linearInterpolation(fx, a, x, dims);
printf("%f\n",fxInterpolated);
return (EXIT_SUCCESS);
}
int linearInterpolation(double *fx, double **a, double *x, int dims){
double *b, *pos;
int i;
b=allocateDoubleVector(dims);
pos=allocateDoubleVector(dims);
for (i=0; i<dims;i++)
b[i] = (x[i] - a[i][0]) / (a[i][1] - a[i][0]);
interp(0,dims,pos,fx,b);
return (EXIT_SUCCESS);
}
void interp(int j, int dims, double *pos, double *fx, double *b) {
int i;
if (j == dims){
fxInterpolated+=mult(dims,fx[iter],pos,b);
iter++;
return;
}
for (i = 0; i < 2; i++){
pos[j]=(double)i;
interp(j+1,dims,pos,fx,b);
}
}
double mult(int dims, double fx, double *pos, double *b){
int i;
double val=1.0;
for (i = 0; i < dims; i++){
val *= fabs(1.0-pos[i]-b[i]);
}
val *= fx;
printf("mult val= %f fx=%f\n",val, fx);
return val;
}
double ** allocateDoubleMatrix(int i, int j){
int k;
double ** matrix;
matrix = (double **) calloc(i, sizeof(double *));
for (k=0; k< i; k++)matrix[k] = allocateDoubleVector(j);
return matrix;
}
double * allocateDoubleVector(int i){
double *vector;
vector = (double *) calloc(i,sizeof(double));
return vector;
}
Thanks for the comments so far. I want to avoid the use of static. I have removed the global variable and as suggested tried parsing with the iter variable. But no joy. In addition I am getting a compile warning: "value computed is not used" with reference to *iter++; What am I doing wrong?
void interp(int j, int dims, double *pos, double *fx, double *b, int *iter) {
int i;
if (j == dims){
fxInterpolated+=mult(dims,fx[*iter],pos,b);
*iter++;
return;
}
for (i = 0; i < 2; i++){
pos[j]=(double)i;
interp(j+1,dims,pos,fx,b,iter);
}
}
There are two approaches I would consider when looking at this problem:
Keep the state in a parameter
You could use one or more variables that you pass to the function (as a pointer, if necessary) to keep the state across function calls.
For instance,
int global = 0;
int recursive(int argument) {
// ... recursive stuff
return recursive(new_argument);
}
could become
int recursive(int argument, int *global) {
// ... recursive stuff
return recursive(new_argument, global);
}
or sometimes even
int recursive(int argument, int global) {
// ... recursive stuff
return recursive(new_argument, global);
}
Use static variables
You can also declare a variable in a function to be preserved across function calls by using the static keyword:
int recursive(int argument) {
static int global = 0;
// ... recursive stuff
return recursive(argument);
}
Note that because of the static keyword, global = 0 is only set when the program starts, not every time the function is called, as it would be without the keyword. This means that if you alter the value of global, it would keep this value the next time the function is called.
This method can be used if you only use your recursive function once during your program; if you need to use it multiple times, I recommend that you use the alternative method above.
A solution is to use statics and then to reset the variables on the first call, via a flag that I call initialise. That way you can choose to have the variables reset or not.
double interp(int j, int dims, double *pos, double *fx, double *b, int initialise) {
static double fxInterpolated = 0.0;
static int iter = 0;
int i;
if (initialise){
fxInterpolated = 0.0;
iter = 0;
}
.....
......
}

Numerical integration of a complex function with Cubature C package

I want to use the Cubature C package to perform a multidimensional integral of a complex function. I tried to do it in the following way for the very simple function f(x,y) = x + y*i over the square [0,1]x[0,1]. The exact result is 0.5 + 0.5i.
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "../cubature.h"
int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval);
int main(void)
{
double xmin[2] = {0,0}, xmax[2] = {1,1}, val, err;
hcubature(1, f, NULL, 2, xmin, xmax, 0, 0, 1e-3, ERROR_PAIRED, &val, &err);
printf("Computed integral = %f+%fi +/- %f\n", creal(val),cimag(val), err);
}
int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval)
{
fval[0] = x[0]+x[1]*I;
return 0;
}
But what I get is Computed integral = 0.500000+0.000000i +/- 0.000000, that is the imaginary part does not appear. If I put a pure imaginary integrand (e.g. x*i) I always get 0 as result.
What am I doing wrong? Do you know any better way to compute integrals of complex functions in C?
2 issues:
1) Your are declaring double val, but you want it to be double val[2]. Your original val being a double in cimag(val) will always return 0.0. Change to
double xmin[2] = {0,0}, xmax[2] = {1,1}, val[2] /* not val */, err;
hcubature(2 /* not 1 */, f, NULL, 2, xmin, xmax, 0, 0, 1e-3, ERROR_PAIRED, /* & */val, &err);
printf("Computed integral = %f+%fi +/- %f\n", val[0], val[1], err);
2) It does not appear you are calculating f(x,y) = x + y*i correctly in f(). fval[0] is a double and can not hold the complex answer you are trying to assign.
int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval) {
fval[0] = x[0];
fval[1] = x[1];
return 0;
}
Sorry I do not have "../cubature.h" to test right now.
When you define val, do this:
double *val=(double *) malloc(sizeof(double) * integrand_fdim);
where integrand_fdim is equal to unsigned fdim - first argument of your integrand f.
P.S.: the answer by #chux produces Bus 10 or segfault...

Computing the reciprocal condition number with lapack (i.e. rcond(x))

I wish to do exactly what rcond does in MATLAB/Octave using LAPACK from C.
The MATLAB manual tells me dgecon is used, and that is uses a 1-based norm.
I wrote a simple test program for an extremely simple case; [1,1; 1,0]
For this input matlab and octave gives me 0.25 using rcond and 1/cond(x,1), but in the case using LAPACK, this sample program prints 0.0. For other cases, such as identity, it prints the correct value.
Since MATLAB is supposely actually using this routine with success, what am I doing wrong?
I'm trying to decipher what Octave does, with little success as its wrapped in
#include <stdio.h>
extern void dgecon_(const char *norm, const int *n, const double *a,
const int *lda, const double *anorm, double *rcond, double *work,
int *iwork, int *info, int len_norm);
int main()
{
int i, info, n, lda;
double anorm, rcond;
double w[8] = { 0,0,0,0,0,0,0,0 };
int iw[2] = { 0,0 };
double x[4] = { 1, 1, 1, 0 };
anorm = 2.0; /* maximum column sum, computed manually */
n = 2;
lda = 2;
dgecon_("1", &n, x, &lda, &anorm, &rcond, w, iw, &info, 1);
if (info != 0) fprintf(stderr, "failure with error %d\n", info);
printf("%.5e\n", rcond);
return 0;
}
Compiled with cc testdgecon.c -o testdgecon -llapack; ./testdgecon
I found the answer to me own question.
The matrix is must be LU-decomposed before it is sent to dgecon. This seems very logical since one often wants to solve the system after checking the condition, in which case there is no need to decompose the matrix twice. The same idea goes for the norm which is computed separately.
The following code is all the necessary parts the compute the reciprocal condition number with LAPACK.
#include "stdio.h"
extern int dgecon_(const char *norm, const int *n, double *a, const int *lda, const double *anorm, double *rcond, double *work, int *iwork, int *info, int len);
extern int dgetrf_(const int *m, const int *n, double *a, const int *lda, int *lpiv, int *info);
extern double dlange_(const char *norm, const int *m, const int *n, const double *a, const int *lda, double *work, const int norm_len);
int main()
{
int i, info, n, lda;
double anorm, rcond;
int iw[2];
double w[8];
double x[4] = {7,3,-9,2 };
n = 2;
lda = 2;
/* Computes the norm of x */
anorm = dlange_("1", &n, &n, x, &lda, w, 1);
/* Modifies x in place with a LU decomposition */
dgetrf_(&n, &n, x, &lda, iw, &info);
if (info != 0) fprintf(stderr, "failure with error %d\n", info);
/* Computes the reciprocal norm */
dgecon_("1", &n, x, &lda, &anorm, &rcond, w, iw, &info, 1);
if (info != 0) fprintf(stderr, "failure with error %d\n", info);
printf("%.5e\n", rcond);
return 0;
}

C File Input/Trapezoid Rule Program

Little bit of a 2 parter. First of all im trying to do this in all c. First of all I'll go ahead and post my program
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
#include <string.h>
double f(double x);
void Trap(double a, double b, int n, double* integral_p);
int main(int argc, char* argv[]) {
double integral=0.0; //Integral Result
double a=6, b=10; //Left and Right Points
int n; //Number of Trapezoids (Higher=more accurate)
int degree;
if (argc != 3) {
printf("Error: Invalid Command Line arguements, format:./trapezoid N filename");
exit(0);
}
n = atoi(argv[2]);
FILE *fp = fopen( argv[1], "r" );
# pragma omp parallel
Trap(a, b, n, &integral);
printf("With n = %d trapezoids....\n", n);
printf("of the integral from %f to %f = %.15e\n",a, b, integral);
return 0;
}
double f(double x) {
double return_val;
return_val = pow(3.0*x,5)+pow(2.5*x,4)+pow(-1.5*x,3)+pow(0*x,2)+pow(1.7*x,1)+4;
return return_val;
}
void Trap(double a, double b, int n, double* integral_p) {
double h, x, my_integral;
double local_a, local_b;
int i, local_n;
int my_rank = omp_get_thread_num();
int thread_count = omp_get_num_threads();
h = (b-a)/n;
local_n = n/thread_count;
local_a = a + my_rank*local_n*h;
local_b = local_a + local_n*h;
my_integral = (f(local_a) + f(local_b))/2.0;
for (i = 1; i <= local_n-1; i++) {
x = local_a + i*h;
my_integral += f(x);
}
my_integral = my_integral*h;
# pragma omp critical
*integral_p += my_integral;
}
As you can see, it calculates trapezoidal rule given an interval.
First of all it DOES work, if you hardcode the values and the function. But I need to read from a file in the format of
5
3.0 2.5 -1.5 0.0 1.7 4.0
6 10
Which means:
It is of degree 5 (no more than 50 ever)
3.0x^5 +2.5x^4 −1.5x^3 +1.7x+4 is the polynomial (we skip ^2 since it's 0)
and the Interval is from 6 to 10
My main concern is the f(x) function which I have hardcoded. I have NO IDEA how to make it take up to 50 besides literally typing out 50 POWS and reading in the values to see what they could be.......Anyone else have any ideas perhaps?
Also what would be the best way to read in the file? fgetc? Im not really sure when it comes to reading in C input (especially since everything i read in is an INT, is there some way to convert them?)
For a large degree polynomial, would something like this work?
double f(double x, double coeff[], int nCoeff)
{
double return_val = 0.0;
int exponent = nCoeff-1;
int i;
for(i=0; i<nCoeff-1; ++i, --exponent)
{
return_val = pow(coeff[i]*x, exponent) + return_val;
}
/* add on the final constant, 4, in our example */
return return_val + coeff[nCoeff-1];
}
In your example, you would call it like:
sampleCall()
{
double coefficients[] = {3.0, 2.5, -1.5, 0, 1.7, 4};
/* This expresses 3x^5 + 2.5x^4 + (-1.5x)^3 + 0x^2 + 1.7x + 4 */
my_integral = f(x, coefficients, 6);
}
By passing an array of coefficients (the exponents are assumed), you don't have to deal with variadic arguments. The hardest part is constructing the array, and that is pretty simple.
It should go without saying, if you put the coefficients array and number-of-coefficients into global variables, then the signature of f(x) doesn't need to change:
double f(double x)
{
// access glbl_coeff and glbl_NumOfCoeffs, instead of parameters
}
For you f() function consider making it variadic (varargs is another name)
http://www.gnu.org/s/libc/manual/html_node/Variadic-Functions.html
This way you could pass the function 1 arg telling it how many "pows" you want, with each susequent argument being a double value. Is this what you are asking for with the f() function part of your question?

Resources