develooper Front page | perl.perl6.language.data | Postings from September 2000

Re: RFC 207 (v1) Array: Efficient Array Loops

Thread Previous | Thread Next
From:
Buddha Buck
Date:
September 11, 2000 15:38
Subject:
Re: RFC 207 (v1) Array: Efficient Array Loops
Message ID:
20000911223759.1D27115865@zaphod
> Reading through the examples left me wondering about some
> technicalities:
> 
> >   @t[|i;|j] = @a[|j;|i];  # transpose 2-d @a
> 
> Written like this it would require that @a is exact 2-dim, i.e. it would
> not just swap the first two dims of any n-dim array? I suppose if I'd
> want that I'd write
> 
>     @t[|i;|j;] = @a[|j;|i;]; # trailing ';' implies there might be
> trailing dims

I will confess, operations on general multidimensional arrays were not 
something I had considered when I originally had this idea.  The 
problem I see with your @t[|i;|j;] example is that it isn't clear that 
the trailing dims for @a and @t will have tied iterators.  I.e., if @a 
is defined with "my @a :bounds (3,3,3);", which of these two should be 
considered equivilant?

      @t[|i;|j;|k] = @a[|j;|i;|k];  # or...
      @t[|i;|j;|k] = @a[|j;|i;|l];

Arguments could be made for either one.

> >   #compute pairwise sum, pairwise product, pairwise difference...
> >   @sum = @a[|i;|j;|k;|l] + @b[|i;|j;|k;|l];
> >   @prod= @a[|i;|j;|k;|l] * @b[|i;|j;|k;|l];
> >   @diff= @a[|i;|j;|k;|l] - @b[|i;|j;|k;|l];
> 
> Hm, not sure if I am missing the point of these examples. Is that any
> different from the elementwise '+','*','-' apart from being possibly
> limited to 4D arrays?

It would be another way to do it, assuming that elementwise operators 
are accepted.  There does seem to be some resistance to the idea.  In 
which case, this would become the preferred way to do it.

> >   #print lots of stuff to the screen.
> >   sub foo { print join(',',@_),"\n"; return 0; }
> >   $zero[|i;|j;|k;|l;|m;|n;|o;|p] = foo(|i,|j,|k,|l,|m,|n,|o,|p);
> 
> Should that be '$zero' or '@zero'?

That's an interesting question.  Based on the reasoning I had when I 
wrote the RFC, it probably should be @zero.  But... the $zero[...] 
notation is more suggestive of what it's actually doing.

Would:

   $zero[[|i,|j,|k,|l,|m,|n,|o,|p]] = foo(...);

be a good alternate or replacement for @zero[|i;|j;...]?


> >   # Sneaky way to generate dot-product:
> >   my $dotproduct;
> >   { my @temp[|i] = $dotproduct += $a[|i] * $b[|i]; }
> 
> Hm, how can this work with lazy evaluation? How is Perl supposed to know
> that @temp should be transiently created to increment $dotproduct as a
> side effect? Also, doesn't the above syntax seem to be conflicting with
> perl context rules since it essentially contains a statement
> 
>    @arr = $scalar

Hmmm, would {my @temp; $temp[|i] = $dotproduct += $a[|i] * $b[|i]; } 
deal with the
@arr = $scaler issue?

As far as the transient creation of @temp, what would happen is that 
the entire expression
 "$temp[$i] = $dotproduct += $a[$i] * $b[$i]" would get wrapped in a 
loop:

  { my @temp;
    #generated loop
    for my $i (scaler(@a)) {
      $temp[$i] = $dotproduct += $a[$i] * $b[$i];
    }
  }

  Perhaps a better way to do that would be:

  (|i, $dotproduct += $a[[|i]] * $b[[|i]]);

Hmm...  Would this work?:

Start with the smallest expression in the statement that includes all 
the iterators.

If the expression is in void context, then simply wrap it in loops, 
replacing each iterator with the appropriately lexically scoped 
variable, renaming if necessary to avoid name-clashes:

  $scalarproduct[|i;|j] = $i * $a[|i;|j];

gets transformed into:

  for my $i_ (0..$#a[0]) {
    for my $j (0..$#a[1]) {
     $scalerproduct[$i_;$j] = $i * $a[|i;|j];
    }
  }

If the expression is in a list context, generate a temporary array of 
dimension equal to the total number of (explicit or implicit) 
iterators, assign the value of the expression evaluated at each 
iteration of the inner loop to the corresponding element of the 
temporary array, and finally return the array:

  @tensorproduct = $a[[|i]] * $b[[|j]];

gets transformed into
 
  @tensorproduct = do {
    my @temp :bounds($#a[0],$#b[1]);
    for my $i (0..$#a[0]) {
      for my $j (0..$#b[1]) {
        @temp[[$i,$j]] = $a[[$i]] * $b[[$j]];
      }
    }
    @temp;
  };

If the expression is in a scalar (lvalue) context expand the scope of 
the iterators:

  $dotproduct += $a[[|i]] + $b[[|i]];
  $a[|i;|j] = rand();

In the first case, the RHS is the smallest expression containing all 
the iterators, but it's in scalar context.  Therefore, expand to 
include the LHS as well, which puts us in void context, then transform 
to:

  for $i (0..$#a) {
    $dotproduct += $a[[$]] + $b[[$i]];
  }

In the second case, the LHS is the smallest expression containing all 
the iterators, but it's in scalar lvalue context.  Therefore, expand to 
include the RHS as well, which puts us in void context, then transform 
to:

  for $i (0..$#a[0]) {
    for $j (0..$#a[1]) {
      $a[[$i,$j]] = rand();
    }
  }

I'm not sure what to do in list lvalue context.  Are there any contexts 
untouched (void lvalue?!?)?

And how do you lazily evaluate a dotproduct, anyway?

>   Christian

-- 
     Buddha Buck                             bmbuck@14850.com
"Just as the strength of the Internet is chaos, so the strength of our
liberty depends upon the chaos and cacophony of the unfettered speech
the First Amendment protects."  -- A.L.A. v. U.S. Dept. of Justice



Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About