1API(1) User Contributed Perl Documentation API(1)
2
3
4
6 PDL::API - making ndarrays from Perl and C/XS code
7
9 A simple cookbook how to create ndarrays manually. It covers both the
10 Perl and the C/XS level. Additionally, it describes the PDL core
11 routines that can be accessed from other modules. These routines
12 basically define the PDL API. If you need to access ndarrays from C/XS
13 you probably need to know about these functions.
14
16 use PDL;
17 sub mkmyndarray {
18 ...
19 }
20
22 Sometimes you want to create an ndarray manually from binary data. You
23 can do that at the Perl level. Examples in the distribution include
24 some of the IO routines. The code snippet below illustrates the
25 required steps.
26
27 use Carp;
28 sub mkmyndarray {
29 my $class = shift;
30 my $pdl = $class->new;
31 $pdl->set_datatype($PDL_B);
32 my @dims = (1,3,4);
33 my $size = 1;
34 for (@dims) { $size *= $_ }
35 $pdl->setdims([@dims]);
36 my $dref = $pdl->get_dataref();
37
38 # read data directly from file
39 open my $file, '<data.dat' or die "couldn't open data.dat";
40 my $len = $size*PDL::Core::howbig($pdl->get_datatype);
41 croak "couldn't read enough data" if
42 read( $file, $$dref, $len) != $len;
43 close $file;
44 $pdl->upd_data();
45
46 return $pdl;
47 }
48
50 The following example creates an ndarray at the C level. We use the
51 "Inline" module which is a good way to interface Perl and C, using the
52 "with" capability in Inline 0.68+.
53
54 Note that to create a "scalar" ndarray (with no dimensions at all, and
55 a single element), just pass a zero-length "dims" array, with "ndims"
56 as zero.
57
58 use PDL::LiteF;
59
60 $x = myfloatseq(); # exercise our C ndarray constructor
61
62 print $x->info,"\n";
63
64 use Inline with => 'PDL';
65 use Inline C;
66 Inline->init; # useful if you want to be able to 'do'-load this script
67
68 __DATA__
69
70 __C__
71
72 static pdl* new_pdl(int datatype, PDL_Indx dims[], int ndims)
73 {
74 pdl *p = PDL->pdlnew();
75 PDL->setdims (p, dims, ndims); /* set dims */
76 p->datatype = datatype; /* and data type */
77 PDL->allocdata (p); /* allocate the data chunk */
78
79 return p;
80 }
81
82 pdl* myfloatseq()
83 {
84 PDL_Indx dims[] = {5,5,5};
85 pdl *p = new_pdl(PDL_F,dims,3);
86 PDL_Float *dataf = (PDL_Float *) p->data;
87 PDL_Indx i; /* dimensions might be 64bits */
88
89 for (i=0;i<5*5*5;i++)
90 dataf[i] = i; /* the data must be initialized ! */
91 return p;
92 }
93
94 Wrapping your own data into an ndarray
95 Sometimes you obtain a chunk of data from another source, for example
96 an image processing library, etc. All you want to do in that case is
97 wrap your data into an ndarray struct at the C level. Examples using
98 this approach can be found in the IO modules (where FastRaw and FlexRaw
99 use it for mmapped access) and the Gimp Perl module (that uses it to
100 wrap Gimp pixel regions into ndarrays). The following script
101 demonstrates a simple example:
102
103 use PDL::LiteF;
104 use PDL::Core::Dev;
105 use PDL::Graphics::PGPLOT;
106
107 $y = mkndarray();
108
109 print $y->info,"\n";
110
111 imag1 $y;
112
113 use Inline with => 'PDL';
114 use Inline C;
115 Inline->init;
116
117 __DATA__
118
119 __C__
120
121 /* wrap a user supplied chunk of data into an ndarray
122 * You must specify the dimensions (dims,ndims) and
123 * the datatype (constants for the datatypes are declared
124 * in pdl.h; e.g. PDL_B for byte type, etc)
125 *
126 * when the created ndarray 'npdl' is destroyed on the
127 * Perl side the function passed as the 'delete_magic'
128 * parameter will be called with the pointer to the pdl structure
129 * and the 'delparam' argument.
130 * This gives you an opportunity to perform any clean up
131 * that is necessary. For example, you might have to
132 * explicitly call a function to free the resources
133 * associated with your data pointer.
134 * At the very least 'delete_magic' should zero the ndarray's data pointer:
135 *
136 * void delete_mydata(pdl* pdl, int param)
137 * {
138 * pdl->data = 0;
139 * }
140 * pdl *p = pdl_wrap(mydata, PDL_B, dims, ndims, delete_mydata,0);
141 *
142 * pdl_wrap returns the pointer to the pdl
143 * that was created.
144 */
145 typedef void (*DelMagic)(pdl *, int param);
146 static void default_magic(pdl *p, int pa) { p->data = 0; }
147 static pdl* pdl_wrap(void *data, int datatype, PDL_Indx dims[],
148 int ndims, DelMagic delete_magic, int delparam)
149 {
150 pdl* npdl = PDL->pdlnew(); /* get the empty container */
151
152 PDL->setdims(npdl,dims,ndims); /* set dims */
153 npdl->datatype = datatype; /* and data type */
154 npdl->data = data; /* point it to your data */
155 /* make sure the core doesn't meddle with your data */
156 npdl->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED;
157 if (delete_magic != NULL)
158 PDL->add_deletedata_magic(npdl, delete_magic, delparam);
159 else
160 PDL->add_deletedata_magic(npdl, default_magic, 0);
161 return npdl;
162 }
163
164 #define SZ 256
165 /* a really silly function that makes a ramp image
166 * in reality this could be an opaque function
167 * in some library that you are using
168 */
169 static PDL_Byte* mkramp(void)
170 {
171 PDL_Byte *data;
172 int i; /* should use PDL_Indx to support 64bit pdl indexing */
173
174 if ((data = malloc(SZ*SZ*sizeof(PDL_Byte))) == NULL)
175 croak("mkramp: Couldn't allocate memory");
176 for (i=0;i<SZ*SZ;i++)
177 data[i] = i % SZ;
178
179 return data;
180 }
181
182 /* this function takes care of the required clean-up */
183 static void delete_myramp(pdl* p, int param)
184 {
185 if (p->data)
186 free(p->data);
187 p->data = 0;
188 }
189
190 pdl* mkndarray()
191 {
192 PDL_Indx dims[] = {SZ,SZ};
193 pdl *p;
194
195 p = pdl_wrap((void *) mkramp(), PDL_B, dims, 2,
196 delete_myramp,0); /* the delparam is abitrarily set to 0 */
197 return p;
198 }
199
201 The Core struct -- getting at PDL core routines at runtime
202 PDL uses a technique similar to that employed by the Tk modules to let
203 other modules use its core routines. A pointer to all shared core PDL
204 routines is stored in the $PDL::SHARE variable. XS code should get
205 hold of this pointer at boot time so that the rest of the C/XS code can
206 then use that pointer for access at run time. This initial loading of
207 the pointer is most easily achieved using the functions
208 "PDL_AUTO_INCLUDE" and "PDL_BOOT" that are defined and exported by
209 "PDL::Core::Dev". Typical usage with the Inline module has already been
210 demonstrated:
211
212 use Inline with => 'PDL';
213
214 In earlier versions of "Inline", this was achieved like this:
215
216 use Inline C => Config =>
217 INC => &PDL_INCLUDE,
218 TYPEMAPS => &PDL_TYPEMAP,
219 AUTO_INCLUDE => &PDL_AUTO_INCLUDE, # declarations
220 BOOT => &PDL_BOOT; # code for the XS boot section
221
222 The code returned by "PDL_AUTO_INCLUDE" makes sure that pdlcore.h is
223 included and declares the static variables to hold the pointer to the
224 "Core" struct. It looks something like this:
225
226 print PDL_AUTO_INCLUDE;
227
228 #include <pdlcore.h>
229 static Core* PDL; /* Structure holds core C functions */
230 static SV* CoreSV; /* Gets pointer to Perl var holding core structure */
231
232 The code returned by "PDL_BOOT" retrieves the $PDL::SHARE variable and
233 initializes the pointer to the "Core" struct. For those who know their
234 way around the Perl API here is the code:
235
236 perl_require_pv ("PDL/Core.pm"); /* make sure PDL::Core is loaded */
237 #ifndef aTHX_
238 #define aTHX_
239 #endif
240 if (SvTRUE (ERRSV)) Perl_croak(aTHX_ "%s",SvPV_nolen (ERRSV));
241 CoreSV = perl_get_sv("PDL::SHARE",FALSE); /* SV* value */
242 if (CoreSV==NULL)
243 Perl_croak(aTHX_ "We require the PDL::Core module, which was not found");
244 PDL = INT2PTR(Core*,SvIV( CoreSV )); /* Core* value */
245 if (PDL->Version != PDL_CORE_VERSION)
246 Perl_croak(aTHX_ "[PDL->Version: \%d PDL_CORE_VERSION: \%d XS_VERSION: \%s] The code needs to be recompiled against the newly installed PDL", PDL->Version, PDL_CORE_VERSION, XS_VERSION);
247
248 The "Core" struct contains version info to ensure that the structure
249 defined in pdlcore.h really corresponds to the one obtained at runtime.
250 The code above tests for this
251
252 if (PDL->Version != PDL_CORE_VERSION)
253 ....
254
255 For more information on the Core struct see PDL::Internals.
256
257 With these preparations your code can now access the core routines as
258 already shown in some of the examples above, e.g.
259
260 pdl *p = PDL->pdlnew();
261
262 By default the C variable named "PDL" is used to hold the pointer to
263 the "Core" struct. If that is (for whichever reason) a problem you can
264 explicitly specify a name for the variable with the "PDL_AUTO_INCLUDE"
265 and the "PDL_BOOT" routines:
266
267 use Inline C => Config =>
268 INC => &PDL_INCLUDE,
269 TYPEMAPS => &PDL_TYPEMAP,
270 AUTO_INCLUDE => &PDL_AUTO_INCLUDE 'PDL_Corep',
271 BOOT => &PDL_BOOT 'PDL_Corep';
272
273 Make sure you use the same identifier with "PDL_AUTO_INCLUDE" and
274 "PDL_BOOT" and use that same identifier in your own code. E.g.,
275 continuing from the example above:
276
277 pdl *p = PDL_Corep->pdlnew();
278
279 Some selected core routines explained
280 The full definition of the "Core" struct can be found in the file
281 pdlcore.h. In the following the most frequently used member functions
282 of this struct are briefly explained.
283
284 • "pdl *SvPDLV(SV *sv)"
285
286 • "pdl *SetSV_PDL(SV *sv, pdl *it)"
287
288 • "pdl *pdlnew()"
289
290 "pdlnew" returns an empty pdl object that needs further
291 initialization to turn it into a proper ndarray. Example:
292
293 pdl *p = PDL->pdlnew();
294 PDL->setdims(p,dims,ndims);
295 p->datatype = PDL_B;
296
297 • "pdl *null()"
298
299 • "SV *copy(pdl* p, char* )"
300
301 • "void *smalloc(STRLEN nbytes)"
302
303 • "int howbig(int pdl_datatype)"
304
305 • "void add_deletedata_magic(pdl *p, void (*func)(pdl*, int), int
306 param)"
307
308 • "void allocdata(pdl *p)"
309
310 • "void make_physical(pdl *p)"
311
312 • "void make_physdims(pdl *p)"
313
314 • "void make_physvaffine(pdl *p)"
315
316 • "void qsort_X(PDL_Xtype *data, PDL_Indx a, PDL_Indx b)" and "void
317 qsort_ind_X(PDL_Xtype *data, PDL_Indx *ix, PDL_Indx a, PDL_Indx
318 b)"
319
320 where X is one of B,S,U,L,F,D and Xtype is one of Byte, Short,
321 Ushort, Long, Float or Double. PDL_Indx is the C integer type
322 corresponding to appropriate indexing size for the perl
323 configuration (ivsize and ivtype). It can be either 'long' or
324 'long long' depending on whether your perl is 32bit or 64bit
325 enabled.
326
327 • "void pdl_barf(const char* pat,...)" and "void pdl_warn(const
328 char* pat,...)"
329
330 These are C-code equivalents of "barf" and "warn". They include
331 special handling of error or warning messages during pthreading
332 (i.e. processor multi-threading) that defer the messages until
333 after pthreading is completed. When pthreading is complete, perl's
334 "barf" or "warn" is called with the deferred messages. This is
335 needed to keep from calling perl's "barf" or "warn" during
336 pthreading, which can cause segfaults.
337
338 Note that "barf" and "warn" have been redefined (using
339 c-preprocessor macros) in pdlcore.h to "PDL->barf" and
340 "PDL->warn". This is to keep any XS or PP code from calling perl's
341 "barf" or "warn" directly, which can cause segfaults during
342 pthreading.
343
344 See PDL::ParallelCPU for more information on pthreading.
345
347 PDL
348
349 Inline
350
351 Handy macros from pdl.h
352 Some of the C API functions return "PDL_Anyval" C type which is a
353 structure and therefore requires special handling.
354
355 You might want to use for example "get_pdl_badvalue" function:
356
357 /* THIS DOES NOT WORK! (although it did in older PDL) */
358 if( PDL->get_pdl_badvalue(a) == 0 ) { ... }
359
360 /* THIS IS CORRECT */
361 double bad_a;
362 ANYVAL_TO_CTYPE(bad_a, double, PDL->get_pdl_badvalue(a));
363 if( bad_a == 0 ) { ... }
364
365 As of PDL 2.014, in pdl.h there are the following macros for handling
366 PDL_Anyval from C code:
367
368 ANYVAL_FROM_CTYPE(out_anyval, out_anyval_type, in_variable)
369 ANYVAL_TO_CTYPE(out_variable, out_ctype, in_anyval)
370 ANYVAL_EQ_ANYVAL(x, y)
371
372 As of PDL 2.039 there is:
373
374 ANYVAL_ISNAN(anyval)
375
376 As of PDL 2.040 (the additional parameters are to detect the badflag,
377 and handle caching the bad value for efficiency):
378
379 ANYVAL_ISBAD(in_anyval, pdl, badval)
380
381 As of PDL 2.048, in pdlperl.h there are:
382
383 ANYVAL_FROM_SV(out_anyval, in_SV, use_undefval, forced_type)
384 ANYVAL_TO_SV(out_SV, in_anyval)
385
386 Because these are used in the PDL typemap.pdl, you will need to include
387 pdlperl.h in any XS file with functions that take or return a
388 "PDL_Anyval".
389
391 This manpage is still under development. Feedback and corrections are
392 welcome.
393
395 Copyright 2013 Chris Marshall (chm@cpan.org).
396
397 Copyright 2010 Christian Soeller (c.soeller@auckland.ac.nz). You can
398 distribute and/or modify this document under the same terms as the
399 current Perl license.
400
401 See: http://dev.perl.org/licenses/
402
403
404
405perl v5.34.0 2021-08-16 API(1)