Joe,
Here are some questions I have

On Wed, Jul 8, 2015 at 11:16 AM, Joe Bogner <[email protected]> wrote:
> Vijay, Thanks for the feedback. Glad to hear it compiled fine.
>
> Yes, I intend to dispatch to type-specific functions where possible
> and then fall back to dynamic functions. It's a bit tedious to
> implement, but it will yield the best performance. It's a shame that
> C# can't infer the type on dynamically created generic types.
>
> For example, these type-specific math operations for long and double
> are 7x faster than the dynamic mixed version.
>
>         public A<long> mathi(A<long> x, A<long> y, Func<long, long, long> op) 
> {
>             var z = new A<long>(y.Ravel.Length, y.Shape);
>             for(var i = 0; i < y.Ravel.Length; i++) {
>                 //lambdas add about 3% overhead based upon tests of
> 100 times, for now worth it for code clarity
>                 z.Ravel[i] = op(x.Ravel[0], y.Ravel[i]);
>                 //z.Ravel[i] = x.Ravel[0] +  y.Ravel[i];
>             }
>             return z;
>         }
>         public A<double> mathd(A<double> x, A<double> y, Func<double,
> double, double> op) {
>             var z = new A<double>(y.Ravel.Length, y.Shape);
>             for(var i = 0; i < y.Ravel.Length; i++) {
>                 z.Ravel[i] = op(x.Ravel[0], y.Ravel[i]);
>             }
>             return z;
>         }
>

Why can't mathi and mathd not be replaced by the following?

public A<T> math(A<T> x, A<T> y, Func<T,T,T> op) where T : struct {
    var z = new A<T>(y.Ravel.Length, y.Shape);
    for(var i = 0; i < y.Ravel.Length; i++) {
        z.Ravel[i] = op(x.Ravel[0], y.Ravel[i]);
    }
    return z;
}

Is there a penalty for this?  Or more broadly, is there a way that C#
compiler can automatically generate these for all the known (and well
defined?) operations (+,-,/,^) and types (ints, floats, doubles?)?
Julia does this really well.  In Julia repl try @which 2 + 3 and
@which 2.0 + 3 .  It  does type promotion (a very general mechanism)
and is definitely worth checking out (Conversion and Promotion section
in the docs).  I think that J also does a lot of internal type
checking and promotion to get correct results.

>         //dynamic dispatch of math operations -- slowest, around 7x slower
>         public A<double> mathmixed(dynamic x, dynamic y, Func<dynamic,
> dynamic, dynamic> op) {
>             var z = new A<double>(y.Ravel.Length, y.Shape);
>             for(var i = 0; i < y.Ravel.Length; i++) {
>                 z.Ravel[i] = op(x.Ravel[0], y.Ravel[i]);
>             }
>             return z;
>         }
>
> To demonstrate:
>
> Sum up 10 million integers
>
> microj "+/ ( 10000000 $ 1 2 3)" -n 10
> Output: 19999999
> Took: 46.5 ms
>
> jconsole -js "exit [smoutput 1000*(10 (6!:2) '+/ ( 10000000 $ 1 2 3 )')"
> 36.9519
>
> sum up floats:
>
> microj "+/ ( 10000000 $ 1.2 2.3 3.4)" -n 10
> Output: 22999998.8992955
> Took: 45.5 ms
>
> jconsole -js "exit [smoutput 1000*(10 (6!:2) '+/ ( 10000000 $ 1.2 2.3 3.4 )')"
> 39.2031
>
>
> Let's avoid special-code next:
>
> Add 3 to a large array of ints:
>
> microj "$ 3 + ( 10000000 $ 1 2 3)" -n 10
> Took: 96.4 ms
>
> jconsole -js "exit [smoutput 1000*(10 (6!:2) '$ 3 + ( 10000000 $ 1 2 3 )')"
> 60.0216
>
> Add 3.0 to a large array of floats (roughly the same)
>
> microj "$ 3.0 + ( 10000000 $ 1.0 2.0 3.1)" -n 10
> Took: 98.4 ms
>
> jconsole -js "exit [smoutput 1000*(10 (6!:2) '$ 1.0 + ( 10000000 $ 1.1
> 2.2 3.3 )')"
> 58.9558
>
> Add integer to array of floats - hits mixed math operation (38x slower!)
>
> microj "$ 3 + ( 10000000 $ 1.0 2.0 3.1)" -n 10
> Took: 3706.3 ms
>
> J handles it fine
>
> jconsole -js "exit [smoutput 1000*(10 (6!:2) '$ 3 + ( 10000000 $ 1.1
> 2.2 3.3 )')"
> 58.7644
>
> We can add a new overload that takes the mixed long/double:
>
>         public A<double> mathmixed(A<long> x, A<double> y,
> Func<dynamic, dynamic, dynamic> op) {
>             var z = new A<double>(y.Ravel.Length, y.Shape);
>             for(var i = 0; i < y.Ravel.Length; i++) {
>                 z.Ravel[i] = op(x.Ravel[0], y.Ravel[i]);
>             }
>             return z;
>         }
> And add it to the dispatch table:
>
>             if (op == "+") {
>                 if (x.GetType() == typeof(A<long>) && y.GetType() ==
> typeof(A<long>)) {
>                     return mathi((A<long>)x,(A<long>)y, (a,b)=>a+b);
>                 }
>                 else if (x.GetType() == typeof(A<double>) &&
> y.GetType() == typeof(A<double>)) {
>                     return mathd((A<double>)x,(A<double>)y, (a,b)=>a+b);
>                 }
>                 //NEW CODE HERE
>                 else if (x.GetType() == typeof(A<long>) && y.GetType()
> == typeof(A<double>)) {
>                     return mathmixed((A<long>)x,(A<double>)y, (a,b)=>a+b);
>                 }
>                 else if (x.GetType() != y.GetType()) {
>                     return mathmixed(x,y, (a,b)=>a+b);
>                 }
>
>             }
>
> So this skips the dynamic version, but is still 6x slower than keeping
> the types the same
>
> microj "$ 3 + ( 10000000 $ 1.0 2.0 3.1)" -n 10
> Took: 378.1 ms
>
> Of course, now we still have the double/int mixed situation
>
> microj "$ 3.0 + ( 10000000 $ 1 2 3)" -n 10
> Took: 3142.9 ms
>
> This can be resolved the same way, or we can add code to the dispatch
> operation to cast if x is an atom and a different type to the same
> type as the list, which would make sense for x<int> + y<float>but not
> make sense for x<float> + y<int>  where y has rank greater than 1. (In
> other words, it is expensive to cast a list to a different type, but
> not a scalar argument).
>
> That dispatch code would look like this:
>
>                 else if (x.Rank == 0 && x.GetType() != y.GetType() &&
>                          x.GetType() == typeof(A<long>) && y.GetType()
> == typeof(A<double>)) {
>                     //experimental special code for 1 + (1.2 2.3 4.5)
>                     var newx = new A<double>(1);
>                     newx.Ravel[0] = ((A<long>)x).Ravel[0];
>                     return mathd((A<double>)newx,(A<double>)y, (a,b)=>a+b);
>                 }
>
>
> Which gets us back to the performance of same types
>
> microj "$ 1 + ( 10000000 $ 1.1 2.2 3.3)" -n 10
> Took: 91.5 ms
>
>
>
> On Wed, Jul 8, 2015 at 9:05 AM, Vijay Lulla <[email protected]> wrote:
>> Joe,
>> I could compile it just fine using the build.bat.  It looks good and I
>> like the idea of separate library (just like j.dll).  Looking at your
>> source code I was wondering if you intend to dispatch functions (just
>> like J's implementation) based on the data types of arguments to the
>> primitives.  This is one of the superb, and well thought out, aspects
>> of J that I like more every time I use J.
>>
>> I will try to share some code if and when I can.....I haven't
>> programmed in C# for years now!!  Regardless, good start, Joe.
>> Thanks,
>> Vijay.
>>
>> On Wed, Jul 8, 2015 at 3:19 AM, Mike Day <[email protected]> wrote:
>>> OK, Joe
>>> I got it to compile and discovered that I had a c# compiler without
>>> needing to load the SharpDevelop IDE - needed to adapt build.bat
>>> a bit to hard-wire the folder locations. This is in WIndows 8.1
>>>
>>> Anyway,  microj.exe runs ok in a cmd window.  It would be nice if
>>> it didn't abort with i.10 (say),  seeming to require an embedded
>>> space.
>>> The principle feature of any demo,
>>>   10 30$'Hello World'
>>> is fine.
>>>
>>> The unadorned noun   a.   crashed.
>>>
>>> This behaviour was puzzling:
>>> "
>>> +/ i. 10
>>> 45
>>> +/\ i. 10
>>> MicroJ.Verb
>>> "
>>>
>>> A line-feed with only spaces leads to
>>> Unhandled Exception:....
>>>
>>> It would be nice if it would not crash on unhandled exceptions!
>>>
>>> But you probably know all this already.
>>>
>>> Well done, and good luck with the project!
>>>
>>> Thanks,
>>> Mike
>>>
>>>
>>>
>>> On 07/07/2015 21:29, Joe Bogner wrote:
>>>>
>>>> I have a work-in-progress implementation of J in C# that I thought
>>>> would be useful to share. It's actively being worked on, but it's to a
>>>> point where it's useful enough to play with. I figured others may be
>>>> interested in seeing it.
>>>>
>>>> https://github.com/joebo/microj
>>>>
>>>> Feedback is welcome
>>>> ----------------------------------------------------------------------
>>>> For information about J forums see http://www.jsoftware.com/forums.htm
>>>>
>>>
>>>
>>> ---
>>> This email has been checked for viruses by Avast antivirus software.
>>> https://www.avast.com/antivirus
>>>
>>>
>>> ----------------------------------------------------------------------
>>> For information about J forums see http://www.jsoftware.com/forums.htm
>> ----------------------------------------------------------------------
>> For information about J forums see http://www.jsoftware.com/forums.htm
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to