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

SEE ALSO

546       PDL
547
548       Inline
549

BUGS

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