// This file copyright (C) 2006 Andres Jordan <ajordan@eso.org>
// and Simon Casassus <simon@das.uchile.cl>
// All rights reserved. There is no warranty. You are allowed to
// redistribute this software/documentation under certain conditions.
// For details, see the file COPYING in the PDL distribution. If this file
// is separated from the PDL distribution, the copyright notice should be
// included in the file.
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>
#include "EXTERN.h"
#include "perl.h"
#include "pdl.h"
#include "pdlcore.h"
#define PDL PDL_GSL_MROOT
extern Core *PDL;
static SV* ext_funname1;
static PDL_Indx ene;
void set_funname(SV *fn, PDL_Indx n) {
ext_funname1 = fn;
ene = n;
}
void DFF(double* xval, double* vector){
//this version tries just to get the output
dSP;
ENTER;
SAVETMPS;
pdl* px = PDL->pdlnew();
if (!px) PDL->pdl_barf("Failed to create pdl");
SV* pxsv = sv_newmortal();
PDL->SetSV_PDL(pxsv, px);
int ndims = 1;
PDL_Indx pdims[] = { (PDL_Indx) ene };
PDL->barf_if_error(PDL->setdims(px,pdims,ndims));
px->datatype = PDL_D;
px->data = (void *) xval;
px->state |= PDL_ALLOCATED | PDL_DONTTOUCHDATA;
/* get function name on the perl side */
PUSHMARK(SP);
XPUSHs(pxsv);
PUTBACK;
int count=call_sv(ext_funname1,G_SCALAR);
SPAGAIN;
SP -= count ;
I32 ax = (SP - PL_stack_base) + 1 ;
if (count!=1)
croak("error calling perl function\n");
/* recover output value */
pdl* pvector = PDL->SvPDLV(ST(0));
PDL->barf_if_error(PDL->make_physical(pvector));
double *xpass = (double *) pvector->data;
PDL_Indx i;
for(i=0;i<ene;i++) {
vector[i] = xpass[i];
}
px->data = NULL;
PUTBACK;
FREETMPS;
LEAVE;
}
int my_f (const gsl_vector * v, void * params, gsl_vector * df)
{
double dp = *((double *)params);
int nelem = (int) dp;
double xfree[nelem], vector[nelem];
int iloop;
for (iloop=0;iloop< nelem;iloop++) {
xfree[iloop] = gsl_vector_get(v, iloop);
vector[iloop] = gsl_vector_get(v, iloop) * gsl_vector_get(v, iloop);
}
DFF(xfree, vector);
for (iloop=0;iloop< nelem;iloop++) {
gsl_vector_set(df, iloop, vector[iloop]);
}
return GSL_SUCCESS;
}
int
print_state (size_t iter, gsl_multiroot_fsolver * s)
{
printf ("iter = %3zu x = % .3f % .3f "
"f(x) = % .3e % .3e\n",
iter,
gsl_vector_get (s->x, 0),
gsl_vector_get (s->x, 1),
gsl_vector_get (s->f, 0),
gsl_vector_get (s->f, 1));
return 1;
}
int fsolver (double *xfree, int nelem, double epsabs, int method)
{
gsl_multiroot_fsolver_type *T;
gsl_multiroot_fsolver *s;
int status;
size_t i, iter = 0;
size_t n = nelem;
double p[1] = { nelem };
int iloop;
// struct func_params p = {1.0, 10.0};
gsl_multiroot_function func = {&my_f, n, p};
gsl_vector *x = gsl_vector_alloc (n);
for (iloop=0;iloop<nelem; iloop++) {
//printf("in fsovler2D, C side, input is %g \n",xfree[iloop]);
gsl_vector_set (x, iloop, xfree[iloop]);
}
switch (method){
case 0 : T = (gsl_multiroot_fsolver_type *) gsl_multiroot_fsolver_hybrids; break;
case 1 : T = (gsl_multiroot_fsolver_type *) gsl_multiroot_fsolver_hybrid; break;
case 2 : T = (gsl_multiroot_fsolver_type *) gsl_multiroot_fsolver_dnewton; break;
case 3 : T = (gsl_multiroot_fsolver_type *) gsl_multiroot_fsolver_broyden; break;
default: return GSL_EINVAL; break;
}
s = gsl_multiroot_fsolver_alloc (T, nelem);
gsl_multiroot_fsolver_set (s, &func, x);
do
{
iter++;
//printf("GSL iter %d \n",iter);
status = gsl_multiroot_fsolver_iterate (s);
if (status) /* check if solver is stuck */
break;
status = gsl_multiroot_test_residual (s->f, epsabs);
}
while (status == GSL_CONTINUE && iter < 1000);
if (status)
warn ("Final status = %s\n", gsl_strerror (status));
for (iloop=0;iloop<nelem; iloop++) {
xfree[iloop] = gsl_vector_get (s->x, iloop);
}
gsl_multiroot_fsolver_free (s);
gsl_vector_free (x);
return GSL_SUCCESS;
}