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
