using System;
using System.Text;
public struct Magma<T>
{
public readonly Func<T, T, T> op;
public Magma(Func<T, T, T> op)
{
this.op = op;
}
}
public static class Magma
{
public static readonly Magma<float> FloatSum =
new Magma<float>((a, b) => a + b);
public static readonly Magma<int> IntSum =
new Magma<int>((a, b) => a + b);
}
public struct Matrix<T>
{
public readonly T[] Elems;
public readonly int Dim;
public Matrix(int dim)
{
Dim = dim;
Elems = new T[dim * dim];
}
public Matrix(T[] elems)
{
Dim = (int)Math.Sqrt(elems.Length);
Elems = elems;
}
public override string ToString()
{
var sb = new StringBuilder();
for (int i = 0; i < Dim; ++i)
{
for (int j = 0; j < Dim; ++j)
sb.Append(Elems[i*Dim + j]).Append(' ');
sb.AppendLine();
}
return sb.ToString();
}
}
public static class Matrix
{
public static Matrix<T> Sum<T>(Matrix<T> lhs, Matrix<T> rhs, Magma<T> sum)
{
var result = new Matrix<T>(lhs.Dim);
for (int i = 0; i < lhs.Elems.Length; ++i)
{
result.Elems[i] = sum.op(lhs.Elems[i], rhs.Elems[i]);
}
return result;
}
}
public class Test
{
public static void Main()
{
var a = new Matrix<float>(new float[] { 1.1f, 2.2f, 3.3f, 4.4f });
Console.WriteLine(Matrix.Sum(a, a, Magma.FloatSum));
var b = new Matrix<int>(new int[] { 3, 5, 4, 9 });
Console.WriteLine(Matrix.Sum(b, b, Magma.IntSum));
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uVGV4dDsKCnB1YmxpYyBzdHJ1Y3QgTWFnbWE8VD4KewogICAgcHVibGljIHJlYWRvbmx5IEZ1bmM8VCwgVCwgVD4gb3A7CiAgICBwdWJsaWMgTWFnbWEoRnVuYzxULCBULCBUPiBvcCkKICAgIHsKICAgICAgICB0aGlzLm9wID0gb3A7CiAgICB9Cn0KCnB1YmxpYyBzdGF0aWMgY2xhc3MgTWFnbWEKewogICAgcHVibGljIHN0YXRpYyByZWFkb25seSBNYWdtYTxmbG9hdD4gRmxvYXRTdW0gPQogICAgICAgIG5ldyBNYWdtYTxmbG9hdD4oKGEsIGIpID0+IGEgKyBiKTsKICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgTWFnbWE8aW50PiBJbnRTdW0gPQogICAgICAgIG5ldyBNYWdtYTxpbnQ+KChhLCBiKSA9PiBhICsgYik7ICAgICAgICAKfQoKcHVibGljIHN0cnVjdCBNYXRyaXg8VD4KewogICAgcHVibGljIHJlYWRvbmx5IFRbXSBFbGVtczsKICAgIHB1YmxpYyByZWFkb25seSBpbnQgRGltOwoKICAgIHB1YmxpYyBNYXRyaXgoaW50IGRpbSkKICAgIHsKICAgICAgICBEaW0gPSBkaW07CiAgICAgICAgRWxlbXMgPSBuZXcgVFtkaW0gKiBkaW1dOwogICAgfQoKICAgIHB1YmxpYyBNYXRyaXgoVFtdIGVsZW1zKQogICAgewogICAgICAgIERpbSA9IChpbnQpTWF0aC5TcXJ0KGVsZW1zLkxlbmd0aCk7CiAgICAgICAgRWxlbXMgPSBlbGVtczsKICAgIH0KICAgIAogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBUb1N0cmluZygpIAogICAgewogICAgCXZhciBzYiA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAJZm9yIChpbnQgaSA9IDA7IGkgPCBEaW07ICsraSkKICAgIAl7CiAgICAJCWZvciAoaW50IGogPSAwOyBqIDwgRGltOyArK2opCiAgICAJCQlzYi5BcHBlbmQoRWxlbXNbaSpEaW0gKyBqXSkuQXBwZW5kKCcgJyk7CiAgICAJCXNiLkFwcGVuZExpbmUoKTsKICAgIAl9CiAgICAJcmV0dXJuIHNiLlRvU3RyaW5nKCk7CiAgICB9Cn0KCnB1YmxpYyBzdGF0aWMgY2xhc3MgTWF0cml4CnsKICAgIHB1YmxpYyBzdGF0aWMgTWF0cml4PFQ+IFN1bTxUPihNYXRyaXg8VD4gbGhzLCBNYXRyaXg8VD4gcmhzLCBNYWdtYTxUPiBzdW0pCiAgICB7CiAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBNYXRyaXg8VD4obGhzLkRpbSk7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBsaHMuRWxlbXMuTGVuZ3RoOyArK2kpCiAgICAgICAgewogICAgICAgICAgICByZXN1bHQuRWxlbXNbaV0gPSBzdW0ub3AobGhzLkVsZW1zW2ldLCByaHMuRWxlbXNbaV0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgfQp9CgpwdWJsaWMgY2xhc3MgVGVzdAp7CglwdWJsaWMgc3RhdGljIHZvaWQgTWFpbigpCgl7CgkJdmFyIGEgPSBuZXcgTWF0cml4PGZsb2F0PihuZXcgZmxvYXRbXSB7IDEuMWYsIDIuMmYsIDMuM2YsIDQuNGYgfSk7CgkJQ29uc29sZS5Xcml0ZUxpbmUoTWF0cml4LlN1bShhLCBhLCBNYWdtYS5GbG9hdFN1bSkpOwoJCXZhciBiID0gbmV3IE1hdHJpeDxpbnQ+KG5ldyBpbnRbXSB7IDMsIDUsIDQsIDkgfSk7CgkJQ29uc29sZS5Xcml0ZUxpbmUoTWF0cml4LlN1bShiLCBiLCBNYWdtYS5JbnRTdW0pKTsKCX0KfQ==