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 static SV* CoreSV; /* Gets pointer to Perl var holding core structure */
235
236 The code returned by "PDL_BOOT" retrieves the $PDL::SHARE variable and
237 initializes the pointer to the "Core" struct. For those who know their
238 way around the Perl API here is the code:
239
240 perl_require_pv ("PDL/Core.pm"); /* make sure PDL::Core is loaded */
241 #ifndef aTHX_
242 #define aTHX_
243 #endif
244 if (SvTRUE (ERRSV)) Perl_croak(aTHX_ "%s",SvPV_nolen (ERRSV));
245 if (!(CoreSV = perl_get_sv("PDL::SHARE",FALSE))) /* SV* value */
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 safe_indterm
355
356 Checks given offset is within given ndarray's bounds, else throws
357 an exception.
358
359 •
360
361
362 converttype
363
364 Used by "set_datatype" to change an ndarray's type, converting and
365 possibly re-allocating the data if a different size. If the
366 ndarray's "badflag" was set, its "badvalue" will become the
367 default for the new type. Bad values will still be bad.
368
369 •
370
371
372 converttypei_new
373
374 Affine transformation used only by "get_convertedpdl" to convert
375 an ndarray's type. Not bad-value aware.
376
377 •
378
379
380 get_convertedpdl
381
382 Used by "convert" in PDL::Core.
383
384 •
385
386
387 affine_new
388
389 Creates a child vaffine ndarray from given parent ndarray, with
390 given offs (starting point for that pthread in that ndarray),
391 inclist and dims.
392
393 •
394
395
396 make_trans_mutual
397
398 Triggers the actual running of a previously-set-up "pdl_trans".
399
400 •
401
402
403 get
404
405 Get data at given coordinates.
406
407 •
408
409
410 get_offs
411
412 Get data at given offset.
413
414 •
415
416
417 put_offs
418
419 Put data at given offset.
420
421 •
422
423
424 setdims_careful
425
426 Despite the name, just calls "resize_defaultincs" then
427 "reallocbroadcastids" with one.
428
429 •
430
431
432 destroy
433
434 Destroy ndarray.
435
436 •
437
438
439 reallocdims
440
441 Cause the ndarray to have given number of dimensions, destroying
442 previous ones.
443
444 •
445
446
447 reallocbroadcastids
448
449 Reallocate n broadcastids. Set the new extra ones to the end.
450
451 •
452
453
454 resize_defaultincs
455
456 Recalculate default increments from "dims", and grow the PDL data.
457
458 Handy macros from pdl.h
459 Some of the C API functions return "PDL_Anyval" C type which is a
460 structure and therefore requires special handling.
461
462 You might want to use for example "get_pdl_badvalue" function:
463
464 /* THIS DOES NOT WORK! (although it did in older PDL) */
465 if( PDL->get_pdl_badvalue(a) == 0 ) { ... }
466
467 /* THIS IS CORRECT */
468 double bad_a;
469 PDL_Anyval bv = PDL->get_pdl_badvalue(a);
470 if (bv.type < 0) croak("error getting badvalue");
471 ANYVAL_TO_CTYPE(bad_a, double, bv);
472 if( bad_a == 0 ) { ... }
473
474 As of PDL 2.014, in pdl.h there are the following macros for handling
475 PDL_Anyval from C code:
476
477 ANYVAL_FROM_CTYPE(out_anyval, out_anyval_type, in_variable)
478 ANYVAL_TO_CTYPE(out_variable, out_ctype, in_anyval)
479 ANYVAL_EQ_ANYVAL(x, y) /* returns -1 on type error */
480
481 As of PDL 2.039 (returns -1 rather than croaking on failure as of
482 2.064) there is:
483
484 ANYVAL_ISNAN(anyval)
485
486 As of PDL 2.040 (changed parameter list, also returns -1 rather than
487 croaking on failure, in 2.064) - you need to check the badflag first:
488
489 ANYVAL_ISBAD(in_anyval, badval)
490
491 e.g.
492
493 int badflag = (x->state & PDL_BADVAL) > 0;
494 PDL_Anyval badval = pdl_get_pdl_badvalue(x);
495 if (badflag) {
496 int isbad = ANYVAL_ISBAD(result, badval);
497 if (isbad == -1) croak("ANYVAL_ISBAD error on types %d, %d", result.type, badval.type);
498 if (isbad)
499 RETVAL = newSVpvn( "BAD", 3 );
500 else
501 ANYVAL_TO_SV(RETVAL, result);
502 } else
503 ANYVAL_TO_SV(RETVAL, result);
504
505 As of PDL 2.058, there are:
506
507 ANYVAL_FROM_CTYPE_OFFSET(result, datatype, x, ioff);
508 ANYVAL_TO_CTYPE_OFFSET(x, ioff, datatype, value);
509
510 The latter dispatches on both the destination type and the input
511 "anyval" type. They are intended for retrieving values from, and
512 setting them within, ndarrays.
513
514 As of PDL 2.048, in pdlperl.h there are:
515
516 ANYVAL_FROM_SV(out_anyval, in_SV, use_undefval, forced_type)
517 ANYVAL_TO_SV(out_SV, in_anyval)
518
519 Because these are used in the PDL typemap.pdl, you will need to include
520 pdlperl.h in any XS file with functions that take or return a
521 "PDL_Anyval".
522
523 Access to PDL operations as C functions
524 As of 2.058, all PDL operations can be accessed from C code in a
525 similar way to XS functions, since that is what the XS functions now
526 call. Each module defines various C functions and data-structures for
527 each operation, as needed to operate as a PDL transformation. The entry
528 point from outside (and from XS functions) is a C function called
529 "pdl_(operationname)_run", with a signature derived from its "Pars" and
530 "OtherPars". E.g.
531
532 # from PDL::Primitive
533 pp_def('wtstat',
534 Pars => 'a(n); wt(n); avg(); [o]b();',
535 OtherPars => 'int deg',
536 # ...
537 );
538
539 has the C signature:
540
541 void pdl_wtstat_run(pdl *a, pdl *wt, pdl *avg, pdl *b, int deg);
542
543 Not very surprisingly, all "pdl*" parameters must be initialised (at
544 least to "PDL->null" status), and they are changed according to the
545 operation's specification. This makes the XS "_(name)_int" non-varargs
546 XS functions very thin layers over this.
547
549 PDL
550
551 Inline
552
554 This manpage is still under development. Feedback and corrections are
555 welcome.
556
558 Copyright 2013 Chris Marshall (chm@cpan.org).
559
560 Copyright 2010 Christian Soeller (c.soeller@auckland.ac.nz). You can
561 distribute and/or modify this document under the same terms as the
562 current Perl license.
563
564 See: http://dev.perl.org/licenses/
565
566
567
568perl v5.34.0 2022-02-28 API(1)