def test_parsing_of_matrix_expressions(): expr = M * N assert parse_matrix_expression(expr) == CodegenArrayContraction( CodegenArrayTensorProduct(M, N), (1, 2)) expr = Transpose(M) assert parse_matrix_expression(expr) == CodegenArrayPermuteDims(M, [1, 0]) expr = M * Transpose(N) assert parse_matrix_expression(expr) == CodegenArrayContraction( CodegenArrayTensorProduct(M, CodegenArrayPermuteDims(N, [1, 0])), (1, 2)) expr = 3 * M * N res = parse_matrix_expression(expr) rexpr = recognize_matrix_expression(res) assert expr == rexpr expr = 3 * M + N * M.T * M + 4 * k * N res = parse_matrix_expression(expr) rexpr = recognize_matrix_expression(res) assert expr == rexpr expr = Inverse(M) * N rexpr = recognize_matrix_expression(parse_matrix_expression(expr)) assert expr == rexpr expr = M**2 rexpr = recognize_matrix_expression(parse_matrix_expression(expr)) assert expr == rexpr expr = M * (2 * N + 3 * M) res = parse_matrix_expression(expr) rexpr = recognize_matrix_expression(res) assert expr.expand() == rexpr.doit() expr = Trace(M) result = CodegenArrayContraction(M, (0, 1)) assert parse_matrix_expression(expr) == result
def test_codegen_extra(): if not np: skip("NumPy not installed") M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) P = MatrixSymbol("P", 2, 2) Q = MatrixSymbol("Q", 2, 2) ma = np.matrix([[1, 2], [3, 4]]) mb = np.matrix([[1,-2], [-1, 3]]) mc = np.matrix([[2, 0], [1, 2]]) md = np.matrix([[1,-1], [4, 7]]) cg = CodegenArrayTensorProduct(M, N) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == np.einsum(ma, [0, 1], mb, [2, 3])).all() cg = CodegenArrayElementwiseAdd(M, N) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == ma+mb).all() cg = CodegenArrayElementwiseAdd(M, N, P) f = lambdify((M, N, P), cg, 'numpy') assert (f(ma, mb, mc) == ma+mb+mc).all() cg = CodegenArrayElementwiseAdd(M, N, P, Q) f = lambdify((M, N, P, Q), cg, 'numpy') assert (f(ma, mb, mc, md) == ma+mb+mc+md).all() cg = CodegenArrayPermuteDims(M, [1, 0]) f = lambdify((M,), cg, 'numpy') assert (f(ma) == ma.T).all() cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [1, 2, 3, 0]) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == np.transpose(np.einsum(ma, [0, 1], mb, [2, 3]), (1, 2, 3, 0))).all() cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (1, 2)) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == np.diagonal(np.einsum(ma, [0, 1], mb, [2, 3]), axis1=1, axis2=2)).all()
def test_codegen_array_contraction_construction(): cg = CodegenArrayContraction(A) assert cg == A s = Sum(A[i] * B[i], (i, 0, 3)) cg = parse_indexed_expression(s) assert cg == CodegenArrayContraction(CodegenArrayTensorProduct(A, B), (0, 1)) cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, B), (1, 0)) assert cg == CodegenArrayContraction(CodegenArrayTensorProduct(A, B), (0, 1)) expr = M * N result = CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (1, 2)) assert parse_matrix_expression(expr) == result elem = expr[i, j] assert parse_indexed_expression(elem) == result expr = M * N * M result = CodegenArrayContraction(CodegenArrayTensorProduct(M, N, M), (1, 2), (3, 4)) assert parse_matrix_expression(expr) == result elem = expr[i, j] result = CodegenArrayContraction(CodegenArrayTensorProduct(M, M, N), (1, 4), (2, 5)) cg = parse_indexed_expression(elem) cg = cg.sort_args_by_name() assert cg == result
def tensorproduct(*args): """ Tensor product among scalars or array-like objects. Examples ======== >>> from sympy.tensor.array import tensorproduct, Array >>> from sympy.abc import x, y, z, t >>> A = Array([[1, 2], [3, 4]]) >>> B = Array([x, y]) >>> tensorproduct(A, B) [[[x, y], [2*x, 2*y]], [[3*x, 3*y], [4*x, 4*y]]] >>> tensorproduct(A, x) [[x, 2*x], [3*x, 4*x]] >>> tensorproduct(A, B, B) [[[[x**2, x*y], [x*y, y**2]], [[2*x**2, 2*x*y], [2*x*y, 2*y**2]]], [[[3*x**2, 3*x*y], [3*x*y, 3*y**2]], [[4*x**2, 4*x*y], [4*x*y, 4*y**2]]]] Applying this function on two matrices will result in a rank 4 array. >>> from sympy import Matrix, eye >>> m = Matrix([[x, y], [z, t]]) >>> p = tensorproduct(eye(3), m) >>> p [[[[x, y], [z, t]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[x, y], [z, t]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[x, y], [z, t]]]] """ from sympy.tensor.array import SparseNDimArray, ImmutableSparseNDimArray if len(args) == 0: return S.One if len(args) == 1: return _arrayfy(args[0]) from sympy.codegen.array_utils import _CodegenArrayAbstract, CodegenArrayTensorProduct from sympy.tensor.array.expressions.array_expressions import _ArrayExpr if any(isinstance(arg, (_ArrayExpr, _CodegenArrayAbstract)) for arg in args): return CodegenArrayTensorProduct(*args) if len(args) > 2: return tensorproduct(tensorproduct(args[0], args[1]), *args[2:]) # length of args is 2: a, b = map(_arrayfy, args) if not isinstance(a, NDimArray) or not isinstance(b, NDimArray): return a*b if isinstance(a, SparseNDimArray) and isinstance(b, SparseNDimArray): lp = len(b) new_array = {k1*lp + k2: v1*v2 for k1, v1 in a._sparse_array.items() for k2, v2 in b._sparse_array.items()} return ImmutableSparseNDimArray(new_array, a.shape + b.shape) product_list = [i*j for i in Flatten(a) for j in Flatten(b)] return ImmutableDenseNDimArray(product_list, a.shape + b.shape)
def test_codegen_array_shape(): expr = CodegenArrayTensorProduct(M, N, P, Q) assert expr.shape == (k, k, k, k, k, k, k, k) Z = MatrixSymbol("Z", m, n) expr = CodegenArrayTensorProduct(M, Z) assert expr.shape == (k, k, m, n) expr2 = CodegenArrayContraction(expr, (0, 1)) assert expr2.shape == (m, n) expr2 = CodegenArrayDiagonal(expr, (0, 1)) assert expr2.shape == (m, n, k) exprp = CodegenArrayPermuteDims(expr, [2, 1, 3, 0]) assert exprp.shape == (m, k, n, k) expr3 = CodegenArrayTensorProduct(N, Z) expr2 = CodegenArrayElementwiseAdd(expr, expr3) assert expr2.shape == (k, k, m, n) # Contraction along axes with discordant dimensions: raises(ValueError, lambda: CodegenArrayContraction(expr, (1, 2))) # Also diagonal needs the same dimensions: raises(ValueError, lambda: CodegenArrayDiagonal(expr, (1, 2))) # Diagonal requires at least to axes to compute the diagonal: raises(ValueError, lambda: CodegenArrayDiagonal(expr, (1,)))
def test_nested_array_elementwise_add(): cg = CodegenArrayContraction( CodegenArrayElementwiseAdd(CodegenArrayTensorProduct(M, N), CodegenArrayTensorProduct(N, M)), (1, 2)) result = CodegenArrayElementwiseAdd( CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (1, 2)), CodegenArrayContraction(CodegenArrayTensorProduct(N, M), (1, 2))) assert cg == result cg = CodegenArrayDiagonal( CodegenArrayElementwiseAdd(CodegenArrayTensorProduct(M, N), CodegenArrayTensorProduct(N, M)), (1, 2)) result = CodegenArrayElementwiseAdd( CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (1, 2)), CodegenArrayDiagonal(CodegenArrayTensorProduct(N, M), (1, 2))) assert cg == result
def test_permute_tensor_product(): cg1 = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N, P, Q), Permutation([2, 3, 1, 0, 5, 4, 6, 7])) cg2 = CodegenArrayTensorProduct(N, CodegenArrayPermuteDims(M, [1, 0]), CodegenArrayPermuteDims(P, [1, 0]), Q) assert cg1 == cg2 # TODO: reverse operation starting with `CodegenArrayPermuteDims` and getting down to `bb`... cg1 = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N, P, Q), Permutation([2, 3, 4, 5, 0, 1, 6, 7])) cg2 = CodegenArrayTensorProduct(N, P, M, Q) assert cg1 == cg2 cg1 = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N, P, Q), Permutation([2, 3, 4, 6, 5, 7, 0, 1])) assert cg1.expr == CodegenArrayTensorProduct(N, P, Q, M) assert cg1.permutation == Permutation([0, 1, 2, 4, 3, 5, 6, 7]) cg1 = CodegenArrayContraction( CodegenArrayPermuteDims(CodegenArrayTensorProduct(N, Q, Q, M), [2, 1, 5, 4, 0, 3, 6, 7]), [1, 2, 6]) cg2 = CodegenArrayPermuteDims( CodegenArrayContraction(CodegenArrayTensorProduct(Q, Q, N, M), (3, 5, 6)), [0, 2, 3, 1, 4]) assert cg1 == cg2 cg1 = CodegenArrayContraction( CodegenArrayContraction( CodegenArrayContraction( CodegenArrayContraction( CodegenArrayPermuteDims( CodegenArrayTensorProduct(N, Q, Q, M), [2, 1, 5, 4, 0, 3, 6, 7]), [1, 2, 6]), [1, 3, 4]), [1]), [0]) cg2 = CodegenArrayContraction(CodegenArrayTensorProduct(M, N, Q, Q), (0, 3, 5), (1, 4, 7), (2, ), (6, )) assert cg1 == cg2
def test_array_expr_zero_array(): za1 = ZeroArray(k, l, m, n) zm1 = ZeroMatrix(m, n) za2 = ZeroArray(k, m, m, n) zm2 = ZeroMatrix(m, m) zm3 = ZeroMatrix(k, k) assert CodegenArrayTensorProduct(M, N, za1) == ZeroArray(k, k, k, k, k, l, m, n) assert CodegenArrayTensorProduct(M, N, zm1) == ZeroArray(k, k, k, k, m, n) assert CodegenArrayContraction(za1, (3, )) == ZeroArray(k, l, m) assert CodegenArrayContraction(zm1, (1, )) == ZeroArray(m) assert CodegenArrayContraction(za2, (1, 2)) == ZeroArray(k, n) assert CodegenArrayContraction(zm2, (0, 1)) == 0 assert CodegenArrayDiagonal(za2, (1, 2)) == ZeroArray(k, n, m) assert CodegenArrayDiagonal(zm2, (0, 1)) == ZeroArray(m) assert CodegenArrayPermuteDims(za1, [2, 1, 3, 0]) == ZeroArray(m, l, n, k) assert CodegenArrayPermuteDims(zm1, [1, 0]) == ZeroArray(n, m) assert CodegenArrayElementwiseAdd(za1) == za1 assert CodegenArrayElementwiseAdd(zm1) == ZeroArray(m, n) tp1 = CodegenArrayTensorProduct(MatrixSymbol("A", k, l), MatrixSymbol("B", m, n)) assert CodegenArrayElementwiseAdd(tp1, za1) == tp1 tp2 = CodegenArrayTensorProduct(MatrixSymbol("C", k, l), MatrixSymbol("D", m, n)) assert CodegenArrayElementwiseAdd(tp1, za1, tp2) == CodegenArrayElementwiseAdd( tp1, tp2) assert CodegenArrayElementwiseAdd(M, zm3) == M assert CodegenArrayElementwiseAdd(M, N, zm3) == CodegenArrayElementwiseAdd(M, N)
def test_codegen_array_parse(): expr = M[i, j] assert _codegen_array_parse(expr) == (M, (i, j)) expr = M[i, j]*N[k, l] assert _codegen_array_parse(expr) == (CodegenArrayTensorProduct(M, N), (i, j, k, l)) expr = M[i, j]*N[j, k] assert _codegen_array_parse(expr) == (CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (1, 2)), (i, k, j)) expr = Sum(M[i, j]*N[j, k], (j, 0, k-1)) assert _codegen_array_parse(expr) == (CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (1, 2)), (i, k)) expr = M[i, j] + N[i, j] assert _codegen_array_parse(expr) == (CodegenArrayElementwiseAdd(M, N), (i, j)) expr = M[i, j] + N[j, i] assert _codegen_array_parse(expr) == (CodegenArrayElementwiseAdd(M, CodegenArrayPermuteDims(N, Permutation([1,0]))), (i, j)) expr = M[i, j] + M[j, i] assert _codegen_array_parse(expr) == (CodegenArrayElementwiseAdd(M, CodegenArrayPermuteDims(M, Permutation([1,0]))), (i, j)) expr = (M*N*P)[i, j] assert _codegen_array_parse(expr) == (CodegenArrayContraction(CodegenArrayTensorProduct(M, N, P), (1, 2), (3, 4)), (i, j)) expr = expr.function # Disregard summation in previous expression ret1, ret2 = _codegen_array_parse(expr) assert ret1 == CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N, P), (1, 2), (3, 4)) assert str(ret2) == "(i, j, _i_1, _i_2)" expr = KroneckerDelta(i, j)*M[i, k] assert _codegen_array_parse(expr) == (M, ({i, j}, k)) expr = KroneckerDelta(i, j)*KroneckerDelta(j, k)*M[i, l] assert _codegen_array_parse(expr) == (M, ({i, j, k}, l)) expr = KroneckerDelta(j, k)*(M[i, j]*N[k, l] + N[i, j]*M[k, l]) assert _codegen_array_parse(expr) == (CodegenArrayDiagonal(CodegenArrayElementwiseAdd( CodegenArrayTensorProduct(M, N), CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), Permutation(0, 2)(1, 3)) ), (1, 2)), (i, l, frozenset({j, k}))) expr = KroneckerDelta(j, m)*KroneckerDelta(m, k)*(M[i, j]*N[k, l] + N[i, j]*M[k, l]) assert _codegen_array_parse(expr) == (CodegenArrayDiagonal(CodegenArrayElementwiseAdd( CodegenArrayTensorProduct(M, N), CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), Permutation(0, 2)(1, 3)) ), (1, 2)), (i, l, frozenset({j, m, k}))) expr = KroneckerDelta(i, j)*KroneckerDelta(j, k)*KroneckerDelta(k,m)*M[i, 0]*KroneckerDelta(m, n) assert _codegen_array_parse(expr) == (M, ({i,j,k,m,n}, 0)) expr = M[i, i] assert _codegen_array_parse(expr) == (CodegenArrayDiagonal(M, (0, 1)), (i,))
def test_codegen_array_doit(): M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) P = MatrixSymbol("P", 2, 2) Q = MatrixSymbol("Q", 2, 2) M = M.as_explicit() N = N.as_explicit() P = P.as_explicit() Q = Q.as_explicit() expr = CodegenArrayTensorProduct(M, N, P, Q) assert expr.doit() == tensorproduct(M, N, P, Q) expr2 = CodegenArrayContraction(expr, (0, 1)) assert expr2.doit() == tensorcontraction(tensorproduct(M, N, P, Q), (0, 1)) expr2 = CodegenArrayDiagonal(expr, (0, 1)) #assert expr2 = ... # TODO: not implemented expr = CodegenArrayTensorProduct(M, N) exprp = CodegenArrayPermuteDims(expr, [2, 1, 3, 0]) assert exprp.doit() == permutedims(tensorproduct(M, N), [2, 1, 3, 0]) expr = CodegenArrayElementwiseAdd(M, N) assert expr.doit() == M + N
def test_diag2contraction_diagmatrix(): cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, a), (1, 2)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction(CodegenArrayTensorProduct(M, OneArray(1), DiagMatrix(a)), (1, 3)) raises(ValueError, lambda: CodegenArrayDiagonal(CodegenArrayTensorProduct(a, M), (1, 2))) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a.T, M), (1, 2)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction(CodegenArrayTensorProduct(OneArray(1), M, DiagMatrix(a.T)), (1, 4)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a.T, M, N, b.T), (1, 2), (4, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a.T), DiagMatrix(b.T)), (1, 7), (3, 9)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a, M, N, b.T), (0, 2), (4, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a), DiagMatrix(b.T)), (1, 6), (3, 9)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a, M, N, b.T), (0, 4), (3, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a), DiagMatrix(b.T)), (3, 6), (2, 9))
def test_remove_trivial_dims(): # Tensor Product: assert _remove_trivial_dims(CodegenArrayTensorProduct(a, b)) == (a * b.T, [1, 3]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a.T, b)) == (a * b.T, [0, 3]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a, b.T)) == (a * b.T, [1, 2]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a.T, b.T)) == (a * b.T, [0, 2]) assert _remove_trivial_dims(CodegenArrayTensorProduct(I, a.T, b.T)) == (a * b.T, [0, 1, 2, 4]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a.T, I, b.T)) == (a * b.T, [0, 2, 3, 4]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a, I)) == (a, [2, 3]) assert _remove_trivial_dims(CodegenArrayTensorProduct(I, a)) == (a, [0, 1]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a.T, b.T, c, d)) == ( CodegenArrayTensorProduct(a * b.T, c * d.T), [0, 2, 5, 7]) assert _remove_trivial_dims(CodegenArrayTensorProduct(a.T, I, b.T, c, d, I)) == ( CodegenArrayTensorProduct(a * b.T, c * d.T, I), [0, 2, 3, 4, 7, 9]) # Addition: cg = CodegenArrayElementwiseAdd(CodegenArrayTensorProduct(a, b), CodegenArrayTensorProduct(c, d)) assert _remove_trivial_dims(cg) == (a * b.T + c * d.T, [1, 3]) # Permute Dims: cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(a, b), Permutation(3)(1, 2)) assert _remove_trivial_dims(cg) == (a * b.T, [2, 3]) cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(a, I, b), Permutation(5)(1, 2, 3, 4)) assert _remove_trivial_dims(cg) == (a * b.T, [2, 3, 4, 5]) cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(I, b, a), Permutation(5)(1, 2, 4, 5, 3)) assert _remove_trivial_dims(cg) == (b * a.T, [0, 1, 2, 3]) # Diagonal: cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, a), (1, 2)) assert _remove_trivial_dims(cg) == (cg, []) # Contraction: cg = CodegenArrayContraction(CodegenArrayTensorProduct(M, a), (1, 2)) assert _remove_trivial_dims(cg) == (cg, [])
def test_array_wrong_permutation_size(): cg = CodegenArrayTensorProduct(M, N) raises(ValueError, lambda: CodegenArrayPermuteDims(cg, [1, 0])) raises(ValueError, lambda: CodegenArrayPermuteDims(cg, [1, 0, 2, 3, 5, 4]))
def test_contraction_permutation_mix(): Me = M.subs(k, 3).as_explicit() Ne = N.subs(k, 3).as_explicit() cg1 = CodegenArrayContraction(CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), Permutation([0, 2, 1, 3])), (2, 3)) cg2 = CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (1, 3)) assert cg1 == cg2 assert recognize_matrix_expression(cg2) == M*N.T cge1 = tensorcontraction(permutedims(tensorproduct(Me, Ne), Permutation([0, 2, 1, 3])), (2, 3)) cge2 = tensorcontraction(tensorproduct(Me, Ne), (1, 3)) assert cge1 == cge2 cg1 = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), Permutation([0, 1, 3, 2])) cg2 = CodegenArrayTensorProduct(M, CodegenArrayPermuteDims(N, Permutation([1, 0]))) assert cg1 == cg2 assert recognize_matrix_expression(cg1) == CodegenArrayTensorProduct(M, N.T) assert recognize_matrix_expression(cg2) == CodegenArrayTensorProduct(M, N.T) cg1 = CodegenArrayContraction( CodegenArrayPermuteDims( CodegenArrayTensorProduct(M, N, P, Q), Permutation([0, 2, 3, 1, 4, 5, 7, 6])), (1, 2), (3, 5) ) cg2 = CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, CodegenArrayPermuteDims(Q, Permutation([1, 0]))), (1, 5), (2, 3) ) assert cg1 == cg2 assert recognize_matrix_expression(cg1) == CodegenArrayTensorProduct(M*P.T*Trace(N), Q.T) assert recognize_matrix_expression(cg2) == CodegenArrayTensorProduct(M*P.T*Trace(N), Q.T) cg1 = CodegenArrayContraction( CodegenArrayPermuteDims( CodegenArrayTensorProduct(M, N, P, Q), Permutation([1, 0, 4, 6, 2, 7, 5, 3])), (0, 1), (2, 6), (3, 7) ) cg2 = CodegenArrayPermuteDims( CodegenArrayContraction( CodegenArrayTensorProduct(M, P, Q, N), (0, 1), (2, 3), (4, 7)), [1, 0] ) assert cg1 == cg2 cg1 = CodegenArrayContraction( CodegenArrayPermuteDims( CodegenArrayTensorProduct(M, N, P, Q), Permutation([1, 0, 4, 6, 7, 2, 5, 3])), (0, 1), (2, 6), (3, 7) ) cg2 = CodegenArrayPermuteDims( CodegenArrayContraction( CodegenArrayTensorProduct(CodegenArrayPermuteDims(M, [1, 0]), N, P, Q), (0, 1), (3, 6), (4, 5) ), Permutation([1, 0]) ) assert cg1 == cg2
def test_parsing_of_matrix_expressions(): expr = M*N assert parse_matrix_expression(expr) == CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (1, 2)) expr = Transpose(M) assert parse_matrix_expression(expr) == CodegenArrayPermuteDims(M, [1, 0]) expr = M*Transpose(N) assert parse_matrix_expression(expr) == CodegenArrayContraction(CodegenArrayTensorProduct(M, CodegenArrayPermuteDims(N, [1, 0])), (1, 2)) expr = 3*M*N res = parse_matrix_expression(expr) rexpr = recognize_matrix_expression(res) assert expr == rexpr expr = 3*M + N*M.T*M + 4*k*N res = parse_matrix_expression(expr) rexpr = recognize_matrix_expression(res) assert expr == rexpr expr = Inverse(M)*N rexpr = recognize_matrix_expression(parse_matrix_expression(expr)) assert expr == rexpr expr = M**2 rexpr = recognize_matrix_expression(parse_matrix_expression(expr)) assert expr == rexpr expr = M*(2*N + 3*M) res = parse_matrix_expression(expr) rexpr = recognize_matrix_expression(res) assert expr == rexpr expr = Trace(M) result = CodegenArrayContraction(M, (0, 1)) assert parse_matrix_expression(expr) == result expr = 3*Trace(M) result = CodegenArrayContraction(CodegenArrayTensorProduct(3, M), (0, 1)) assert parse_matrix_expression(expr) == result expr = 3*Trace(Trace(M) * M) result = CodegenArrayContraction(CodegenArrayTensorProduct(3, M, M), (0, 1), (2, 3)) assert parse_matrix_expression(expr) == result expr = 3*Trace(M)**2 result = CodegenArrayContraction(CodegenArrayTensorProduct(3, M, M), (0, 1), (2, 3)) assert parse_matrix_expression(expr) == result expr = HadamardProduct(M, N) result = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (0, 2), (1, 3)) assert parse_matrix_expression(expr) == result expr = HadamardPower(M, 2) result = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, M), (0, 2), (1, 3)) assert parse_matrix_expression(expr) == result expr = M**2 assert isinstance(expr, MatPow) assert parse_matrix_expression(expr) == CodegenArrayContraction(CodegenArrayTensorProduct(M, M), (1, 2))
def _(expr: MatrixSymbol, x: Expr): m, n = expr.shape if expr == x: return CodegenArrayPermuteDims( CodegenArrayTensorProduct(Identity(m), Identity(n)), [0, 2, 1, 3]) return ZeroArray(*(x.shape + expr.shape))
def test_codegen_array_diagonal(): cg = CodegenArrayDiagonal(M, (1, 0)) assert cg == CodegenArrayDiagonal(M, (0, 1)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N, P), (4, 1), (2, 0)) assert cg == CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N, P), (1, 4), (0, 2))
def test_recognize_diagonalized_vectors(): a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) X = MatrixSymbol("X", k, k) x = MatrixSymbol("x", k, 1) I1 = Identity(1) I = Identity(k) # Check matrix recognition over trivial dimensions: cg = CodegenArrayTensorProduct(a, b) assert recognize_matrix_expression(cg) == a*b.T cg = CodegenArrayTensorProduct(I1, a, b) assert recognize_matrix_expression(cg) == a*I1*b.T # Recognize trace inside a tensor product: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, B, C), (0, 3), (1, 2)) assert recognize_matrix_expression(cg) == Trace(A*B)*C # Transform diagonal operator to contraction: cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(A, a), (1, 2)) assert cg.transform_to_product() == CodegenArrayContraction(CodegenArrayTensorProduct(A, DiagonalizeVector(a)), (1, 2)) assert recognize_matrix_expression(cg) == A*DiagonalizeVector(a) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a, b), (0, 2)) assert cg.transform_to_product() == CodegenArrayContraction(CodegenArrayTensorProduct(DiagonalizeVector(a), b), (0, 2)) assert recognize_matrix_expression(cg).doit() == DiagonalizeVector(a)*b cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(A, a), (0, 2)) assert cg.transform_to_product() == CodegenArrayContraction(CodegenArrayTensorProduct(A, DiagonalizeVector(a)), (0, 2)) assert recognize_matrix_expression(cg) == A.T*DiagonalizeVector(a) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(I, x, I1), (0, 2), (3, 5)) assert cg.transform_to_product() == CodegenArrayContraction(CodegenArrayTensorProduct(I, DiagonalizeVector(x), I1), (0, 2)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(I, x, A, B), (1, 2), (5, 6)) assert cg.transform_to_product() == CodegenArrayDiagonal(CodegenArrayContraction(CodegenArrayTensorProduct(I, DiagonalizeVector(x), A, B), (1, 2)), (3, 4)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(x, I1), (1, 2)) assert isinstance(cg, CodegenArrayDiagonal) assert cg.diagonal_indices == ((1, 2),) assert recognize_matrix_expression(cg) == x cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(x, I), (0, 2)) assert cg.transform_to_product() == CodegenArrayContraction(CodegenArrayTensorProduct(DiagonalizeVector(x), I), (0, 2)) assert recognize_matrix_expression(cg).doit() == DiagonalizeVector(x) cg = CodegenArrayDiagonal(x, (1,)) assert cg == x # Ignore identity matrices with contractions: cg = CodegenArrayContraction(CodegenArrayTensorProduct(I, A, I, I), (0, 2), (1, 3), (5, 7)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg) == Trace(A)*I cg = CodegenArrayContraction(CodegenArrayTensorProduct(Trace(A) * I, I, I), (1, 5), (3, 4)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg).doit() == Trace(A)*I # Add DiagonalizeVector when required: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a), (1, 2)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg) == A*a cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, B), (1, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction(CodegenArrayTensorProduct(A, DiagonalizeVector(a), B), (1, 2), (3, 4)) assert recognize_matrix_expression(cg) == A*DiagonalizeVector(a)*B cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, B), (0, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction(CodegenArrayTensorProduct(A, DiagonalizeVector(a), B), (0, 2), (3, 4)) assert recognize_matrix_expression(cg) == A.T*DiagonalizeVector(a)*B cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, b, a.T, B), (0, 2, 4, 7, 9)) assert cg.split_multiple_contractions() == CodegenArrayContraction(CodegenArrayTensorProduct(A, DiagonalizeVector(a), DiagonalizeVector(b), DiagonalizeVector(a), B), (0, 2), (3, 4), (5, 7), (6, 9)) assert recognize_matrix_expression(cg).doit() == A.T*DiagonalizeVector(a)*DiagonalizeVector(b)*DiagonalizeVector(a)*B.T cg = CodegenArrayContraction(CodegenArrayTensorProduct(I1, I1, I1), (1, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction(CodegenArrayTensorProduct(I1, I1, I1), (1, 2), (3, 4)) assert recognize_matrix_expression(cg).doit() == Identity(1) cg = CodegenArrayContraction(CodegenArrayTensorProduct(I, I, I, I, A), (1, 2, 8), (5, 6, 9)) assert recognize_matrix_expression(cg.split_multiple_contractions()).doit() == A cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8)) assert cg.split_multiple_contractions() == CodegenArrayContraction(CodegenArrayTensorProduct(A, DiagonalizeVector(a), C, DiagonalizeVector(a), B), (1, 2), (3, 4), (5, 6), (7, 8)) assert recognize_matrix_expression(cg) == A*DiagonalizeVector(a)*C*DiagonalizeVector(a)*B cg = CodegenArrayContraction(CodegenArrayTensorProduct(a, I1, b, I1, (a.T*b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions() == CodegenArrayContraction(CodegenArrayTensorProduct(a, I1, b, I1, (a.T*b).applyfunc(cos)), (1, 2), (3, 8), (5, 6), (7, 9)) assert recognize_matrix_expression(cg) == MatMul(a, I1, (a.T*b).applyfunc(cos), Transpose(I1), b.T) cg = CodegenArrayContraction(CodegenArrayTensorProduct(A.T, a, b, b.T, (A*X*b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A.T, DiagonalizeVector(a), b, b.T, (A*X*b).applyfunc(cos)), (1, 2), (3, 8), (5, 6, 9)) # assert recognize_matrix_expression(cg) # Check no overlap of lines: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8), (3, 7)) assert cg.split_multiple_contractions() == cg cg = CodegenArrayContraction(CodegenArrayTensorProduct(a, b, A), (0, 2, 4), (1, 3)) assert cg.split_multiple_contractions() == cg
def test_codegen_array_flatten(): # Flatten nested CodegenArrayTensorProduct objects: expr1 = CodegenArrayTensorProduct(M, N) expr2 = CodegenArrayTensorProduct(P, Q) expr = CodegenArrayTensorProduct(expr1, expr2) assert expr == CodegenArrayTensorProduct(M, N, P, Q) assert expr.args == (M, N, P, Q) # Flatten mixed CodegenArrayTensorProduct and CodegenArrayContraction objects: cg1 = CodegenArrayContraction(expr1, (1, 2)) cg2 = CodegenArrayContraction(expr2, (0, 3)) expr = CodegenArrayTensorProduct(cg1, cg2) assert expr == CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, Q), (1, 2), (4, 7)) expr = CodegenArrayTensorProduct(M, cg1) assert expr == CodegenArrayContraction(CodegenArrayTensorProduct(M, M, N), (3, 4)) # Flatten nested CodegenArrayContraction objects: cgnested = CodegenArrayContraction(cg1, (0, 1)) assert cgnested == CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (0, 3), (1, 2)) cgnested = CodegenArrayContraction(CodegenArrayTensorProduct(cg1, cg2), (0, 3)) assert cgnested == CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, Q), (0, 6), (1, 2), (4, 7)) cg3 = CodegenArrayContraction(CodegenArrayTensorProduct(M, N, P, Q), (1, 3), (2, 4)) cgnested = CodegenArrayContraction(cg3, (0, 1)) assert cgnested == CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, Q), (0, 5), (1, 3), (2, 4)) cgnested = CodegenArrayContraction(cg3, (0, 3), (1, 2)) assert cgnested == CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, Q), (0, 7), (1, 3), (2, 4), (5, 6)) cg4 = CodegenArrayContraction(CodegenArrayTensorProduct(M, N, P, Q), (1, 5), (3, 7)) cgnested = CodegenArrayContraction(cg4, (0, 1)) assert cgnested == CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, Q), (0, 2), (1, 5), (3, 7)) cgnested = CodegenArrayContraction(cg4, (0, 1), (2, 3)) assert cgnested == CodegenArrayContraction( CodegenArrayTensorProduct(M, N, P, Q), (0, 2), (1, 5), (3, 7), (4, 6)) cg = CodegenArrayDiagonal(cg4) assert cg == cg4 assert isinstance(cg, type(cg4)) # Flatten nested CodegenArrayDiagonal objects: cg1 = CodegenArrayDiagonal(expr1, (1, 2)) cg2 = CodegenArrayDiagonal(expr2, (0, 3)) cg3 = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N, P, Q), (1, 3), (2, 4)) cg4 = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N, P, Q), (1, 5), (3, 7)) cgnested = CodegenArrayDiagonal(cg1, (0, 1)) assert cgnested == CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (1, 2), (0, 3)) cgnested = CodegenArrayDiagonal(cg3, (1, 2)) assert cgnested == CodegenArrayDiagonal( CodegenArrayTensorProduct(M, N, P, Q), (1, 3), (2, 4), (5, 6)) cgnested = CodegenArrayDiagonal(cg4, (1, 2)) assert cgnested == CodegenArrayDiagonal( CodegenArrayTensorProduct(M, N, P, Q), (1, 5), (3, 7), (2, 4))
def test_recognize_diagonalized_vectors(): a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a), (1, 2)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg) == A * a cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, B), (1, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagonalizeVector(a), B), (1, 2), (3, 4)) assert recognize_matrix_expression(cg) == A * DiagonalizeVector(a) * B cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, B), (0, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagonalizeVector(a), B), (0, 2), (3, 4)) assert recognize_matrix_expression(cg) == A.T * DiagonalizeVector(a) * B cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, b, a.T, B), (0, 2, 4, 7, 9)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagonalizeVector(a), DiagonalizeVector(b), DiagonalizeVector(a), B), (0, 2), (3, 4), (5, 7), (6, 9)) assert recognize_matrix_expression(cg).doit() == A.T * DiagonalizeVector( a) * DiagonalizeVector(b) * DiagonalizeVector(a) * B.T I1 = Identity(1) cg = CodegenArrayContraction(CodegenArrayTensorProduct(I1, I1, I1), (1, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(I1, I1, I1), (1, 2), (3, 4)) assert recognize_matrix_expression(cg).doit() == Identity(1) I = Identity(k) cg = CodegenArrayContraction(CodegenArrayTensorProduct(I, I, I, I, A), (1, 2, 8), (5, 6, 9)) assert recognize_matrix_expression( cg.split_multiple_contractions()).doit() == A cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagonalizeVector(a), C, DiagonalizeVector(a), B), (1, 2), (3, 4), (5, 6), (7, 8)) assert recognize_matrix_expression( cg) == A * DiagonalizeVector(a) * C * DiagonalizeVector(a) * B cg = CodegenArrayContraction( CodegenArrayTensorProduct(a, I1, b, I1, (a.T * b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(a, I1, b, I1, (a.T * b).applyfunc(cos)), (1, 2), (3, 8), (5, 6), (7, 9)) assert recognize_matrix_expression(cg) == MatMul(a, I1, (a.T * b).applyfunc(cos), Transpose(I1), b.T) # Check no overlap of lines: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8), (3, 7)) raises(ValueError, lambda: cg.split_multiple_contractions()) cg = CodegenArrayContraction(CodegenArrayTensorProduct(a, b, A), (0, 2, 4), (1, 3)) raises(ValueError, lambda: cg.split_multiple_contractions())
def test_diag2contraction_diagmatrix(): cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, a), (1, 2)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(M, OneArray(1), DiagMatrix(a)), (1, 3)) raises( ValueError, lambda: CodegenArrayDiagonal(CodegenArrayTensorProduct(a, M), (1, 2))) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a.T, M), (1, 2)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, DiagMatrix(a.T)), (1, 4)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a.T, M, N, b.T), (1, 2), (4, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a.T), DiagMatrix(b.T)), (1, 7), (3, 9)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a, M, N, b.T), (0, 2), (4, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a), DiagMatrix(b.T)), (1, 6), (3, 9)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a, M, N, b.T), (0, 4), (3, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == CodegenArrayContraction( CodegenArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a), DiagMatrix(b.T)), (3, 6), (2, 9)) I1 = Identity(1) x = MatrixSymbol("x", k, 1) A = MatrixSymbol("A", k, k) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(x, A.T, I1), (0, 2)) assert _array_diag2contr_diagmatrix(cg).shape == cg.shape assert array2matrix(cg).shape == cg.shape
def test_recognize_products_support_function(): A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) D = MatrixSymbol("D", k, k) X = MatrixSymbol("X", k, k) Y = MatrixSymbol("Y", k, k) assert _support_function_tp1_recognize([], [2 * k]) == 2 * k assert _support_function_tp1_recognize([(1, 2)], [A, 2 * k, B, 3]) == 6 * k * A * B assert _support_function_tp1_recognize([(0, 3), (1, 2)], [A, B]) == Trace(A * B) assert _support_function_tp1_recognize([(1, 2)], [A, B]) == A * B assert _support_function_tp1_recognize([(0, 2)], [A, B]) == A.T * B assert _support_function_tp1_recognize([(1, 3)], [A, B]) == A * B.T assert _support_function_tp1_recognize([(0, 3)], [A, B]) == A.T * B.T assert _support_function_tp1_recognize( [(1, 2), (5, 6)], [A, B, C, D]) == CodegenArrayTensorProduct(A * B, C * D) assert _support_function_tp1_recognize( [(1, 4), (3, 6)], [A, B, C, D]) == CodegenArrayPermuteDims( CodegenArrayTensorProduct(A * C, B * D), [0, 2, 1, 3]) assert _support_function_tp1_recognize([(0, 3), (1, 4)], [A, B, C]) == B * A * C assert _support_function_tp1_recognize( [(9, 10), (1, 2), (5, 6), (3, 4), (7, 8)], [X, Y, A, B, C, D]) == X * Y * A * B * C * D assert _support_function_tp1_recognize( [(9, 10), (1, 2), (5, 6), (3, 4)], [X, Y, A, B, C, D]) == CodegenArrayTensorProduct(X * Y * A * B, C * D) assert _support_function_tp1_recognize( [(1, 7), (3, 8), (4, 11)], [X, Y, A, B, C, D]) == CodegenArrayPermuteDims( CodegenArrayTensorProduct(X * B.T, Y * C, D * A), [0, 2, 5, 1, 3, 4]) assert _support_function_tp1_recognize( [(0, 1), (3, 6), (5, 8)], [X, A, B, C, D]) == CodegenArrayPermuteDims( CodegenArrayTensorProduct(Trace(X) * A * C, B * D), [0, 2, 1, 3]) assert _support_function_tp1_recognize([(1, 2), (3, 4), (5, 6), (7, 8)], [A, A, B, C, D]) == A**2 * B * C * D assert _support_function_tp1_recognize( [(1, 2), (3, 4), (5, 6), (7, 8)], [X, A, B, C, D]) == X * A * B * C * D assert _support_function_tp1_recognize( [(1, 6), (3, 8), (5, 10)], [X, Y, A, B, C, D]) == CodegenArrayPermuteDims( CodegenArrayTensorProduct(X * B, Y * C, A * D), [0, 2, 4, 1, 3, 5]) assert _support_function_tp1_recognize( [(1, 4), (3, 6)], [A, B, C, D]) == CodegenArrayPermuteDims( CodegenArrayTensorProduct(A * C, B * D), [0, 2, 1, 3]) assert _support_function_tp1_recognize( [(0, 4), (1, 7), (2, 5), (3, 8)], [X, A, B, C, D]) == C * X.T * B * A * D assert _support_function_tp1_recognize( [(0, 4), (1, 7), (2, 5), (3, 8)], [X, A, B, C, D]) == C * X.T * B * A * D
def test_codegen_permutedims_sink(): cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [0, 1, 3, 2]) sunk = cg.nest_permutation() assert sunk == CodegenArrayTensorProduct( M, CodegenArrayPermuteDims(N, [1, 0])) assert recognize_matrix_expression(sunk) == [M, N.T] cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [1, 0, 3, 2]) sunk = cg.nest_permutation() assert sunk == CodegenArrayTensorProduct( CodegenArrayPermuteDims(M, [1, 0]), CodegenArrayPermuteDims(N, [1, 0])) assert recognize_matrix_expression(sunk) == [M.T, N.T] cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [3, 2, 1, 0]) sunk = cg.nest_permutation() assert sunk == CodegenArrayTensorProduct( CodegenArrayPermuteDims(N, [1, 0]), CodegenArrayPermuteDims(M, [1, 0])) assert recognize_matrix_expression(sunk) == [N.T, M.T] cg = CodegenArrayPermuteDims( CodegenArrayContraction(CodegenArrayTensorProduct(M, N), (1, 2)), [1, 0]) sunk = cg.nest_permutation() assert sunk == CodegenArrayContraction( CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [[0, 3]]), (1, 2)) cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [1, 0, 3, 2]) sunk = cg.nest_permutation() assert sunk == CodegenArrayTensorProduct( CodegenArrayPermuteDims(M, [1, 0]), CodegenArrayPermuteDims(N, [1, 0])) cg = CodegenArrayPermuteDims( CodegenArrayContraction(CodegenArrayTensorProduct(M, N, P), (1, 2), (3, 4)), [1, 0]) sunk = cg.nest_permutation() assert sunk == CodegenArrayContraction( CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N, P), [[0, 5]]), (1, 2), (3, 4))
def test_codegen_extra(): if not tf: skip("TensorFlow not installed") graph = tf.Graph() with graph.as_default(): session = tf.compat.v1.Session() M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) P = MatrixSymbol("P", 2, 2) Q = MatrixSymbol("Q", 2, 2) ma = tf.constant([[1, 2], [3, 4]]) mb = tf.constant([[1, -2], [-1, 3]]) mc = tf.constant([[2, 0], [1, 2]]) md = tf.constant([[1, -1], [4, 7]]) cg = CodegenArrayTensorProduct(M, N) assert tensorflow_code(cg) == \ 'tensorflow.linalg.einsum("ab,cd", M, N)' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(tf.einsum("ij,kl", ma, mb)) assert (y == c).all() cg = CodegenArrayElementwiseAdd(M, N) assert tensorflow_code(cg) == 'tensorflow.math.add(M, N)' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(ma + mb) assert (y == c).all() cg = CodegenArrayElementwiseAdd(M, N, P) assert tensorflow_code(cg) == \ 'tensorflow.math.add(tensorflow.math.add(M, N), P)' f = lambdify((M, N, P), cg, 'tensorflow') y = session.run(f(ma, mb, mc)) c = session.run(ma + mb + mc) assert (y == c).all() cg = CodegenArrayElementwiseAdd(M, N, P, Q) assert tensorflow_code(cg) == \ 'tensorflow.math.add(' \ 'tensorflow.math.add(tensorflow.math.add(M, N), P), Q)' f = lambdify((M, N, P, Q), cg, 'tensorflow') y = session.run(f(ma, mb, mc, md)) c = session.run(ma + mb + mc + md) assert (y == c).all() cg = CodegenArrayPermuteDims(M, [1, 0]) assert tensorflow_code(cg) == 'tensorflow.transpose(M, [1, 0])' f = lambdify((M, ), cg, 'tensorflow') y = session.run(f(ma)) c = session.run(tf.transpose(ma)) assert (y == c).all() cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [1, 2, 3, 0]) assert tensorflow_code(cg) == \ 'tensorflow.transpose(' \ 'tensorflow.linalg.einsum("ab,cd", M, N), [1, 2, 3, 0])' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(tf.transpose(tf.einsum("ab,cd", ma, mb), [1, 2, 3, 0])) assert (y == c).all() cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (1, 2)) assert tensorflow_code(cg) == \ 'tensorflow.linalg.einsum("ab,bc->acb", M, N)' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(tf.einsum("ab,bc->acb", ma, mb)) assert (y == c).all()
def test_recognize_diagonalized_vectors(): a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) X = MatrixSymbol("X", k, k) x = MatrixSymbol("x", k, 1) I1 = Identity(1) I = Identity(k) # Check matrix recognition over trivial dimensions: cg = CodegenArrayTensorProduct(a, b) assert recognize_matrix_expression(cg) == a * b.T cg = CodegenArrayTensorProduct(I1, a, b) assert recognize_matrix_expression(cg) == a * I1 * b.T # Recognize trace inside a tensor product: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, B, C), (0, 3), (1, 2)) assert recognize_matrix_expression(cg) == Trace(A * B) * C # Transform diagonal operator to contraction: cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(A, a), (1, 2)) assert cg.transform_to_product() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagMatrix(a)), (1, 2)) assert recognize_matrix_expression(cg) == A * DiagMatrix(a) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(a, b), (0, 2)) assert cg.transform_to_product() == CodegenArrayContraction( CodegenArrayTensorProduct(DiagMatrix(a), b), (0, 2)) assert recognize_matrix_expression(cg).doit() == DiagMatrix(a) * b cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(A, a), (0, 2)) assert cg.transform_to_product() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagMatrix(a)), (0, 2)) assert recognize_matrix_expression(cg) == A.T * DiagMatrix(a) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(I, x, I1), (0, 2), (3, 5)) assert cg.transform_to_product() == CodegenArrayContraction( CodegenArrayTensorProduct(I, DiagMatrix(x), I1), (0, 2)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(I, x, A, B), (1, 2), (5, 6)) assert cg.transform_to_product() == CodegenArrayDiagonal( CodegenArrayContraction( CodegenArrayTensorProduct(I, DiagMatrix(x), A, B), (1, 2)), (3, 4)) cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(x, I1), (1, 2)) assert isinstance(cg, CodegenArrayDiagonal) assert cg.diagonal_indices == ((1, 2), ) assert recognize_matrix_expression(cg) == x cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(x, I), (0, 2)) assert cg.transform_to_product() == CodegenArrayContraction( CodegenArrayTensorProduct(DiagMatrix(x), I), (0, 2)) assert recognize_matrix_expression(cg).doit() == DiagMatrix(x) cg = CodegenArrayDiagonal(x, (1, )) assert cg == x # Ignore identity matrices with contractions: cg = CodegenArrayContraction(CodegenArrayTensorProduct(I, A, I, I), (0, 2), (1, 3), (5, 7)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg) == Trace(A) * I cg = CodegenArrayContraction(CodegenArrayTensorProduct(Trace(A) * I, I, I), (1, 5), (3, 4)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg).doit() == Trace(A) * I # Add DiagMatrix when required: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a), (1, 2)) assert cg.split_multiple_contractions() == cg assert recognize_matrix_expression(cg) == A * a cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, B), (1, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagMatrix(a), B), (1, 2), (3, 4)) assert recognize_matrix_expression(cg) == A * DiagMatrix(a) * B cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, B), (0, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagMatrix(a), B), (0, 2), (3, 4)) assert recognize_matrix_expression(cg) == A.T * DiagMatrix(a) * B cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, b, a.T, B), (0, 2, 4, 7, 9)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagMatrix(a), DiagMatrix(b), DiagMatrix(a), B), (0, 2), (3, 4), (5, 7), (6, 9)) assert recognize_matrix_expression( cg).doit() == A.T * DiagMatrix(a) * DiagMatrix(b) * DiagMatrix(a) * B.T cg = CodegenArrayContraction(CodegenArrayTensorProduct(I1, I1, I1), (1, 2, 4)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(I1, I1, I1), (1, 2), (3, 4)) assert recognize_matrix_expression(cg).doit() == Identity(1) cg = CodegenArrayContraction(CodegenArrayTensorProduct(I, I, I, I, A), (1, 2, 8), (5, 6, 9)) assert recognize_matrix_expression( cg.split_multiple_contractions()).doit() == A cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8)) assert cg.split_multiple_contractions() == CodegenArrayContraction( CodegenArrayTensorProduct(A, DiagMatrix(a), C, DiagMatrix(a), B), (1, 2), (3, 4), (5, 6), (7, 8)) assert recognize_matrix_expression( cg) == A * DiagMatrix(a) * C * DiagMatrix(a) * B cg = CodegenArrayContraction( CodegenArrayTensorProduct(a, I1, b, I1, (a.T * b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions().dummy_eq( CodegenArrayContraction( CodegenArrayTensorProduct(a, I1, b, I1, (a.T * b).applyfunc(cos)), (1, 2), (3, 8), (5, 6), (7, 9))) assert recognize_matrix_expression(cg).dummy_eq( MatMul(a, I1, (a.T * b).applyfunc(cos), Transpose(I1), b.T)) cg = CodegenArrayContraction( CodegenArrayTensorProduct(A.T, a, b, b.T, (A * X * b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions().dummy_eq( CodegenArrayContraction( CodegenArrayTensorProduct(A.T, DiagMatrix(a), b, b.T, (A * X * b).applyfunc(cos)), (1, 2), (3, 8), (5, 6, 9))) # assert recognize_matrix_expression(cg) # Check no overlap of lines: cg = CodegenArrayContraction(CodegenArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8), (3, 7)) assert cg.split_multiple_contractions() == cg cg = CodegenArrayContraction(CodegenArrayTensorProduct(a, b, A), (0, 2, 4), (1, 3)) assert cg.split_multiple_contractions() == cg
def test_codegen_extra(): if not torch: skip("Torch not installed") M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) P = MatrixSymbol("P", 2, 2) Q = MatrixSymbol("Q", 2, 2) ma = torch.tensor([[1, 2], [3, 4]]) mb = torch.tensor([[1, -2], [-1, 3]]) mc = torch.tensor([[2, 0], [1, 2]]) md = torch.tensor([[1, -1], [4, 7]]) cg = CodegenArrayTensorProduct(M, N) assert torch_code(cg) == 'torch.einsum("ab,cd", [M, N])' f = lambdify((M, N), cg, 'torch') y = f(ma, mb) c = torch.einsum("ij,kl", ma, mb) assert (y == c).all() cg = CodegenArrayElementwiseAdd(M, N) assert torch_code(cg) == 'torch.add(M, N)' f = lambdify((M, N), cg, 'torch') y = f(ma, mb) c = ma + mb assert (y == c).all() cg = CodegenArrayElementwiseAdd(M, N, P) assert torch_code(cg) == 'torch.add(torch.add(M, N), P)' f = lambdify((M, N, P), cg, 'torch') y = f(ma, mb, mc) c = ma + mb + mc assert (y == c).all() cg = CodegenArrayElementwiseAdd(M, N, P, Q) assert torch_code(cg) == 'torch.add(torch.add(torch.add(M, N), P), Q)' f = lambdify((M, N, P, Q), cg, 'torch') y = f(ma, mb, mc, md) c = ma + mb + mc + md assert (y == c).all() cg = CodegenArrayPermuteDims(M, [1, 0]) assert torch_code(cg) == 'M.permute(1, 0)' f = lambdify((M, ), cg, 'torch') y = f(ma) c = ma.T assert (y == c).all() cg = CodegenArrayPermuteDims(CodegenArrayTensorProduct(M, N), [1, 2, 3, 0]) assert torch_code( cg) == 'torch.einsum("ab,cd", [M, N]).permute(1, 2, 3, 0)' f = lambdify((M, N), cg, 'torch') y = f(ma, mb) c = torch.einsum("ab,cd", ma, mb).permute(1, 2, 3, 0) assert (y == c).all() cg = CodegenArrayDiagonal(CodegenArrayTensorProduct(M, N), (1, 2)) assert torch_code(cg) == 'torch.einsum("ab,bc->acb", [M, N])' f = lambdify((M, N), cg, 'torch') y = f(ma, mb) c = torch.einsum("ab,bc->acb", ma, mb) assert (y == c).all()