The cheesiest possible way is to ->copy the PDL before making your Inline::C call of course!
There is a PDL->make_physical you can call from C in the PDL core structure. That should take care of the segfaults, but it will give you unpredictable flow: affine (slice) flow will work fine since it is implemented with direct links into the other PDL’s ->data area, but other types (which require calling a function pointer in the trans structure) will not work right. I’ll go with everyone else here and say that you should be using Inline::Pdlpp unless you have a Really Good Reason not to. If you do have a Really Good Reason, have a look at the flag structure (there’s an appendix about it in Practical Magick) and search on the flags in the core C routines in the PDL tree — that will point you to the Right way to trigger explicit-copy dataflow. Good luck! > On Jun 19, 2020, at 12:22 AM, Derek Lamb <[email protected]> wrote: > > Question: Is there a straightforward way to operate on a piddle in C without > knowing whether it's a physical or a child piddle, just like we do in PDL? > And if so, what is it? > > As background: I have a subroutine, implemented in C, called from Perl using > Inline::C. It takes an arbitrary-sized array ref of 2D-piddles as input, and > modifies the piddles, like so: > > ### > my $aref = [$pdl1, $pdl2, $pdl3]; > my_sub( $aref ); > ### > > So far, so good. That is, until I accidentally threw a child (non-physical) > piddle at it: > > ### > my $aref = [$big_3D_pdl->dog]; > my_sub( $aref ); > ### > > Then, at best, my_sub completes successfully but does not change any of the > data in the piddles in $aref. Other times it segfaults. It has no trouble > changing the data in $aref in the first example, when the piddles are > physical. > > For simplicity, here is an example that doesn't use array refs, just takes a > single piddle as input. When called on a physical piddle $im0, it works > fine, but does not change the data in $im2 and frequently segfaults. This > script contains a subroutine "times_ten" that just multiplies each element of > the piddle by 10. > > ### > use strict; > use warnings; > use PDL::LiteF; > use PDL::Core::Dev; > use PDL::Dbg; > $PDL::debug=1; #for px calls > > my $im0 = sequence(5,4); > my $im1 = sequence(8,7); > my $im2 = $im1->slice("0:3,0:2"); > > $_->px foreach ($im0,$im2); > > times_ten($im0); > times_ten($im2); > > print "\nNow that I'm done, \$im0 is:\n$im0\n"; > print "\nNow that I'm done, \$im2 is:\n$im2\n"; > > no strict 'subs'; > use Inline with => 'PDL'; > use Inline C; > Inline->init; # useful if you want to be able to 'do'-load this script > 1; > > __DATA__ > > __C__ > > void times_ten(pdl* im){ > > printf("im xsize = %ld, ysize = %ld\n",im->dims[0],im->dims[1]); > PDL_Double *data = (PDL_Double *) im->data; > for (PDL_Indx x = 0; x < im->dims[0]; x++){ > for (PDL_Indx y = 0; y < im->dims[1]; y++){ > PDL_Indx offset = x * im->dimincs[0] + y * im->dimincs[1]; > data[offset] *= 10; > } > } > return; > } > ### > > What I would like is something near the beginning of the C code that > abstracts the input piddle so the subsequent code doesn't care whether the > input is physical or child. > > I made a similar example using Inline::Pdlpp and looked at the generated C > code, and there in the subroutine "pdl_times_ten_readdata", in the THREADLOOP > section is code that seems to take care of the pointer addressing whether the > input piddle is physical or a virtual/child piddle. I was hoping for > something less involved than a bunch of "__privtrans" lines—it's a bit hard > for the casual reader to understand what's going on. (That "casual reader" > may be me, in 6 or 12 months!) Is there a clean way to do this, or is it > best in this case to make sure that the input piddles are always physical? > > thanks much, > Derek > > _______________________________________________ > pdl-general mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/pdl-general > _______________________________________________ pdl-general mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/pdl-general
