The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <gsl/gsl_math.h>
#include <gsl/gsl_monte.h>
#include <gsl/gsl_monte_miser.h>
#define NEED_sv_2pv_flags
#include "ppport.h"
struct params {
SV* eqn;
};
double integrand(double *x, size_t size, void *params) {
dSP;
SV* eqn;
int i, count, dim;
double val;
eqn = ((struct params *)params)->eqn;
ENTER;
SAVETMPS;
PUSHMARK(SP);
dim = (int)size;
for(i=0; i<dim; i++) {
XPUSHs(sv_2mortal(newSVnv(x[i])));
}
PUTBACK;
count = call_sv(eqn, G_SCALAR);
if (count != 1)
croak("Integrand closure did not return a value");
SPAGAIN;
val = POPn;
PUTBACK;
FREETMPS;
LEAVE;
return val;
}
AV* c_int_multi(SV* eqn, AV* lower, AV* upper, int calls) {
int i, dim;
double * xl;
double * xu;
double res, err;
size_t dim_size, calls_size;
const gsl_rng_type *T;
gsl_rng *r;
struct params myparams;
gsl_monte_function F;
AV* ret = newAV();
sv_2mortal((SV*)ret);
/* deal with lower and upper limits */
dim = av_len(lower) + 1;
if((av_len(upper)+1) != dim)
croak("dimension mismatch");
Newx(xl, dim, double);
if(xl == NULL)
croak ("Failed to allocate memory to 'xl' in 'c_int_multi'");
Newx(xu, dim, double);
if(xu == NULL)
croak ("Failed to allocate memory to 'xu' in 'c_int_multi'");
for (i=0; i<dim; i++) {
xl[i] = SvNV(*av_fetch(lower, i, 0));
xu[i] = SvNV(*av_fetch(upper, i, 0));
}
/* store the equation to pass to mock function */
myparams.eqn = eqn;
/* setup the random number generator */
gsl_rng_env_setup();
T = gsl_rng_default;
r = gsl_rng_alloc(T);
/* setup the integrator */
dim_size = (size_t)dim;
calls_size = (size_t)calls;
F.f = &integrand;
F.dim = dim_size;
F.params = &myparams;
gsl_monte_miser_state *s = gsl_monte_miser_alloc(dim_size);
gsl_monte_miser_integrate(&F, xl, xu, dim_size, calls_size, r, s, &res, &err);
av_push(ret, newSVnv(res));
av_push(ret, newSVnv(err));
/* cleanup */
gsl_monte_miser_free(s);
gsl_rng_free(r);
Safefree(xl);
Safefree(xu);
return ret;
}
MODULE = PerlGSL::Integration::MultiDim PACKAGE = PerlGSL::Integration::MultiDim
PROTOTYPES: DISABLE
AV *
c_int_multi (eqn, lower, upper, calls)
SV* eqn
AV* lower
AV* upper
int calls