1API(1) User Contributed Perl Documentation API(1)
2
3
4
6 PDL::API - making ndarrays from Perl and C/XS code
7
9 use PDL;
10 sub mkmyndarray {
11 ...
12 }
13
15 A simple cookbook how to create ndarrays manually. It covers both the
16 Perl and the C/XS level. Additionally, it describes the PDL core
17 routines that can be accessed from other modules. These routines
18 basically define the PDL API. If you need to access ndarrays from C/XS
19 you probably need to know about these functions.
20
21 Also described is the new (as of PDL 2.058) access to PDL operations
22 via C functions, which the XS functions now call.
23
24 Creating an ndarray manually from Perl
25 Sometimes you want to create an ndarray manually from binary data. You
26 can do that at the Perl level. Examples in the distribution include
27 some of the IO routines. The code snippet below illustrates the
28 required steps.
29
30 use Carp;
31 sub mkmyndarray {
32 my $class = shift;
33 my $pdl = $class->new;
34 $pdl->set_datatype($PDL_B);
35 $pdl->setdims([1,3,4]);
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 = $pdl->nelems*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
49 Creating an ndarray in C
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 if (!p) return p;
76 pdl_error err = PDL->setdims(p, dims, ndims); /* set dims */
77 if (err.error) { PDL->destroy(p); return NULL; }
78 p->datatype = datatype; /* and data type */
79 err = PDL->allocdata (p); /* allocate the data chunk */
80 if (err.error) { PDL->destroy(p); return NULL; }
81 return p;
82 }
83
84 pdl* myfloatseq()
85 {
86 PDL_Indx dims[] = {5,5,5};
87 pdl *p = new_pdl(PDL_F,dims,3);
88 if (!p) return p;
89 PDL_Float *dataf = (PDL_Float *) p->data;
90 PDL_Indx i; /* dimensions might be 64bits */
91
92 for (i=0;i<5*5*5;i++)
93 dataf[i] = i; /* the data must be initialized ! */
94 return p;
95 }
96
97 Wrapping your own data into an ndarray
98 Sometimes you obtain a chunk of data from another source, for example
99 an image processing library, etc. All you want to do in that case is
100 wrap your data into an ndarray struct at the C level. Examples using
101 this approach can be found in the IO modules (where FastRaw and FlexRaw
102 use it for mmapped access) and the Gimp Perl module (that uses it to
103 wrap Gimp pixel regions into ndarrays). The following script
104 demonstrates a simple example:
105
106 use PDL::LiteF;
107 use PDL::Core::Dev;
108 use PDL::Graphics::PGPLOT;
109
110 $y = mkndarray();
111
112 print $y->info,"\n";
113
114 imag1 $y;
115
116 use Inline with => 'PDL';
117 use Inline C;
118 Inline->init;
119
120 __DATA__
121
122 __C__
123
124 /* wrap a user supplied chunk of data into an ndarray
125 * You must specify the dimensions (dims,ndims) and
126 * the datatype (constants for the datatypes are declared
127 * in pdl.h; e.g. PDL_B for byte type, etc)
128 *
129 * when the created ndarray 'p' is destroyed on the
130 * Perl side the function passed as the 'delete_magic'
131 * parameter will be called with the pointer to the pdl structure
132 * and the 'delparam' argument.
133 * This gives you an opportunity to perform any clean up
134 * that is necessary. For example, you might have to
135 * explicitly call a function to free the resources
136 * associated with your data pointer.
137 * At the very least 'delete_magic' should zero the ndarray's data pointer:
138 *
139 * void delete_mydata(pdl* pdl, int param)
140 * {
141 * pdl->data = 0;
142 * }
143 * pdl *p = pdl_wrap(mydata, PDL_B, dims, ndims, delete_mydata,0);
144 *
145 * pdl_wrap returns the pointer to the pdl
146 * that was created.
147 */
148 typedef void (*DelMagic)(pdl *, int param);
149 static void default_magic(pdl *p, int pa) { p->data = 0; }
150 static pdl* pdl_wrap(void *data, int datatype, PDL_Indx dims[],
151 int ndims, DelMagic delete_magic, int delparam)
152 {
153 pdl* p = PDL->pdlnew(); /* get the empty container */
154 if (!p) return p;
155 pdl_error err = PDL->setdims(p, dims, ndims); /* set dims */
156 if (err.error) { PDL->destroy(p); return NULL; }
157 p->datatype = datatype; /* and data type */
158 p->data = data; /* point it to your data */
159 /* make sure the core doesn't meddle with your data */
160 p->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED;
161 if (delete_magic != NULL)
162 PDL->add_deletedata_magic(p, delete_magic, delparam);
163 else
164 PDL->add_deletedata_magic(p, default_magic, 0);
165 return p;
166 }
167
168 #define SZ 256
169 /* a really silly function that makes a ramp image
170 * in reality this could be an opaque function
171 * in some library that you are using
172 */
173 static PDL_Byte* mkramp(void)
174 {
175 PDL_Byte *data;
176 int i; /* should use PDL_Indx to support 64bit pdl indexing */
177
178 if ((data = malloc(SZ*SZ*sizeof(PDL_Byte))) == NULL)
179 croak("mkramp: Couldn't allocate memory");
180 for (i=0;i<SZ*SZ;i++)
181 data[i] = i % SZ;
182
183 return data;
184 }
185
186 /* this function takes care of the required clean-up */
187 static void delete_myramp(pdl* p, int param)
188 {
189 if (p->data)
190 free(p->data);
191 p->data = 0;
192 }
193
194 pdl* mkndarray()
195 {
196 PDL_Indx dims[] = {SZ,SZ};
197 pdl *p;
198
199 p = pdl_wrap((void *) mkramp(), PDL_B, dims, 2,
200 delete_myramp,0); /* the delparam is abitrarily set to 0 */
201 return p;
202 }
203
205 The Core struct -- getting at PDL core routines at runtime
206 PDL uses a technique similar to that employed by the Tk modules to let
207 other modules use its core routines. A pointer to all shared core PDL
208 routines is stored in the $PDL::SHARE variable. XS code should get
209 hold of this pointer at boot time so that the rest of the C/XS code can
210 then use that pointer for access at run time. This initial loading of
211 the pointer is most easily achieved using the functions
212 "PDL_AUTO_INCLUDE" and "PDL_BOOT" that are defined and exported by
213 "PDL::Core::Dev". Typical usage with the Inline module has already been
214 demonstrated:
215
216 use Inline with => 'PDL';
217
218 In earlier versions of "Inline", this was achieved like this:
219
220 use Inline C => Config =>
221 INC => &PDL_INCLUDE,
222 TYPEMAPS => &PDL_TYPEMAP,
223 AUTO_INCLUDE => &PDL_AUTO_INCLUDE, # declarations
224 BOOT => &PDL_BOOT; # code for the XS boot section
225
226 The code returned by "PDL_AUTO_INCLUDE" makes sure that pdlcore.h is
227 included and declares the static variables to hold the pointer to the
228 "Core" struct. It looks something like this:
229
230 print PDL_AUTO_INCLUDE;
231
232 #include <pdlcore.h>
233 static Core* PDL; /* Structure holds core C functions */
234
235 The code returned by "PDL_BOOT" retrieves the $PDL::SHARE variable and
236 initializes the pointer to the "Core" struct. For those who know their
237 way around the Perl API here is the code:
238
239 perl_require_pv ("PDL/Core.pm"); /* make sure PDL::Core is loaded */
240 #ifndef aTHX_
241 #define aTHX_
242 #endif
243 if (SvTRUE (ERRSV)) Perl_croak(aTHX_ "%s",SvPV_nolen (ERRSV));
244 SV* CoreSV = perl_get_sv("PDL::SHARE",FALSE); /* var with core structure */
245 if (!CoreSV)
246 Perl_croak(aTHX_ "We require the PDL::Core module, which was not found");
247 if (!(PDL = INT2PTR(Core*,SvIV( CoreSV )))) /* Core* value */
248 Perl_croak(aTHX_ "Got NULL pointer for PDL");
249 if (PDL->Version != PDL_CORE_VERSION)
250 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);
251
252 The "Core" struct contains version info to ensure that the structure
253 defined in pdlcore.h really corresponds to the one obtained at runtime.
254 The code above tests for this
255
256 if (PDL->Version != PDL_CORE_VERSION)
257 ....
258
259 For more information on the Core struct see PDL::Internals.
260
261 With these preparations your code can now access the core routines as
262 already shown in some of the examples above, e.g.
263
264 pdl *p = PDL->pdlnew();
265
266 By default the C variable named "PDL" is used to hold the pointer to
267 the "Core" struct. If that is (for whichever reason) a problem you can
268 explicitly specify a name for the variable with the "PDL_AUTO_INCLUDE"
269 and the "PDL_BOOT" routines:
270
271 use Inline C => Config =>
272 INC => &PDL_INCLUDE,
273 TYPEMAPS => &PDL_TYPEMAP,
274 AUTO_INCLUDE => &PDL_AUTO_INCLUDE 'PDL_Corep',
275 BOOT => &PDL_BOOT 'PDL_Corep';
276
277 Make sure you use the same identifier with "PDL_AUTO_INCLUDE" and
278 "PDL_BOOT" and use that same identifier in your own code. E.g.,
279 continuing from the example above:
280
281 pdl *p = PDL_Corep->pdlnew();
282
283 Some selected core routines explained
284 The full definition of the "Core" struct can be found in the file
285 pdlcore.h. In the following the most frequently used member functions
286 of this struct are briefly explained.
287
288 • "pdl *SvPDLV(SV *sv)"
289
290 • "pdl *SetSV_PDL(SV *sv, pdl *it)"
291
292 • "pdl *pdlnew()"
293
294 "pdlnew" returns an empty pdl object that is initialised like a
295 "null" but with no data. Example:
296
297 pdl *p = PDL->pdlnew();
298 if (!p) return p;
299 pdl_error err = PDL->setdims(p, dims, ndims); /* set dims */
300 if (err.error) { PDL->destroy(p); return NULL; }
301 p->datatype = PDL_B;
302
303 Returns "NULL" if a problem occurred, so check for that.
304
305 • "pdl *null()"
306
307 Returns "NULL" if a problem occurred, so check for that.
308
309 • "SV *copy(pdl* p, char* )"
310
311 • "void *smalloc(STRLEN nbytes)"
312
313 • "int howbig(int pdl_datatype)"
314
315 • "pdl_error add_deletedata_magic(pdl *p, void (*func)(pdl*, int),
316 int param)"
317
318 • "pdl_error allocdata(pdl *p)"
319
320 • "pdl_error make_physical(pdl *p)"
321
322 • "pdl_error make_physdims(pdl *p)"
323
324 • "pdl_error make_physvaffine(pdl *p)"
325
326 • "void pdl_barf(const char* pat,...)" and "void pdl_warn(const
327 char* pat,...)"
328
329 These are C-code equivalents of "barf" and "warn". They include
330 special handling of error or warning messages during pthreading
331 (i.e. processor multi-threading) that defer the messages until
332 after pthreading is completed. When pthreading is complete, perl's
333 "barf" or "warn" is called with the deferred messages. This is
334 needed to keep from calling perl's "barf" or "warn" during
335 pthreading, which can cause segfaults.
336
337 Note that "barf" and "warn" have been redefined (using
338 c-preprocessor macros) in pdlcore.h to "PDL->barf" and
339 "PDL->warn". This is to keep any XS or PP code from calling perl's
340 "barf" or "warn" directly, which can cause segfaults during
341 pthreading.
342
343 See PDL::ParallelCPU for more information on pthreading.
344
345 NB As of 2.064, it is highly recommended that you do not call
346 "barf" at all in PP code, but instead use $CROAK(). This will
347 return a "pdl_error" which will transparently be used to throw the
348 correct exception in Perl code, but can be handled suitably by
349 non-Perl callers.
350
351 •
352
353
354 converttype
355
356 Used by "set_datatype" to change an ndarray's type, converting and
357 possibly re-allocating the data if a different size. If the
358 ndarray's "badflag" was set, its "badvalue" will become the
359 default for the new type. Bad values will still be bad.
360
361 •
362
363
364 converttypei_new
365
366 Affine transformation used only by "get_convertedpdl" to convert
367 an ndarray's type. Not bad-value aware.
368
369 •
370
371
372 get_convertedpdl
373
374 Used by "convert" in PDL::Core.
375
376 •
377
378
379 affine_new
380
381 Creates a child vaffine ndarray from given parent ndarray, with
382 given offs (starting point for that pthread in that ndarray),
383 inclist and dims.
384
385 •
386
387
388 make_trans_mutual
389
390 Triggers the actual running of a previously-set-up "pdl_trans".
391
392 •
393
394
395 get
396
397 Get data at given coordinates.
398
399 •
400
401
402 get_offs
403
404 Get data at given offset.
405
406 •
407
408
409 put_offs
410
411 Put data at given offset.
412
413 •
414
415
416 setdims_careful
417
418 Despite the name, just calls "resize_defaultincs" then
419 "reallocbroadcastids" with one.
420
421 •
422
423
424 destroy
425
426 Destroy ndarray.
427
428 •
429
430
431 reallocdims
432
433 Cause the ndarray to have given number of dimensions, destroying
434 previous ones.
435
436 •
437
438
439 reallocbroadcastids
440
441 Reallocate n broadcastids. Set the new extra ones to the end.
442
443 •
444
445
446 resize_defaultincs
447
448 Recalculate default increments from "dims", and grow the PDL data.
449
450 Handy macros from pdl.h
451 Some of the C API functions return "PDL_Anyval" C type which is a
452 structure and therefore requires special handling.
453
454 You might want to use for example "get_pdl_badvalue" function:
455
456 /* THIS DOES NOT WORK! (although it did in older PDL) */
457 if( PDL->get_pdl_badvalue(a) == 0 ) { ... }
458
459 /* THIS IS CORRECT */
460 double bad_a;
461 PDL_Anyval bv = PDL->get_pdl_badvalue(a);
462 if (bv.type < 0) croak("error getting badvalue");
463 ANYVAL_TO_CTYPE(bad_a, double, bv);
464 if( bad_a == 0 ) { ... }
465
466 As of PDL 2.014, in pdl.h there are the following macros for handling
467 PDL_Anyval from C code:
468
469 ANYVAL_FROM_CTYPE(out_anyval, out_anyval_type, in_variable)
470 ANYVAL_TO_CTYPE(out_variable, out_ctype, in_anyval)
471 ANYVAL_EQ_ANYVAL(x, y) /* returns -1 on type error */
472
473 As of PDL 2.039 (returns -1 rather than croaking on failure as of
474 2.064) there is:
475
476 ANYVAL_ISNAN(anyval)
477
478 As of PDL 2.040 (changed parameter list, also returns -1 rather than
479 croaking on failure, in 2.064) - you need to check the badflag first:
480
481 ANYVAL_ISBAD(in_anyval, badval)
482
483 e.g.
484
485 int badflag = (x->state & PDL_BADVAL) > 0;
486 PDL_Anyval badval = pdl_get_pdl_badvalue(x);
487 if (badflag) {
488 int isbad = ANYVAL_ISBAD(result, badval);
489 if (isbad == -1) croak("ANYVAL_ISBAD error on types %d, %d", result.type, badval.type);
490 if (isbad)
491 RETVAL = newSVpvn( "BAD", 3 );
492 else
493 ANYVAL_TO_SV(RETVAL, result);
494 } else
495 ANYVAL_TO_SV(RETVAL, result);
496
497 As of PDL 2.058, there are:
498
499 ANYVAL_FROM_CTYPE_OFFSET(result, datatype, x, ioff);
500 ANYVAL_TO_CTYPE_OFFSET(x, ioff, datatype, value);
501
502 The latter dispatches on both the destination type and the input
503 "anyval" type. They are intended for retrieving values from, and
504 setting them within, ndarrays.
505
506 As of PDL 2.048, in pdlperl.h there are:
507
508 ANYVAL_FROM_SV(out_anyval, in_SV, use_undefval, forced_type)
509 ANYVAL_TO_SV(out_SV, in_anyval)
510
511 Because these are used in the PDL typemap, you will need to include
512 pdlperl.h in any XS file with functions that take or return a
513 "PDL_Anyval".
514
515 As of 2.083, "ANYVAL_TO_SV" assigns a value into the passed "SV*" using
516 the Perl API, rather than assigning the given C value to having a
517 newly-created "SV*", so the caller is responsible for memory-
518 management.
519
520 Access to PDL operations as C functions
521 As of 2.058, all PDL operations can be accessed from C code in a
522 similar way to XS functions, since that is what the XS functions now
523 call. Each module defines various C functions and data-structures for
524 each operation, as needed to operate as a PDL transformation. The entry
525 point from outside (and from XS functions) is a C function called
526 "pdl_(operationname)_run", with a signature derived from its "Pars" and
527 "OtherPars". E.g.
528
529 # from PDL::Primitive
530 pp_def('wtstat',
531 Pars => 'a(n); wt(n); avg(); [o]b();',
532 OtherPars => 'int deg',
533 # ...
534 );
535
536 has the C signature:
537
538 void pdl_wtstat_run(pdl *a, pdl *wt, pdl *avg, pdl *b, int deg);
539
540 Not very surprisingly, all "pdl*" parameters must be initialised (at
541 least to "PDL->null" status), and they are changed according to the
542 operation's specification. This makes the XS "_(name)_int" non-varargs
543 XS functions very thin layers over this.
544
546 PDL
547
548 Inline
549
551 This manpage is still under development. Feedback and corrections are
552 welcome.
553
555 Copyright 2013 Chris Marshall (chm@cpan.org).
556
557 Copyright 2010 Christian Soeller (c.soeller@auckland.ac.nz). You can
558 distribute and/or modify this document under the same terms as the
559 current Perl license.
560
561 See: http://dev.perl.org/licenses/
562
563
564
565perl v5.38.0 2023-07-21 API(1)