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< double> ( ) ;
var m2 = new Matrix2< double> ( ) ;
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< T>
{
static readonly Func< T, T, T> add;
static Matrix1( )
{
var a = Expression.Parameter ( typeof( T) ) ;
var b = Expression.Parameter ( typeof( T) ) ;
add = Expression.Lambda < Func< T, T, T>> ( 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< T>
{
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< Expression, Expression> 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 ( ) ,
)
) ,
)
) ;
}
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 < MatrixOperation> (
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] ;
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uTGlucS5FeHByZXNzaW9uczsKdXNpbmcgU3lzdGVtLkRpYWdub3N0aWNzOwoKc3RhdGljIGNsYXNzIFByb2dyYW0KewogICAgc3RhdGljIHZvaWQgTWFpbigpCiAgICB7CiAgICAJdHJ5IHsKCSAgICAJdmFyIHRlc3QgPSBuZXcgZG91YmxlWzEwMDAsIDEwMDBdOwoJICAgIAkKCSAgICAgICAgdmFyIG0xID0gbmV3IE1hdHJpeDE8ZG91YmxlPigpOwoJICAgICAgICB2YXIgbTIgPSBuZXcgTWF0cml4Mjxkb3VibGU+KCk7CgkgICAgICAgIHZhciBtbiA9IG5ldyBNYXRyaXhOKCk7CgoJICAgICAgICAvLyB3YXJtIHVwCgkgICAgICAgIG0xLkFkZCh0ZXN0LCB0ZXN0KTsKCSAgICAgICAgbTIuQWRkKHRlc3QsIHRlc3QpOwoJICAgICAgICBtbi5BZGQodGVzdCwgdGVzdCk7CgogICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgajwyOyBqKyspIHsKCQkgICAgICAgIFN0b3B3YXRjaCBzd0UgPSBuZXcgU3RvcHdhdGNoKCksIHN3RCA9IG5ldyBTdG9wd2F0Y2goKSwgc3dOID0gbmV3IFN0b3B3YXRjaCgpOwoJCQoJCSAgICAgICAgc3dFLlN0YXJ0KCk7CgkJICAgICAgICBmb3IgKGludCBpPTA7IGk8MTAwOyBpKyspCgkJICAgICAgICAJbTEuQWRkKHRlc3QsIHRlc3QpOwoJCSAgICAgICAgc3dFLlN0b3AoKTsKCQoJCSAgICAgICAgc3dELlN0YXJ0KCk7CgkJICAgICAgICBmb3IgKGludCBpPTA7IGk8MTAwOyBpKyspCgkJICAgICAgICAJbTIuQWRkKHRlc3QsIHRlc3QpOwoJCSAgICAgICAgc3dELlN0b3AoKTsKCQkgICAgICAgIAoJCSAgICAgICAgc3dOLlN0YXJ0KCk7CgkJICAgICAgICBmb3IgKGludCBpPTA7IGk8MTAwOyBpKyspCgkJICAgICAgICAJbW4uQWRkKHRlc3QsIHRlc3QpOwoJCSAgICAgICAgc3dOLlN0b3AoKTsKCQkKCQkgICAgICAgIENvbnNvbGUuV3JpdGVMaW5lKCQiU2ltcGxlIHdheTogICAgICBlbGFwc2VkIHRpbWUge3N3RS5FbGFwc2VkfSIpOwoJCSAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoJCJDb21wbGV4IHdheTogICAgIGVsYXBzZWQgdGltZSB7c3dELkVsYXBzZWR9Iik7CgkJICAgICAgICBDb25zb2xlLldyaXRlTGluZSgkIk5vbi1nZW5lcmljIHdheTogZWxhcHNlZCB0aW1lIHtzd04uRWxhcHNlZH0iKTsKICAgICAgICAgICAgfQogICAgCX0gY2F0Y2ggKEV4Y2VwdGlvbiBleCkgewogICAgCQlDb25zb2xlLldyaXRlTGluZShleCk7CiAgICAJfQogICAgfQp9CgpjbGFzcyBNYXRyaXgxPFQ+CnsKICAgIHN0YXRpYyByZWFkb25seSBGdW5jPFQsIFQsIFQ+IGFkZDsKCiAgICBzdGF0aWMgTWF0cml4MSgpCiAgICB7CiAgICAgICAgdmFyIGEgPSBFeHByZXNzaW9uLlBhcmFtZXRlcih0eXBlb2YoVCkpOwogICAgICAgIHZhciBiID0gRXhwcmVzc2lvbi5QYXJhbWV0ZXIodHlwZW9mKFQpKTsKICAgICAgICBhZGQgPSBFeHByZXNzaW9uLkxhbWJkYTxGdW5jPFQsIFQsIFQ+PihFeHByZXNzaW9uLkFkZChhLCBiKSwgYSwgYikuQ29tcGlsZSgpOwogICAgfQoKICAgIHB1YmxpYyB2b2lkIEFkZChUWyxdIGEsIFRbLF0gYikKICAgIHsKICAgIAlpbnQgbGIwID0gYS5HZXRMb3dlckJvdW5kKDApLAogICAgCSAgICB1YjAgPSBhLkdldFVwcGVyQm91bmQoMCksCiAgICAJICAgIGxiMSA9IGEuR2V0TG93ZXJCb3VuZCgxKSwKICAgIAkgICAgdWIxID0gYS5HZXRVcHBlckJvdW5kKDEpOwogICAgCQogICAgCWZvciAodmFyIGkgPSBsYjA7IGk8PXViMDsgaSsrKQogICAgCSAgZm9yICh2YXIgaiA9IGxiMTsgajw9dWIxOyBqKyspCiAgICAJICAgIGFbaSxqXSA9IGFkZChhW2ksal0sIGJbaSxqXSk7CiAgICB9Cn0KCmNsYXNzIE1hdHJpeDI8VD4KewoJZGVsZWdhdGUgdm9pZCBNYXRyaXhPcGVyYXRpb24gKGludCBsYjAsIGludCB1YjAsIGludCBsYjEsIGludCB1YjEsIFRbLF0gYSwgVFssXSBiKTsKICAgIHN0YXRpYyByZWFkb25seSBNYXRyaXhPcGVyYXRpb24gYWRkOwogICAgCiAgICBzdGF0aWMgRXhwcmVzc2lvbiBNYWtlUmFuZ2VGb3IoRXhwcmVzc2lvbiBtaW4sIEV4cHJlc3Npb24gbWF4LCBGdW5jPEV4cHJlc3Npb24sIEV4cHJlc3Npb24+IGJvZHkpIHsKICAgIAl2YXIgaSA9IEV4cHJlc3Npb24uVmFyaWFibGUobWluLlR5cGUpOwogICAgCXZhciBleGl0ID0gRXhwcmVzc2lvbi5MYWJlbCgpOwogICAgCXJldHVybiBFeHByZXNzaW9uLkJsb2NrKG5ld1tdeyBpIH0sIAogICAgCSAgRXhwcmVzc2lvbi5Bc3NpZ24oaSwgbWluKSwKICAgIAkgIEV4cHJlc3Npb24uTG9vcCgKICAgIAkgIAlFeHByZXNzaW9uLkJsb2NrKAogICAgCSAgCQlib2R5KGkpLAogICAgCSAgCQlFeHByZXNzaW9uLkNvbmRpdGlvbigKICAgIAkgIAkJCUV4cHJlc3Npb24uTGVzc1RoYW5PckVxdWFsKEV4cHJlc3Npb24uUHJlSW5jcmVtZW50QXNzaWduKGkpLCBtYXgpLAogICAgCSAgCQkJRXhwcmVzc2lvbi5FbXB0eSgpLAogICAgCSAgCQkJRXhwcmVzc2lvbi5CcmVhayhleGl0KQoJICAJCQkpCgkgIAkJKSwKICAgIAkgIAlleGl0CiAgICAJICApCiAgICAJKTsKICAgIH0KCiAgICBzdGF0aWMgTWF0cml4MigpCiAgICB7CiAgICAJdmFyIGxiMCA9IEV4cHJlc3Npb24uUGFyYW1ldGVyKHR5cGVvZihpbnQpKTsKICAgIAl2YXIgdWIwID0gRXhwcmVzc2lvbi5QYXJhbWV0ZXIodHlwZW9mKGludCkpOwogICAgCXZhciBsYjEgPSBFeHByZXNzaW9uLlBhcmFtZXRlcih0eXBlb2YoaW50KSk7CiAgICAJdmFyIHViMSA9IEV4cHJlc3Npb24uUGFyYW1ldGVyKHR5cGVvZihpbnQpKTsKICAgICAgICB2YXIgYSA9IEV4cHJlc3Npb24uUGFyYW1ldGVyKHR5cGVvZihUWyxdKSk7CiAgICAgICAgdmFyIGIgPSBFeHByZXNzaW9uLlBhcmFtZXRlcih0eXBlb2YoVFssXSkpOwoKICAgICAgICBhZGQgPSBFeHByZXNzaW9uLkxhbWJkYTxNYXRyaXhPcGVyYXRpb24+KAogICAgICAgIAlNYWtlUmFuZ2VGb3IobGIwLCB1YjAsIGkgPT4KICAgICAgICAJCU1ha2VSYW5nZUZvcihsYjEsIHViMSwgaiA9PgogICAgICAgIAkJCUV4cHJlc3Npb24uQWRkQXNzaWduKAogICAgICAgIAkJCQlFeHByZXNzaW9uLkFycmF5QWNjZXNzKGEsIGksIGopLAogICAgICAgIAkJCQlFeHByZXNzaW9uLkFycmF5QWNjZXNzKGIsIGksIGopCiAgICAJCQkJKQogICAgICAgIAkJKQogICAgCQkpLAogICAgCQlsYjAsIHViMCwgbGIxLCB1YjEsIGEsIGIpLkNvbXBpbGUoKTsKICAgIH0KCiAgICBwdWJsaWMgdm9pZCBBZGQoVFssXSBhLCBUWyxdIGIpCiAgICB7CiAgICAJaW50IGxiMCA9IGEuR2V0TG93ZXJCb3VuZCgwKSwKICAgIAkgICAgdWIwID0gYS5HZXRVcHBlckJvdW5kKDApLAogICAgCSAgICBsYjEgPSBhLkdldExvd2VyQm91bmQoMSksCiAgICAJICAgIHViMSA9IGEuR2V0VXBwZXJCb3VuZCgxKTsKICAgIAkgICAgCiAgICAJYWRkKGxiMCwgdWIwLCBsYjEsIHViMSwgYSwgYik7CiAgICB9Cn0KCmNsYXNzIE1hdHJpeE4KewogICAgcHVibGljIHZvaWQgQWRkKGRvdWJsZVssXSBhLCBkb3VibGVbLF0gYikKICAgIHsKICAgIAlpbnQgbGIwID0gYS5HZXRMb3dlckJvdW5kKDApLAogICAgCSAgICB1YjAgPSBhLkdldFVwcGVyQm91bmQoMCksCiAgICAJICAgIGxiMSA9IGEuR2V0TG93ZXJCb3VuZCgxKSwKICAgIAkgICAgdWIxID0gYS5HZXRVcHBlckJvdW5kKDEpOwogICAgCQogICAgCWZvciAodmFyIGkgPSBsYjA7IGk8PXViMDsgaSsrKQogICAgCSAgZm9yICh2YXIgaiA9IGxiMTsgajw9dWIxOyBqKyspCiAgICAJICAgIGFbaSxqXSArPSBiW2ksal07CiAgICB9Cn0K