File Coverage

pdlperlfunc.c
Criterion Covered Total %
statement 93 99 93.9
branch 16 30 53.3
condition n/a
subroutine n/a
pod n/a
total 109 129 84.5


line stmt bran cond sub pod time code
1             /* This file is to be included in Levmar.xs
2             *
3             * John Lapeyre
4             */
5              
6             #include "EXTERN.h"
7             #include "perl.h"
8             #include "XSUB.h"
9             #include "pdl.h"
10             #include "pdlcore.h"
11              
12             #if defined(PDL_CORE_VERSION) && PDL_CORE_VERSION < 10
13             typedef PDL_Long PDL_Indx;
14             #endif
15              
16             #include
17              
18             static Core* PDL; /* Structure holds core C functions */
19             static SV* CoreSV; /* Gets pointer to perl var holding core structure */
20              
21             // following line useless, i guess
22             // typedef void (*levmarfunc)( double *, double *, int, int, void * ) ;
23              
24             typedef void (*DelMagic)(pdl *, int param);
25             static void delete_levmar_pdls(pdl* p, int param);
26              
27 0           static void default_magic(pdl *p, int pa) { p->data = 0; }
28             static pdl* pdl_wrap(void *data, int datatype, PDL_Indx dims[],
29             int ndims, DelMagic delete_magic, int delparam);
30             static SV *getref_pdl(pdl *it);
31              
32             /* We use a struct holding data for the wrapper functions to
33             * perl fit code, LEVFUNC, and JLEVFUNC. liblevmar uses fit
34             * functions whose the last argument is a pointer to
35             * unpecified data. When fitting data it is normally used
36             * for the ordinate data (t). We pass a DFP struct instead.
37             * These functions are all re-entrant, i hope. The DFP
38             * struct holds pdls which are created once at the start of
39             * a fit and destroyed when it is finished. Data is not put
40             * in the pdls here. The fit routines send different arrays
41             * on different calls, so the pdl pointer to the data must
42             * be set in the wrapper functions at each call. t is an
43             * exception-- it is set by the user just once. levmar calls
44             * DFP_check() (below) which either sets t, or points the
45             * DFP *dat directly to t, if the wrapper functions are not
46             * used (ie for pure C fit functions).
47             */
48              
49             // Don't remember why i called it DFP
50             typedef struct {
51             SV * p_sv; // sv to pass directly to perl fit subs
52             SV * d_sv;
53             SV * x_sv;
54             SV * t_sv;
55             pdl * p_pdl; // the pdl pointer
56             pdl * d_pdl;
57             pdl * x_pdl;
58             pdl * t_pdl;
59             SV* perl_fit_func; // perl refs to user's fit and jac functions
60             SV* perl_jac_func;
61             int datatype;
62             } DFP;
63              
64             /* moved to xs
65             // called from sub levmar
66             DFP * _DFP_create () {
67             DFP * dat;
68             dat = (DFP *)malloc(sizeof( DFP ));
69             if ( NULL == dat ) {
70             fprintf(stderr, "Can't allocate storage for dat in DFP_create\n");
71             exit(1);
72             }
73             return dat;
74             }
75             */
76              
77             /*
78             // called from sub levmar
79             int _DFP_free (DFP *dat) {
80             if ( dat ) {
81             free(dat);
82             }
83             }
84             */
85              
86             /* moved into xs
87             void DFP_set_perl_funcs ( DFP *dat, SV* perl_fit_func, SV* perl_jac_func ) {
88             if ( dat == NULL ) {
89             fprintf(stderr, "DFP_set_perl_funcs got null struct\n");
90             exit(1);
91             }
92             dat->perl_fit_func = perl_fit_func;
93             dat->perl_jac_func = perl_jac_func;
94             }
95             */
96              
97 10           void DFP_create_pdls( DFP *dat, int data_type, int m, int n, int nt) {
98              
99             pdl *p_pdl, *x_pdl, *d_pdl, *t_pdl;
100             SV *p_sv, *x_sv, *d_sv, *t_sv;
101            
102 10           PDL_Indx mf_dims[] = {m};
103 10           int num_mf_dims = 1;
104              
105 10           PDL_Indx mjac_dims[] = {m,n}; // for jacobian 'd' variable
106 10           int num_mjac_dims = 2;
107              
108 10           PDL_Indx n_dims[] = {n};
109 10           int num_n_dims = 1;
110              
111 10           PDL_Indx nt_dims[] = {nt};
112 10           int num_nt_dims = 1;
113              
114              
115             // create pdls, but with no data;
116 10           p_pdl = pdl_wrap(NULL, data_type, mf_dims, num_mf_dims, delete_levmar_pdls, 0);
117 10           d_pdl = pdl_wrap(NULL, data_type, mjac_dims, num_mjac_dims, delete_levmar_pdls, 0);
118 10           x_pdl = pdl_wrap(NULL, data_type, n_dims, num_n_dims, delete_levmar_pdls, 0);
119 10           t_pdl = pdl_wrap(NULL, data_type, nt_dims, num_nt_dims, delete_levmar_pdls, 0);
120            
121 10           p_sv = getref_pdl(p_pdl);
122 10           d_sv = getref_pdl(d_pdl);
123 10           x_sv = getref_pdl(x_pdl);
124 10           t_sv = getref_pdl(t_pdl);
125              
126             // otherwise we get a memory leak
127 10           sv_2mortal(p_sv);
128 10           sv_2mortal(d_sv);
129 10           sv_2mortal(x_sv);
130 10           sv_2mortal(t_sv);
131              
132 10           dat->p_pdl = p_pdl;
133 10           dat->d_pdl = d_pdl;
134 10           dat->t_pdl = t_pdl;
135 10           dat->x_pdl = x_pdl;
136              
137 10           dat->p_sv = p_sv;
138 10           dat->d_sv = d_sv;
139 10           dat->t_sv = t_sv;
140 10           dat->x_sv = x_sv;
141            
142 10           }
143              
144             /* If dat is null then no DFP struct was created because we
145             * are using a C function and it will expect t as the last
146             * argument (and dat is passed as the last argument). If
147             * dat is non-null, it will hold a struct with all the pdls
148             * and we must put t in its proper place.
149             */
150 93           void DFP_check(DFP **dat, int data_type, int m, int n, int nt, void *t ) {
151 93 100         if ( *dat != NULL) {
152 10           DFP_create_pdls( *dat, data_type, m, n, nt);
153 10           (*dat)->t_pdl->data = t;
154             }
155             else { // Pure C routine that don't need this wrapper, expect t as last arg
156 83           *dat = (DFP *)t; // cast in case compiler complains.
157             }
158 93           }
159              
160              
161             // Code from PDL::API docs. For creating a pdl and giving it
162             // data storage allocated elswhere.
163 40           static pdl* pdl_wrap(void *data, int datatype, PDL_Indx dims[],
164             int ndims, DelMagic delete_magic, int delparam)
165             {
166 40           pdl* npdl = PDL->pdlnew(); /* get the empty container */
167 40           PDL->setdims(npdl,dims,ndims); /* set dims */
168 40           npdl->datatype = datatype; /* and data type */
169 40           npdl->data = data; /* point it to your data */
170             /* make sure the core doesn't meddle with your data */
171 40           npdl->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED;
172 40 50         if (delete_magic != NULL) {
173 40           PDL->add_deletedata_magic(npdl, delete_magic, delparam);
174             }
175             else
176 0           PDL->add_deletedata_magic(npdl, default_magic, 0);
177 40           return npdl;
178             }
179              
180             // Don't free data, it is allocated inside liblevmar
181 40           static void delete_levmar_pdls(pdl* p, int param)
182             {
183 40           if (p->data) {
184             // free(p->data);
185             }
186             else {
187             }
188 40           p->data = 0;
189 40           }
190              
191             /* Had to cut and paste from pdlcore.c
192             * Is this routine somehow otherwise available ?
193             * This returns SV *ref, giving access to the
194             * pdl *it as a perl scalar.
195             */
196 40           static SV *getref_pdl(pdl *it) {
197             SV *newref;
198 40 50         if(!it->sv) {
199             SV *ref;
200 40           HV *stash = gv_stashpv("PDL",TRUE);
201 40           SV *psv = newSViv(PTR2IV(it));
202 40           it->sv = psv;
203 40           newref = newRV_noinc(it->sv);
204 40           (void)sv_bless(newref,stash);
205             } else {
206 0           newref = newRV_inc(it->sv);
207 0           SvAMAGIC_on(newref);
208             }
209 40           return newref;
210             }
211              
212              
213             //-----------------------------------------------------
214             // Modified Function from pdl gsl interp code
215             // It follows the perlembed doc example closely
216              
217 77645           void LEVFUNC(double *p, double *x, int m, int n, DFP *dat) {
218             int count;
219 77645           dSP;
220              
221 77645           dat->p_pdl->data = p;
222 77645           dat->x_pdl->data = x;
223              
224 77645           ENTER;
225 77645           SAVETMPS;
226              
227 77645 50         PUSHMARK(SP);
228              
229             // Dont make mortal, they come from outside this routine
230 77645 50         XPUSHs(dat->p_sv);
231 77645 50         XPUSHs(dat->x_sv);
232 77645 50         XPUSHs(dat->t_sv);
233              
234 77645           PUTBACK;
235 77645           count=call_sv(dat->perl_fit_func,G_SCALAR);
236 77645           SPAGAIN;
237 77645 50         if (count!=1)
238 0           croak("error calling perl function\n");
239              
240 77645           PUTBACK;
241 77645 50         FREETMPS;
242 77645           LEAVE;
243              
244 77645           }
245              
246 15224           void JLEVFUNC(double *p, double *d, int m, int n, DFP *dat) {
247             int count;
248 15224           dat->p_pdl->data = p;
249 15224           dat->d_pdl->data = d;
250              
251 15224           dSP;
252 15224           ENTER;
253 15224           SAVETMPS;
254 15224 50         PUSHMARK(SP);
255 15224 50         XPUSHs(dat->p_sv);
256 15224 50         XPUSHs(dat->d_sv);
257 15224 50         XPUSHs(dat->t_sv);
258 15224           PUTBACK;
259 15224           count=call_sv(dat->perl_jac_func,G_SCALAR);
260 15224           SPAGAIN;
261 15224 50         if (count!=1)
262 0           croak("error calling perl function\n");
263 15224           PUTBACK;
264 15224 50         FREETMPS;
265 15224           LEAVE;
266 15224           }