Vijay, good suggestion. It can be replaced with what you suggested. I
committed the change. I believe I split them out when I was trying to
get mixed types to work (int + float)..

.NET won't automatically do type promotion on arrays of numbers, so
that had to be implemented manually in microj

Thanks

On Thu, Jul 9, 2015 at 5:15 PM, Vijay Lulla <[email protected]> wrote:
> 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
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to