using System; using System.Linq.Expressions; using System.Diagnostics; static class Program { static void Main() { try { var test = new double[1000, 1000]; var m1 = new Matrix1(); var m2 = new Matrix2(); var mn = new MatrixN(); // warm up m1.Add(test, test); m2.Add(test, test); mn.Add(test, test); for (var j = 0; j<2; j++) { Stopwatch swE = new Stopwatch(), swD = new Stopwatch(), swN = new Stopwatch(); swE.Start(); for (int i=0; i<100; i++) m1.Add(test, test); swE.Stop(); swD.Start(); for (int i=0; i<100; i++) m2.Add(test, test); swD.Stop(); swN.Start(); for (int i=0; i<100; i++) mn.Add(test, test); swN.Stop(); Console.WriteLine($"Simple way: elapsed time {swE.Elapsed}"); Console.WriteLine($"Complex way: elapsed time {swD.Elapsed}"); Console.WriteLine($"Non-generic way: elapsed time {swN.Elapsed}"); } } catch (Exception ex) { Console.WriteLine(ex); } } } class Matrix1 { static readonly Func add; static Matrix1() { var a = Expression.Parameter(typeof(T)); var b = Expression.Parameter(typeof(T)); add = Expression.Lambda>(Expression.Add(a, b), a, b).Compile(); } public void Add(T[,] a, T[,] b) { int lb0 = a.GetLowerBound(0), ub0 = a.GetUpperBound(0), lb1 = a.GetLowerBound(1), ub1 = a.GetUpperBound(1); for (var i = lb0; i<=ub0; i++) for (var j = lb1; j<=ub1; j++) a[i,j] = add(a[i,j], b[i,j]); } } class Matrix2 { delegate void MatrixOperation (int lb0, int ub0, int lb1, int ub1, T[,] a, T[,] b); static readonly MatrixOperation add; static Expression MakeRangeFor(Expression min, Expression max, Func body) { var i = Expression.Variable(min.Type); var exit = Expression.Label(); return Expression.Block(new[]{ i }, Expression.Assign(i, min), Expression.Loop( Expression.Block( body(i), Expression.Condition( Expression.LessThanOrEqual(Expression.PreIncrementAssign(i), max), Expression.Empty(), Expression.Break(exit) ) ), exit ) ); } static Matrix2() { var lb0 = Expression.Parameter(typeof(int)); var ub0 = Expression.Parameter(typeof(int)); var lb1 = Expression.Parameter(typeof(int)); var ub1 = Expression.Parameter(typeof(int)); var a = Expression.Parameter(typeof(T[,])); var b = Expression.Parameter(typeof(T[,])); add = Expression.Lambda( MakeRangeFor(lb0, ub0, i => MakeRangeFor(lb1, ub1, j => Expression.AddAssign( Expression.ArrayAccess(a, i, j), Expression.ArrayAccess(b, i, j) ) ) ), lb0, ub0, lb1, ub1, a, b).Compile(); } public void Add(T[,] a, T[,] b) { int lb0 = a.GetLowerBound(0), ub0 = a.GetUpperBound(0), lb1 = a.GetLowerBound(1), ub1 = a.GetUpperBound(1); add(lb0, ub0, lb1, ub1, a, b); } } class MatrixN { public void Add(double[,] a, double[,] b) { int lb0 = a.GetLowerBound(0), ub0 = a.GetUpperBound(0), lb1 = a.GetLowerBound(1), ub1 = a.GetUpperBound(1); for (var i = lb0; i<=ub0; i++) for (var j = lb1; j<=ub1; j++) a[i,j] += b[i,j]; } }