Expression template

rikki cattermole via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jul 23 05:27:39 PDT 2016


On 24/07/2016 12:09 AM, Etranger wrote:
> On Saturday, 23 July 2016 at 11:19:34 UTC, rikki cattermole wrote:
>> On 23/07/2016 11:05 PM, Etranger wrote:
>> [snip]
>>
>>> ***************** start of code ******************
>>> import std.stdio;
>>> import std.traits;
>>> import std.conv;
>>>
>>> struct VecExpression(alias mixins) {
>>>   mixin (mixins);
>>>   VecSum!(typeof(this), VecExpression!(RHS)) opBinary(string op, alias
>>> RHS)(ref VecExpression!(RHS) rhs)
>>> {
>>>   static if (op == "+") return VecSum!(typeof(this),
>>> VecExpression!(RHS))(&this, &rhs);
>>> }
>>> }
>>>
>>>
>>> mixin template Vec_impl(int n) {
>>>   double[n] elems;
>>>
>>>   @disable this();
>>>
>>>   this(double[n] e){
>>>     elems=e;
>>>   }
>>>
>>>   double opIndex(int i) {
>>>     return elems[i];
>>>   }
>>> }
>>>
>>> alias Vec(alias n) = VecExpression!("mixin
>>> Vec_impl!("~to!string(n)~");"); //Vec(int n) does not work
>>>
>>> mixin template VecSum_impl(E1, E2) {
>>>   E1 * e1;
>>>   E2 * e2;
>>>
>>>   @disable this();
>>>
>>>   this(E1 * ee1, E2 * ee2){
>>>     e1=ee1;
>>>     e2=ee2;
>>>   }
>>>
>>>   double opIndex(int i) {
>>>     return (*e1)[i]+(*e2)[i];
>>>   }
>>> }
>>>
>>> alias VecSum(E1, E2) = VecExpression!("mixin
>>> VecSum_impl!("~fullyQualifiedName!E1~","~fullyQualifiedName!E2~");");
>>>
>>> void main()
>>> {
>>>   Vec!(3) v1 = Vec!(3)([5., 2., 3.]), v2 = Vec!(3)([1., 4., 3.]), v3 =
>>> Vec!(3)([3., 2., 1.]);
>>>   auto res = v1+v2;
>>>   for(int i=0; i < 3; ++i){
>>>     writefln("%f + %f = %f", v1[i], v2[i],  res[i]);
>>>   }
>>>   auto res2 = res+v3;
>>>   for(int i=0; i < 3; ++i){
>>>     writefln("%f + %f = %f", res[i], v3[i],  res2[i]);
>>>   }
>>>   writeln(res);
>>>   writeln(res2);
>>>
>>>   // VecExpression!(Vec_impl!(3)) ve; // Error: template instance
>>> Vec_impl!3 mixin templates are not regular templates
>>> }
>>>
>>> ***************** end of code ******************
>>>
>>> My questions:
>>>
>>> 1- Is there a cleaner way to do it ? I had to use struct because I want
>>> every thing to happen at compile time and on the stack (without gc). And
>>> I had to use string mixins because template mixin does not work the way
>>> I tried to use it ( see the error last line).
>>>
>>> 2- Is there a safer way to do it (without using pointers) ?
>>>
>>> 3- Do you think I'll hit a wall with this approach ?
>>>
>>> 4- Do you known any D libs that uses expression template for linear
>>> algebra ?
>>>
>>> I thank you in advance for your help and wish you a nice weekend (and
>>> apologize for my bad english) :)
>>
>> My goodness that code is awful.
>>
>> I have a fair idea what you are attempting to do here.
>> So I'm going to point you directly to gl3n. Its meant for game dev so
>> won't provide you a 100% solution. But it should give you ideas of how
>> to do it.
>>
>> https://github.com/Dav1dde/gl3n/blob/master/gl3n/linalg.d#L49
>>
>> If you have any questions and want somebody to talk with you instead
>> of write, reply cycle. Please hop on to Freenode #d channel.
>
> Hi and thanks for your quick replay.
>
> A looked to the gl3n code, although the code is clear and clean, it is
> not really what I want to do in my example.
>
> The gl3n is eager evaluation. If I write "v = v1+v2+v3;", then it will
> create a temporary variable "tmp1=v1+v2;" then a second temp
> "tmp2=tmp1+v3;" and finally "v=tmp2;".
>
> what I'm trying to do to use lazy evaluation in order to create only one
> tmp that will that will directly hold the result of v1[i]+v2[i]+v3[i].
> That concept is then generalized in order to perform more optimization
> based on entire expression trees, no just tow operands.
>
> And thanks for the suggestion regarding the channel, I'll try to use it
> as soon as I have the time. I feel on advantage of the forum is that it
> stays for other people and not just for me.
>
> best regards

If you evaluate it as v = a + b + c instead of v = a + (b + c) you will 
still have a temporary value. Remember structs are just the values they 
carry and are basically optimized out. Either way I recommend you not 
worry about it. Compilers can be smart and dmd is mostly good enough in 
this department.

If you use dynamic arrays and not fixed sized arrays, they will go into 
the heap, so be careful with what you do with them. Fixed sized arrays 
like gl3n does is fairly cheap since it goes on to the stack and in some 
cases only in registers.

Usually if we solve it on IRC we post the solution that we come up with 
on the post.


More information about the Digitalmars-d-learn mailing list