Douglas Burke > Inline-SLang > Inline::SLang::Array

Download:
Inline-SLang-1.00.tar.gz

Annotate this POD

CPAN RT

Open  0
View/Report Bugs
Source  

NAME ^

Inline::SLang::Array - Support for arrays

SYNOPSIS ^

  use Inline 'SLang';

  # you can send arrays to S-Lang
  print_in_slang( [ 1, 2, 4 ] );

  # and get them back from S-Lang
  $aref = get_from_slang();
  print "The array contains: " . join(',', @$aref) . "\n";

  __END__
  __SLang__

  define print_in_slang (arr) {
    variable adims, ndim, atype;
    ( adims, ndim, atype ) = array_info(arr);
    vmessage( "Array has type=%S with %d dims", atype, ndim );
    foreach ( arr ) {
      variable val = ();
      vmessage( "  Value = %s", string(val) );
    }
  }
  define get_from_slang() { return ["a string","another one","3"]; }

The output of this code - which can be found in the source-code distribution as examples/arrays.pl - is:

  Array has type=Integer_Type with 1 dims
    Value = 1
    Value = 2
    Value = 4
  The array contains: a string,another one,3

DESCRIPTION ^

The philosophy behind arrays in Perl and S-Lang is somewhat different, which makes converting arrays between the two languages a bit more awkward than with many of the other data types.

We admit three different array representations in Perl: Perl's array references; as an Array_Type object (this class is a part of the Inline::SLang package); and as a piddle - the fundamental object of the Perl Data Language - which is the suggested method to analyze large numeric arrays in Perl. Before discussing this I want to talk about going the "other way".

Things to remember when converting arrays to S-Lang

Consider the following Perl array reference:

  [ [ 2, 1 ], [ 4, 5 ], [ 8, 9 ] ]

This could be represented in S-Lang as one of the following arrays:

  Integer_Type [3,2]
  Double_Type  [3,2]
  String_Type  [3,2]
  Array_Type   [3]
  Any_Type     [3]

Note that this does not match the way that PDL represents array (which considers this to be a 2x3 array). Please see the "Issues with the PDL support" section below.

Admittedly most of these are unlikely, but the point is that they are all valid representations, which makes automatically converting such an item to S-Lang awkward.

As discussed below it is possible to provide extra information (the type and/or dimensionality of the array) to help the conversion - using an Array_Type object or the Inline::SLang::SL_array() function - but hopefully the guesses the code makes will be sufficient.

How do we guess the array?

If the array is stored as a piddle or an Array_Type object then the computer can find out the information without guessing, so the following is only relevant when an array reference is used.

When given an array reference, the code looks at the first element to decide what type of array it is: if it is an array reference then we have a multi-dimensional array and the process is repeated until we reach a value. So, in the example above the "2" would be used to determine the type of the array - so it should come out as Integer_Type - and the array dimensions are taken to be [3,2].

How to confuse the array conversion (by data type)

Since the code only looks at the first element in the array to guess the type it is not too hard to come across arrays that will cause the code to croak with some bizarre message from S-Lang. For instance:

  [ 1, 2, "a string" ]

will cause a problem since it is assumed to be an Integer_Type [3] array, which is fine for the first two elements but not for the last one.

The code could be updated so that it checks all elements in the array and finds the most suitable type and dimensionality; however, this could be a large performance hit for large arrays and the current advice is to use one of the techniques we describe below.

How to confuse the array conversion (by array size)

The code assumes that the array dimensions it calculates hold for all elements. If they don't then you will see error messages (quite possibly strange ones at that). As an example,

  [ [ 2, 1 ], [1] ]

is guaranteed not to be liked by the code; on my machine it dislikes it so much that it causes a segmentation fault. Even if we were to loop through every element, checking the dimensionality of the array, it is not clear how this array should be represented in S-Lang.

How can I help?

If you know the array size and/or type then you can use the Inline::SLang::sl_array() function to help the code out. As an example (see also examples/array_help.pl):

  use Inline 'SLang' => Config => EXPORT =>
       [ 'sl_array', 'Integer_Type' ];
  use Inline 'SLang';

  my $aref = [ 1, 3, 2 ];
  foo( $aref );
  foo( sl_array( $aref, "Int_Type" ) );
  foo( sl_array( $aref, [3] ) );
  foo( sl_array( $aref, [3], Integer_Type() ) );

  __END__
  __SLang__

  define foo(x) { vmessage("Array has type: %S", _typeof(x) ); }

which produces four lines saying

  Array has type: Integer_Type

Note that I snuck in an example of using an automatically-generated wrapper around the DataType_Type constructor - the Integer_Type() function in the last call to foo().

Unfortunately you can not use sl_array() to typecast the array: at least not at the moment. If you replace Int_Type with String_Type in the above then you will come across the following error message

  S-Lang Error: Type Mismatch: Unable to typecast Integer_Type to String_Type

even though Perl can happily treat 1 as an integer or a string. Suggestions on how to handle this case are welcome.

The sl_array() function is actually a wrapper around the constructor call for the Array_Type class which tries to guess the array type and size if they have not been supplied.

Things to remember when converting arrays to Perl

There are three different ways that a S-Lang array can be represented in Perl:

  1. As a reference to a Perl array.
  2. As a piddle (see the Perl Data Language documentation) for numeric types.

    Please see the "Issues with the PDL support" section below.

  3. As an Array_Type object.

In most cases the first two representations are likely to be the ones you use; the use of an Array_Type object is only needed when it is hard for the code to guess the type/dimensionality of an array.

The Inline::SLang::sl_array2perl() function is used to define how S-Lang arrays are converted to Perl, and to find out what the current conversion system is. This function is described in Inline::SLang.

Example

  use Inline 'SLang' => Config => EXPORT => [ 'sl_array2perl' ];
  use Inline 'SLang';

  # use array references for all S-Lang arrays
  sl_array2perl(0);
  my $a0 = get_array();
  print "Array returned as an " . ref($a0) . "\n";
  print "  dim size = " . (1+$#$a0) . "\n";

  # use Array_Type for all S-Lang arrays
  sl_array2perl(1);
  my $a1 = get_array();
  print "Array returned as an " . ref($a1) . "\n";
  my ( $dims, $ndim, $atype ) = $a1->array_info();
  print "  dim size = $$dims[0]\n";
  print "  type     = $atype\n";

  # use a piddle (assumes Inline::SLang::sl_have_pdl() == 1)
  sl_array2perl(2);
  my $a2 = get_array();
  print "Array returned as an " . ref($a2) . "\n";
  print "  dim size = " . $a2->dims(0) . "\n";
  print "  type     = " . $a2->type . "\n";

  __END__
  __SLang__

  define get_array() { return [ 14.0, 3 ]; }

This example is available as examples/array_conversion.pl in the source distribution. When run this outputs:

  Array returned as an ARRAY
    dim size = 2
  Array returned as an Array_Type
    dim size = 2
    type     = Double_Type
  Array returned as an PDL
    dim size = 2
    type     = double

Issues with the PDL support ^

How to access array elements

Although both languages deal with n-dimensional arrays, they use different indexing schemes: PDL uses the FORTRAN-like method where the first index loops fastest, whilst S-Lang uses the C indexing scheme, where the last index loops fastest. This means that a 2 by 3 array in PDL is represented as a 3 by 2 array in S-Lang.

Handling "virtual" piddles

Currently, any "virtual" piddle sent to a S-Lang function will be "made physical". This ensures that the S-Lang function is sent the correct data but will lead to increased memory use. As an example, if foo() is a S-Lang function then

  $a = sequence(10);
  $b = $a(2:5);
  print $b->info( "Type: %T Dim: %-15D State: %S" );
  foo( $b );
  print $b->info( "Type: %T Dim: %-15D State: %S" );

will change $b just as if make_physical() had been called on it. The output of the two print lines would be:

  Type: Double Dim: D [4]           State: -C
  Type: Double Dim: D [4]           State: P

Dealing with piddles with zero dimensionality

In PDL you can have piddles with zero dimensionality. I have not yet decided whether these should be converted to S-Lang as a scalar or a single-element array. Either choice would result in loss of information if the variable were returned to Perl.

It should be possible to change the way the data from the piddle is accessed to avoid this.

Support for 64-bit machines

The PDL support has only been tested on 32-bit machines, so it is possible that things may not work well on 64-bit machines.

THE ARRAY_TYPE CLASS ^

The Perl Array_Type class stores the datatype and dimensionality of an array along with the data. In most cases this information is not needed so you should stick with using array references (or piddles) since it's much easier, but there are times when it can come in handy.

The Array_Type class inherit the default methods of all the Inline::SLang objects, namely:

As with the other object classes these methods can only be called using the $object->method( args ) syntax. There are also a number of additional methods for this class:

Further methods could be added to improve the array access - such as the resize S-Lang function and means of accessing array slices - but this is unlikely to happen since PDL has a much richer set of operations (although they only work for numeric types), or you can do the array processing in S-Lang.

SEE ALSO ^

Inline::SLang::Assoc, Inline::SLang::Types, Inline::SLang, PDL

syntax highlighting: