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

NAME

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

DESCRIPTION

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

SYNOPSIS

16         use PDL;
17         sub mkmyndarray {
18          ...
19         }
20

Creating an ndarray manually from Perl

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

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

The gory details

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

SEE ALSO

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

BUGS

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