I just need to explain better perhaps. So look at this:

typedef vec = array[int,3];
fun + (x:vec,y:vec)=>x.0 + y.0, x.1 + y.1, x.2 + y.2;
var x = 1,2,3;
var y = x + x + x + x;
println$ y;

generated code:

      PTF x.data[0] = 1; //assign
      PTF x.data[1] = 2; //assign
      PTF x.data[2] = 3; //assign
      PTF y.data[0] = PTF x.data[0] + PTF x.data[0]  + PTF x.data[0]  + PTF 
x.data[0] ; //assign
      PTF y.data[1] = PTF x.data[1] + PTF x.data[1]  + PTF x.data[1]  + PTF 
x.data[1] ; //assign
      PTF y.data[2] = PTF x.data[2] + PTF x.data[2]  + PTF x.data[2]  + PTF 
x.data[2] ; //assign

Do you understand how awesome that it???

It looks obvious that this should be what is generated but that is NOT going to 
be
what C++ would generate for a struct. Let me illustrate the awesomeness better:

var z = (x+x+x+x) . 0;

What will C++ do? Why, it will calculate 

        tmp = x + x;
        tmp2 = tmp + x;
        tmp3 = tmp2 + x;
        z = tmp3.0;

Here's what Felix calculates:

      PTF z = PTF x.data[0] + PTF x.data[0]  + PTF x.data[0]  + PTF x.data[0] ; 
//assign

The projection "slices" into the whole formula. The technical (and confusing)
term is that it commutes with parallel addition.

Now let me rewrite that code:

struct vec { a:int; b:int; c:int; };
fun + (x:vec,y:vec)=>vec (x.a + y.a, x.b + y.b, x.c + y.c);
val x = vec (1,2,3);
var y = x + x + x + x;
var z = (x+x+x+x) . a;

println$ (y.a,y.b,y.c),z;

That's semantically identical, right?

Here's the generated code:

      PTF x = reinterpret<_s42810t_57875>(_at57877(1, 2, 3))/* apply struct */; 
//assign

      PTF y = 
reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(PTF
 x.a + PTF x.a , PTF x.b + PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.a + 
PTF x.a , reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + 
PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.b + PTF x.b , 
reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + PTF x.b , 
PTF x.c + PTF x.c ))/* apply struct */.c + PTF x.c ))/* apply struct */.a + PTF 
x.a , 
reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(PTF 
x.a + PTF x.a , PTF x.b + PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.a + 
PTF x.a , reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + 
PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.b + PTF x.b , 
reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + PTF x.b , 
PTF x.c + PTF x.c ))/* apply struct */.c + PTF x.c ))/* apply struct */.b + PTF 
x.b , 
reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(PTF 
x.a + PTF x.a , PTF x.b + PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.a + 
PTF x.a , reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + 
PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.b + PTF x.b , 
reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + PTF x.b , 
PTF x.c + PTF x.c ))/* apply struct */.c + PTF x.c ))/* apply struct */.c + PTF 
x.c ))/* apply struct */; //assign

      PTF z = 
reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(PTF
 x.a + PTF x.a , PTF x.b + PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.a + 
PTF x.a , reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + 
PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.b + PTF x.b , 
reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + PTF x.b , 
PTF x.c + PTF x.c ))/* apply struct */.c + PTF x.c ))/* apply struct */.a + PTF 
x.a , 
reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(PTF 
x.a + PTF x.a , PTF x.b + PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.a + 
PTF x.a , reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + 
PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.b + PTF x.b , 
reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + PTF x.b , 
PTF x.c + PTF x.c ))/* apply struct */.c + PTF x.c ))/* apply struct */.b + PTF 
x.b , 
reinterpret<_s42810t_57875>(_at57877(reinterpret<_s42810t_57875>(_at57877(PTF 
x.a + PTF x.a , PTF x.b + PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.a + 
PTF x.a , reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + 
PTF x.b , PTF x.c + PTF x.c ))/* apply struct */.b + PTF x.b , 
reinterpret<_s42810t_57875>(_at57877(PTF x.a + PTF x.a , PTF x.b + PTF x.b , 
PTF x.c + PTF x.c ))/* apply struct */.c + PTF x.c ))/* apply struct */.c + PTF 
x.c ))/* apply struct */.a; //assign

Now, if you look at nbody, you can see that the C code CHEATS. It hand optimises
the calculation by doing each x,y,z component separately.

The Felix code does NOT cheat. It defines array addition, subtraction, scalar 
multiplication
and uses those definitions.

The PROBLEM in the Felix code is that a planet is a struct, and value 
projections like:

        planets . orbitno . velocity

actually grab the whole planet structure for the given orbitno, then grab the
velocity of that. C++ would use a const ref instead which is a pointer.
In this case, pass by value is not a good thing.

Generally pass by value is still better though! because it can "delve into"
the structure of a computation and optimise it, whereas passing
a pointer cannot do that.


--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
The Go Parallel Website, sponsored by Intel - in partnership with Geeknet, 
is your hub for all things parallel software development, from weekly thought 
leadership blogs to news, videos, case studies, tutorials, tech docs, 
whitepapers, evaluation guides, and opinion stories. Check out the most 
recent posts - join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to