www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - array operations enhancements

reply F. Almeida <francisco.m.almeida gmail.com> writes:
It is an excellent feature of D2 that one can do

double a[];
double b[];
double c[];

//...

c = a[] + 2.0*b[];

But this is still limited, as we cannot include function calls in
these operations.

What if the compiler was able to introduce them in the assignment
loop, provided that the functions pass ref double (in this case)?

double anyfun(ref double x) { ... }

c = anyfun(a[]) + 2.0*b[];
Aug 17 2010
next sibling parent reply Don <nospam nospam.com> writes:
F. Almeida wrote:
 It is an excellent feature of D2 that one can do
 
 double a[];
 double b[];
 double c[];
 
 //...
 
 c = a[] + 2.0*b[];
 
 But this is still limited, as we cannot include function calls in
 these operations.
 
 What if the compiler was able to introduce them in the assignment
 loop, provided that the functions pass ref double (in this case)?
 
 double anyfun(ref double x) { ... }
 
 c = anyfun(a[]) + 2.0*b[];

It's not terribly obvious to me that the 'ref' means 'this function can be parallelized'. Also, the function needs to be marked as pure. Otherwise, that's an interesting syntax. I do think we need a solution to this, so it's good to keep thinking about. It may be that, for example: a[] = x * sin(b[])[] + y * cos(b[])[]; will be enough.
Aug 18 2010
parent reply ponce <contact g1a2m3es4f5r6om7m8ars.fr> writes:
pure double anyfunc(ref double x) { ... }

pure double anyfunc(double[]) { ... }

double[] c = anyfun(a[]) + 2.0*b[];



This proposal could be nice for making array operations more useful, but
complicates overloading.
Aug 19 2010
parent reply Don <nospam nospam.com> writes:
ponce wrote:
 pure double anyfunc(ref double x) { ... }
 
 pure double anyfunc(double[]) { ... }
 
 double[] c = anyfun(a[]) + 2.0*b[];
 
 
 
 This proposal could be nice for making array operations more useful, but
complicates overloading.

double [] c = anyfun(a[]) * b[]; Is this element-wise using the first function, or scalar multiplication using the second? That's why I think appending a [] to the end of every function call would probably be necessary. Changing your second function to: pure double[] anyfunc(double[]) { ... } would have to create an error, because otherwise there is an ambiguity with double[] c = anyfun(a[0..$])[] + b[]; So I don't think the 'ref' is buying us anything at all. We could say that [] after a function call means 'use an array function, if it exists, otherwise synthesize an array operation, if a pure single-element function exists, otherwise generate an error'. And at present, array operations cannot generate temporaries, so an attempt to use the array function from inside an array operation would always be an error.
Aug 19 2010
parent Kagamin <spam here.lot> writes:
Don Wrote:

 ponce wrote:
 pure double anyfunc(ref double x) { ... }
 
 pure double anyfunc(double[]) { ... }
 
 double[] c = anyfun(a[]) + 2.0*b[];
 
 
 
 This proposal could be nice for making array operations more useful, but
complicates overloading.

double [] c = anyfun(a[]) * b[]; Is this element-wise using the first function, or scalar multiplication using the second?

Just report the ambiguity error.
Aug 19 2010
prev sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Aug 18, 10 14:41, F. Almeida wrote:
 It is an excellent feature of D2 that one can do

 double a[];
 double b[];
 double c[];

 //...

 c = a[] + 2.0*b[];

 But this is still limited, as we cannot include function calls in
 these operations.

 What if the compiler was able to introduce them in the assignment
 loop, provided that the functions pass ref double (in this case)?

 double anyfun(ref double x) { ... }

 c = anyfun(a[]) + 2.0*b[];

import std.algorithm; import std.stdio; import std.array; auto vectorize(alias f, U)(U a) { return array(map!f(a)); } double square(double x) { return x*x; } void main () { auto a = [1.0, 2.0, 3.0, 4.0]; auto b = [5.0, 6.0, 7.0, 8.0]; auto c = [0.0, 0.0, 0.0, 0.0]; c[] = vectorize!square(a)[] + 2.0 * b[]; writeln(">", c); }
Aug 19 2010
parent reply F. Almeida <francisco.m.almeida gmail.com> writes:
== Quote from KennyTM~ (kennytm gmail.com)'s article
 On Aug 18, 10 14:41, F. Almeida wrote:
 What if the compiler was able to introduce them in the


 loop, provided that the functions pass ref double (in this


 double anyfun(ref double x) { ... }

 c = anyfun(a[]) + 2.0*b[];

import std.stdio; import std.array; auto vectorize(alias f, U)(U a) { return array(map!f(a)); } double square(double x) { return x*x; } void main () { auto a = [1.0, 2.0, 3.0, 4.0]; auto b = [5.0, 6.0, 7.0, 8.0]; auto c = [0.0, 0.0, 0.0, 0.0]; c[] = vectorize!square(a)[] + 2.0 * b[]; writeln(">", c); }

This doesn't help, as vectorize!() is being called to create an array before passing it to the array expression (one additional assignment loop). Additional functions passed through vectorize!() would lead to N+1 loops per operation, with N the number of vectorize!() calls, instead of the intended single loop. What is intended is to pass as many functions as possible, and allow the assignment to occur within a single loop. The best alternative so far is to allow the compiler to take initiative whenever a pure function accepting one argument (value, not ref) of the same type exists. pure double myf(double x) { ... } c[] = myf(a[]) + 2.0*myf(b[]); Is such an optimization possible?
Aug 19 2010
parent Don <nospam nospam.com> writes:
F. Almeida wrote:
 == Quote from KennyTM~ (kennytm gmail.com)'s article
 On Aug 18, 10 14:41, F. Almeida wrote:
 What if the compiler was able to introduce them in the


 loop, provided that the functions pass ref double (in this


 double anyfun(ref double x) { ... }

 c = anyfun(a[]) + 2.0*b[];

import std.stdio; import std.array; auto vectorize(alias f, U)(U a) { return array(map!f(a)); } double square(double x) { return x*x; } void main () { auto a = [1.0, 2.0, 3.0, 4.0]; auto b = [5.0, 6.0, 7.0, 8.0]; auto c = [0.0, 0.0, 0.0, 0.0]; c[] = vectorize!square(a)[] + 2.0 * b[]; writeln(">", c); }

This doesn't help, as vectorize!() is being called to create an array before passing it to the array expression (one additional assignment loop). Additional functions passed through vectorize!() would lead to N+1 loops per operation, with N the number of vectorize!() calls, instead of the intended single loop. What is intended is to pass as many functions as possible, and allow the assignment to occur within a single loop. The best alternative so far is to allow the compiler to take initiative whenever a pure function accepting one argument (value, not ref) of the same type exists. pure double myf(double x) { ... } c[] = myf(a[]) + 2.0*myf(b[]); Is such an optimization possible?

Definitely. I'm just a bit paranoid about what could happen with user-defined types. I would hope, btw, that we could do: Complex!double[] a; double [] r = a[].re; // grab the real part I see abs, sqrt, re, and im as the most important use cases. My feeling is that it might be necessary to restrict this to: c[] = myf(a[])[] + 2.0 * myf(b[])[]; That may be paranoia on my part. I'm not certain that
Aug 20 2010