1API(1)                User Contributed Perl Documentation               API(1)
2
3
4

NAME

6       PDL::API - making ndarrays from Perl and C/XS code
7

SYNOPSIS

9         use PDL;
10         sub mkmyndarray {
11          ...
12         }
13

DESCRIPTION

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

IMPLEMENTATION DETAILS

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

SEE ALSO

549       PDL
550
551       Inline
552

BUGS

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)
Impressum