Efficient double integration in C with GSL - c

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".

Related

Python C Extension

I am having issues returning a 2D array from a C extension back to Python. When I allocate memory using malloc the returned data is rubbish. When I just initialise an array like sol_matrix[nt][nvar] the returned data is as expected.
#include <Python.h>
#include <numpy/arrayobject.h>
#include <math.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
// function to be solved by Euler solver
double func (double xt, double y){
double y_temp = pow(xt, 2);
y = y_temp;
return y;
}
static PyObject* C_Euler(double h, double xn)
{
double y_temp, dydx; //temps required for solver
double y_sav = 0; //temp required for solver
double xt = 0; //starting value for xt
int nvar = 2; //number of variables (including time)
int nt = xn/h; //timesteps
double y = 0; //y starting value
//double sol_matrix[nt][nvar]; //works fine
double **sol_matrix = malloc(nt * sizeof(double*)); //doesn't work
for (int i=0; i<nt; ++i){
sol_matrix[i] = malloc (nvar * sizeof(double));
}
int i=0;
//solution loop - Euler method.
while (i < nt){
sol_matrix[i][0]=xt;
sol_matrix[i][1]=y_sav;
dydx = func(xt, y);
y_temp = y_sav + h*dydx;
xt = xt+h;
y_sav=y_temp;
i=i+1;
}
npy_intp dims[2];
dims[0] = nt;
dims[1] = 2;
//Create Python object to copy solution array into, get pointer to
//beginning of array, memcpy the data from the C colution matrix
//to the Python object.
PyObject *newarray = PyArray_SimpleNew(2, dims, NPY_DOUBLE);
double *p = (double *) PyArray_DATA(newarray);
memcpy(p, sol_matrix, sizeof(double)*(nt*nvar));
// return array to Python
return newarray;
}
static PyObject* Euler(PyObject* self, PyObject* args)
{
double h, xn;
if (!PyArg_ParseTuple(args, "dd", &h, &xn)){
return NULL;
}
return Py_BuildValue("O", C_Euler(h,xn));
}
Could you provide any guidance on where I am going wrong?
Thank you.
The data in sol_matrix is not in contiguous memory, it's in nt separately allocated arrays. Therefore the line
memcpy(p, sol_matrix, sizeof(double)*(nt*nvar));
is not going to work.
I'm not a big fan of pointer-to-pointer arrays so believe your best option is to allocate sol_matrix as one big chunk:
double *sol_matrix = malloc(nt*nvar * sizeof(double));
This does mean you can't do 2D indexing so will need to do
// OLD: sol_matrix[i][0]=xt;
sol_matrix[i*nvar + 0] = xt;
In contrast
double sol_matrix[nt][nvar]; //works fine
is a single big chunk of memory so the copy works fine.

Montecarlo integral optimization

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.

Initializer element is not constant - C

I'm getting two errors :
Initializer element is not constant in the 2nd last line below in the code
Expected declaration specifiers '...' before string constant in the last line
#define K 10.0
typedef double (*TFunc)(double);
double alpha,x;
double f(double x)
{
return x*x;
}
double derive(TFunc f, const double x0)
{
const double dx = 1.0e-6; // or similar
double dy = f(x0+dx)-f(x0-dx);
return dy/(2.*dx);
}
double fp = derive(f, K);
printf("%lf\n",fp);
You should add any block of code you want to run first during the execution in to a main function. In your case, you should put the code:
double fp = derive(f, K);
printf("%lf\n",fp);
into a main function
int main() {
double fp = derive(f, K);
printf("%lf\n",fp);
}
Make sure you include the stdio.h library at the beginning of file since you are using printf function. Also, make sure you define constant K somewhere. I updated your code according to my suggestion above and it compiled without errors or warnings:
#include <stdio.h>
typedef double (*TFunc)(double);
double alpha,x;
double f(double x)
{
return x*x;
}
double derive(TFunc f, const double x0)
{
const double dx = 1.0e-6; // or similar
double dy = f(x0+dx)-f(x0-dx);
return dy/(2.*dx);
}
int main() {
const double K = 1.0;
double fp = derive(f, K);
printf("%lf\n",fp);
}

warning: assignment from incompatible pointer type [-Wincompatible-pointer-types] qt1.function = &H1

I doing integration of a complex function using gsl library in C programming language. In this code I had to declare two variables using pointer that I have done successfully. But I am facing a problem when I pass these variables in main function.
Please help me out.
My code is being written here:
struct har{
double t;
double k;
double x;
};
#include"str.h"
struct har H1( void * params, float q , int p )
{
struct har *p_params = (void *)params;
float mu=2;
double x =p_params ->x ;
double t = p_params -> t;
double k = p_params -> k;
//printf("%d",k);
struct har H1 = {x*cos(t*x)/(pow((mu*t*k),2)+pow(x,2))};
return H1;
}
double H (double x,void * params )
{
double e;
double t = *(double *) params;
//printf("%f\n",t);
//struct har t1,z;
//double t = z.params ->t1;
double H = (pow(e,-x)/x) ;//I(x,&t)*(sin(x*t));
return H;
}
#include<stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>
#include"H.h"
#include"H1.h"
int
main (void)
{
gsl_integration_workspace * w
= gsl_integration_workspace_alloc (10000);
struct har t,k;
double x, qtr, qbartr, qdottr, qddotr,q7r, qatr, qbtr, qt1r, error;
double expected = -4.0;
double a1 = 1e-14;
double a= 150;//150;
double pi = 3.141;
double b = 1.05263;
double mu = (2*pi)/b;
double q0=0;
double p0=6.5;
double om=7.07;
double tau=0.141;
double gamma = 0.180;
for(int m=2; m<4; m++)
{
float t = 4.14937*(m-1);
gsl_function qt;
qt.function = &H;
qt.params =&t;
gsl_integration_qags (&qt, a1, a, 0,1e-7, 10000, w, &qtr, &error);
// printf ("qtresult = % .18f\n\n", qtr);
for(int k=1; k<=2; k++)
{
{
struct har item = {x,t,k};
struct har *p_params = &item;
double gama=gamma/((mu*k*tau)+1);
// printf("gama = % .18f\n", gama);
gsl_function qt1;
qt1.function = &H1;
qt1.params = &p_params;
// qt1.params = &k;
gsl_integration_qags (&qt1, a1, a, 0,1e-7, 10000, w, &qt1r, &error);
printf("qt1result= % .18f\n", qt1r);
}
}
gsl_integration_workspace_free (w);
return 0;
}
In above code I had four file by namely code.c, str.h, H1.h and H.h. Where H1 and H contains two user defined functions and str is a file for structure and code.c is my main to compile.
Thanks for your time and observation.
Regards
Ramesh
The field qt1.function has type double (*)(double, void *). The function H1 which you attempt to assign to this field has type struct har (*)( void *, float, int).
These types are incompatible as the number of arguments, the types of the arguments, and the return type are all different. As it is right now, you have two parameters called p and q that are never being used. Also, the struct har you construct as a return value doesn't even set all the fields, just the first one, so why are you even returning a struct?
In order for H1 to work with gsl_function, is must accept a double and a void * and return a double. The x value corresponds to the double that is passed in, so you don't need that in your struct. Since you're also only building a single value to return, that's what you return.
struct har{
double t;
double k;
};
double H1( double x, void *params)
{
struct har *p_params = params; // no need to cast to/from void *
float mu=2;
double t = p_params->t;
double k = p_params->k;
return x*cos(t*x)/(pow((mu*t*k),2)+pow(x,2));
}
Also, you're not setting the values of qt1 properly:
qt1.params = &p_params;
Since p_params is a struct har *, its address is a struct har **. Your function however is expecting a struct har * to be passed in. So change this to the address of the struct, not the address of a pointer pointing to it:
qt1.params = &item;
You also have a mismatch when you set qt.params. You're giving it a float *, but your function H is expecting a double *. Just change the type of t to match:
double t = 4.14937*(m-1);

Returning an array of structs from a function - C programming

So I'm trying to write a function that will return an array of several values. At the moment, it is running correctly but only outputting the final calculated value. How would I make it so the output includes all calculated values?
My code looks like this:
//Practice to output an array of structs
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct boat_params {
double V, Uc, Vc;
};
struct boat_params submerged_volume(double L1, double L2, double Lavg, double H) {
struct boat_params volume;
double V_sub, Uc_sub, Vc_sub;
V_sub = 0;
//Boat description
double C, delta;
double theta, theta_rad, theta_min, theta_min2, theta_lim, theta_lim2, theta_lim_deg;
double Ug1, Ug2, Vg1, Vg2, V1, V2;
double pi;
pi = 4*atan(1);
C = sqrt(L1*L1 + L2*L2);
delta = acos(L1/C);
theta_lim = asin(H/L1);
theta_lim_deg = (theta_lim/pi) * 180.0;
theta_min = asin(H/C) - delta;
theta_min2 = 0;
//Calculating the submerged volume and centre of gravity for each different angle
for (theta = 0; theta <= 10; theta ++) {
//**Note: I've taken out the actual calculations of V_sub, Uc_sub, and Vc_sub for brevity**
volume.V = V_sub;
volume.Uc = Uc_sub;
volume.Vc = Vc_sub;
}
return volume;
}
int main () {
double L1, L2, Lavg, H;
struct boat_params volume;
L1 = 17.6;
L2 = 3;
Lavg = 4;
H = 4.5;
volume = submerged_volume(L1, L2, Lavg, H);
printf("V = %lf\nUc = %lf\nVc = %lf\n", volume.V, volume.Uc, volume.Vc);
return 0;
}
I can get it to correctly output the last calculated value (for theta = 10) but that's the only value I'm getting. How would I calculate V_sub, Uc_sub, and Vc_sub for each theta value? and output each value. I'm assuming this means turning the struct into an array and filling each element of the array with values of the struct for that theta but I don't know how to do this!
I really appreciate any help and thank you in advance.
Also: If possible I'd like to avoid pointers but understand this may not be possible! I'm still very new and not good at using them!
You are quite right, you will need to have an array for that. If the number of elements in the array is constant, you could also create a struct that contains exactly that number elements, but please don't do that.
To operate on arrays you will - unfortunately - need pointers. A very common way to do this in C is not to return a pointer, but pass a 'result' pointer in. This means that it will be up to the user of the function to allocate space and free it, he can also use the syntax for arrays. In your code it seems that the number of values is constant, this makes the aforementioned solution possible. Alternatively you could allocate space on the heap (using malloc) and return a pointer, but that means the user needs to free memory he never allocated, counter intuitive and might result in memory leaks if he forgets to do so. Consider the following solution:
void submerged_volume(double L1, double L2, double Lavg, double H, struct boat_params *result) {
// your calculations here
for (theta = 0; theta <= 10; theta ++) {
(result+theta)->V = V_sub;
(result+theta)->Uc = Uc_sub;
(result+theta)->Vc = Vc_sub;
}
}
// somewhere in your code where you want to use your function
struct boat_params values[11];
unsigned char i = 0;
submerged_values(/* parameters */, values);
for (; i <= 10; ++i) {
printf("V = %lf\nUc = %lf\nVc = %lf\n", values[i].V, values[i].Uc, values[i].Vc);
}
Try this, just add your logic to the loop and maths:
#include <stdio.h>
#include <stdlib.h>
#define ARRSIZE 100
typedef struct boat_params {
double V, Uc, Vc;
} Volume;
struct boat_params submerged_volume(double L1, double L2, double Lavg, double H, Volume *volumes[]) {
double theta;
int i = 0; /* only example, change as needed */
Volume *p;
for (theta = 0; theta <= 10; theta ++) {
p = malloc(sizeof(* p));
if (p == NULL) {
printf("malloc failed to allocate a new space");
exit(0);
}
p->V = 1; //V_sub;
p->Uc = 2; //Uc_sub;
p->Vc = 3; //Vc_sub;
volumes[i] = p;
i++;
}
}
int main () {
double L1, L2, Lavg, H;
L1 = 17.6;
L2 = 3;
Lavg = 4;
H = 4.5;
Volume *volumes[ARRSIZE];
submerged_volume(L1, L2, Lavg, H, volumes);
printf("V = %lf\nUc = %lf\nVc = %lf\n", volumes[0]->V, volumes[0]->Uc, volumes[0]->Vc); /* first element for example */
return 0;
}
If you don't know the size of the volumes array in advance, you should consider using linked list.

Resources