ベクトル演算

を作ってみた。

加算は、演算後に次元が変わらないので、割と簡単。

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;
    }