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;
        }

        //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

Reply via email to