ベクトル演算
を作ってみた。
加算は、演算後に次元が変わらないので、割と簡単。
template Dimension(T) { static if (!is (typeof(T.init[0]))) { const size_t Dimension = 0; } else { const size_t Dimension = 1 + Dimension!(typeof(T.init[0])); } } template ElementType(T) { static if (0 == Dimension!(T)) { alias T ElementType; } else { alias typeof(T.init[0]) ElementType; } }
という、エイリアス定義のテンプレートを用意しておき、
T add(T)(in T lhs, in T rhs) { static if (0 == Dimension!(T)) { return lhs + rhs; } else { return vv_add!(ElementType!(T))(lhs, rhs); } } private T[] vv_add(T)(in T[] lhs, in T[] rhs) in { assert(lhs.length == rhs.length); } body { T[] result = new T[lhs.length]; foreach (i; 0..lhs.length) { result[i] = add!(T)(lhs[i], rhs[i]); } return result; }
ですんでしまう。
乗算となると、次元数が変わるので大変。
まぁ、現実的には2次元配列までサポートできればよいでしょう。
理論的には3次元以上の配列もサポートしたいけど。
template MultiplyResultType(L, R) { static if (0 == Dimension!(L) - Dimension!(R)) { static if (1 == Dimension!(L)) alias ElementType!(L) MultiplyResultType; else alias L MultiplyResultType; } else static if (1 == Dimension!(L) - Dimension!(R)) { static if (0 == Dimension!(R)) alias L MultiplyResultType; else static if (1 == Dimension!(R)) alias R MultiplyResultType; } else static if (2 == Dimension!(L) - Dimension!(R)) { static if (0 == Dimension!(R)) alias L MultiplyResultType; } } MultiplyResultType!(L, R) multiply(L, R)(in L lhs, in R rhs) { static if (0 == Dimension!(L) - Dimension!(R)) { static if (0 == Dimension!(L)) return lhs * rhs; else static if (1 == Dimension!(L)) return vv_multiply!(ElementType!(R))(lhs, rhs); else static if (2 == Dimension!(L)) return mm_multiply!(ElementType!(ElementType!(R)))(lhs, rhs); else static assert(false, "not supported"); } else static if (1 == Dimension!(L) - Dimension!(R)) { static if (1 == Dimension!(L)) return vs_multiply!(R)(lhs, rhs); else static if (2 == Dimension!(L)) return mv_multiply!(ElementType!(R))(lhs, rhs); else static assert(false, "not supported"); } else static if (2 == Dimension!(L) - Dimension!(R)) { static if (2 == Dimension!(L)) return ms_multiply!(R)(lhs, rhs); else static assert(false, "not supported"); } } private T[] vs_multiply(T)(in T[] lhs, in T rhs) { T[] result = new T[lhs.length]; foreach (i; 0..lhs.length) { result[i] = multiply!(T, T)(lhs[i], rhs); } return result; } private T[] mv_multiply(T)(in T[][] lhs, in T[] rhs) in { assert(lhs[0].length == rhs.length); } body { T[] result = new T[lhs.length]; foreach (i; 0..lhs.length) { result[i] = multiply!(T[], T[])(lhs[i], rhs); } return result; } private T[][] ms_multiply(T)(in T[][] lhs, in T rhs) { T[][] result = new T[][lhs.length]; foreach (i; 0..lhs.length) { result[i] = multiply!(T[], T)(lhs[i], rhs); } return result; } private T vv_multiply(T)(in T[] lhs, in T[] rhs) in { static assert(is(typeof(lhs[0] + rhs[0]))); static assert(is(typeof(lhs[0] * rhs[0]))); assert(lhs.length == rhs.length); } body { T result; foreach (i; 0..lhs.length) { result = add!(T)(result, multiply!(T, T)(lhs[i], rhs[i])); } return result; } private T[][] mm_multiply(T)(in T[][] lhs, in T[][] rhs) in { static assert(is(typeof(lhs[0][0] + rhs[0][0]))); static assert(is(typeof(lhs[0][0] * rhs[0][0]))); assert(lhs[0].length == rhs.length); } body { T[][] result = new T[][lhs.length]; foreach (i; 0..lhs.length) { result[i] = new T[rhs[0].length]; foreach (j; 0..rhs[0].length) { foreach (k; 0..rhs.length) { result[i][j] = add!(T)(result[i][j], multiply!(T, T)(lhs[i][k], rhs[k][j])); } } } return result; }