def test_mixed_deriv_mixed_expressions(): expr = Trace(A)*A # TODO: this is not yet supported: assert expr.diff(A) == Derivative(expr, A) expr = Trace(Trace(A)*A) assert expr.diff(A) == (2*Trace(A))*Identity(k)
def test_matrix_derivative_with_inverse(): # Cookbook example 61: expr = a.T*Inverse(X)*b assert expr.diff(X) == -Inverse(X).T*a*b.T*Inverse(X).T # Cookbook example 63: expr = Trace(A*Inverse(X)*B) assert expr.diff(X) == -(X**(-1)*B*A*X**(-1)).T # Cookbook example 64: expr = Trace(Inverse(X + A)) assert expr.diff(X) == -(Inverse(X + A)*Inverse(X + A)).T
def test_mixed_deriv_mixed_expressions(): expr = 3*Trace(A) assert expr.diff(A) == 3*Identity(k) expr = k deriv = expr.diff(A) assert isinstance(deriv, ZeroMatrix) assert deriv == ZeroMatrix(k, k) expr = Trace(A)**2 assert expr.diff(A) == (2*Trace(A))*Identity(k) expr = Trace(A)*A # TODO: this is not yet supported: assert expr.diff(A) == Derivative(expr, A) expr = Trace(Trace(A)*A) assert expr.diff(A) == (2*Trace(A))*Identity(k) expr = Trace(Trace(Trace(A)*A)*A) assert expr.diff(A) == (3*Trace(A)**2)*Identity(k)
def test_non_atoms(): assert ask(Q.real(Trace(X)), Q.positive(Trace(X)))
def density(self, expr): n, ZGSE = self.dimension, self.normalization_constant h_pspace = RandomMatrixPSpace('P', model=self) H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) return Lambda(H, exp(-S(n) * Trace(H**2)) / ZGSE)(expr)
def normalization_constant(self): n = self.dimension _H = MatrixSymbol('_H', n, n) return Integral(exp(-S(n) * Trace(_H**2)))
def trace_sum_distribute_repl(dX): return lambda x: Add(*[Trace(A) for A in x.arg.args])
def transpose_traces_repl(dX): return lambda x: Trace(x.arg.T)
from .symbols import d, Kron, SymmetricMatrixSymbol from .simplifications import simplify_matdiff MATRIX_DIFF_RULES = { # e =expression, s = a list of symbols respsect to which # we want to differentiate Symbol: lambda e, s: d(e) if (e in s) else 0, MatrixSymbol: lambda e, s: d(e) if (e in s) else ZeroMatrix(*e.shape), SymmetricMatrixSymbol: lambda e, s: d(e) if (e in s) else ZeroMatrix(*e.shape), Add: lambda e, s: Add(*[_matDiff_apply(arg, s) for arg in e.args]), Mul: lambda e, s: _matDiff_apply(e.args[0], s) if len(e.args)==1 else Mul(_matDiff_apply(e.args[0],s),Mul(*e.args[1:])) + Mul(e.args[0], _matDiff_apply(Mul(*e.args[1:]),s)), MatAdd: lambda e, s: MatAdd(*[_matDiff_apply(arg, s) for arg in e.args]), MatMul: lambda e, s: _matDiff_apply(e.args[0], s) if len(e.args)==1 else MatMul(_matDiff_apply(e.args[0],s),MatMul(*e.args[1:])) + MatMul(e.args[0], _matDiff_apply(MatMul(*e.args[1:]),s)), Kron: lambda e, s: _matDiff_apply(e.args[0],s) if len(e.args)==1 else Kron(_matDiff_apply(e.args[0],s),Kron(*e.args[1:])) + Kron(e.args[0],_matDiff_apply(Kron(*e.args[1:]),s)), Determinant: lambda e, s: MatMul(Determinant(e.args[0]), Trace(e.args[0].I*_matDiff_apply(e.args[0], s))), # inverse always has 1 arg, so we index Inverse: lambda e, s: -Inverse(e.args[0]) * _matDiff_apply(e.args[0], s) * Inverse(e.args[0]), # trace always has 1 arg Trace: lambda e, s: Trace(_matDiff_apply(e.args[0], s)), # transpose also always has 1 arg, index Transpose: lambda e, s: Transpose(_matDiff_apply(e.args[0], s)) } def _matDiff_apply(expr, syms): if expr.__class__ in list(MATRIX_DIFF_RULES.keys()): return MATRIX_DIFF_RULES[expr.__class__](expr, syms) elif expr.is_constant(): return 0 else:
def identify_hadamard_products(expr: Union[ArrayContraction, ArrayDiagonal]): mapping = _get_mapping_from_subranks(expr.subranks) editor: _EditArrayContraction if isinstance(expr, ArrayContraction): editor = _EditArrayContraction(expr) elif isinstance(expr, ArrayDiagonal): if isinstance(expr.expr, ArrayContraction): editor = _EditArrayContraction(expr.expr) diagonalized = ArrayContraction._push_indices_down( expr.expr.contraction_indices, expr.diagonal_indices) elif isinstance(expr.expr, ArrayTensorProduct): editor = _EditArrayContraction(None) editor.args_with_ind = [ _ArgE(arg) for i, arg in enumerate(expr.expr.args) ] diagonalized = expr.diagonal_indices else: return expr # Trick: add diagonalized indices as negative indices into the editor object: for i, e in enumerate(diagonalized): for j in e: arg_pos, rel_pos = mapping[j] editor.args_with_ind[arg_pos].indices[rel_pos] = -1 - i map_contr_to_args: Dict[FrozenSet, List[_ArgE]] = defaultdict(list) map_ind_to_inds = defaultdict(int) for arg_with_ind in editor.args_with_ind: for ind in arg_with_ind.indices: map_ind_to_inds[ind] += 1 if None in arg_with_ind.indices: continue map_contr_to_args[frozenset(arg_with_ind.indices)].append(arg_with_ind) k: FrozenSet[int] v: List[_ArgE] for k, v in map_contr_to_args.items(): make_trace: bool = False if len(k) == 1 and next(iter(k)) >= 0 and sum( [next(iter(k)) in i for i in map_contr_to_args]) == 1: # This is a trace: the arguments are fully contracted with only one # index, and the index isn't used anywhere else: make_trace = True first_element = S.One elif len(k) != 2: # Hadamard product only defined for matrices: continue if len(v) == 1: # Hadamard product with a single argument makes no sense: continue for ind in k: if map_ind_to_inds[ind] <= 2: # There is no other contraction, skip: continue def check_transpose(x): x = [i if i >= 0 else -1 - i for i in x] return x == sorted(x) # Check if expression is a trace: if all([map_ind_to_inds[j] == len(v) and j >= 0 for j in k]) and all([j >= 0 for j in k]): # This is a trace make_trace = True first_element = v[0].element if not check_transpose(v[0].indices): first_element = first_element.T hadamard_factors = v[1:] else: hadamard_factors = v # This is a Hadamard product: hp = hadamard_product(*[ i.element if check_transpose(i.indices) else Transpose(i.element) for i in hadamard_factors ]) hp_indices = v[0].indices if not check_transpose(hadamard_factors[0].indices): hp_indices = list(reversed(hp_indices)) if make_trace: hp = Trace(first_element * hp.T)._normalize() hp_indices = [] editor.insert_after(v[0], _ArgE(hp, hp_indices)) for i in v: editor.args_with_ind.remove(i) # Count the ranks of the arguments: counter = 0 # Create a collector for the new diagonal indices: diag_indices = defaultdict(list) count_index_freq = Counter() for arg_with_ind in editor.args_with_ind: count_index_freq.update(Counter(arg_with_ind.indices)) free_index_count = count_index_freq[None] # Construct the inverse permutation: inv_perm1 = [] inv_perm2 = [] # Keep track of which diagonal indices have already been processed: done = set([]) # Counter for the diagonal indices: counter4 = 0 for arg_with_ind in editor.args_with_ind: # If some diagonalization axes have been removed, they should be # permuted in order to keep the permutation. # Add permutation here counter2 = 0 # counter for the indices for i in arg_with_ind.indices: if i is None: inv_perm1.append(counter4) counter2 += 1 counter4 += 1 continue if i >= 0: continue # Reconstruct the diagonal indices: diag_indices[-1 - i].append(counter + counter2) if count_index_freq[i] == 1 and i not in done: inv_perm1.append(free_index_count - 1 - i) done.add(i) elif i not in done: inv_perm2.append(free_index_count - 1 - i) done.add(i) counter2 += 1 # Remove negative indices to restore a proper editor object: arg_with_ind.indices = [ i if i is not None and i >= 0 else None for i in arg_with_ind.indices ] counter += len([i for i in arg_with_ind.indices if i is None or i < 0]) inverse_permutation = inv_perm1 + inv_perm2 permutation = _af_invert(inverse_permutation) if isinstance(expr, ArrayContraction): return editor.to_array_contraction() else: # Get the diagonal indices after the detection of HadamardProduct in the expression: diag_indices_filtered = [ tuple(v) for v in diag_indices.values() if len(v) > 1 ] expr1 = editor.to_array_contraction() expr2 = ArrayDiagonal(expr1, *diag_indices_filtered) expr3 = PermuteDims(expr2, permutation) return expr3
def _a2m_trace(arg): if isinstance(arg, _CodegenArrayAbstract): return ArrayContraction(arg, (0, 1)) else: from sympy import Trace return Trace(arg)
def test_matrix_derivatives_of_traces(): ## First order: # Cookbook example 99: expr = Trace(X) assert expr.diff(X) == Identity(k) # Cookbook example 100: expr = Trace(X*A) assert expr.diff(X) == A.T # Cookbook example 101: expr = Trace(A*X*B) assert expr.diff(X) == A.T*B.T # Cookbook example 102: expr = Trace(A*X.T*B) assert expr.diff(X) == B*A # Cookbook example 103: expr = Trace(X.T*A) assert expr.diff(X) == A # Cookbook example 104: expr = Trace(A*X.T) assert expr.diff(X) == A # Cookbook example 105: # TODO: TensorProduct is not supported #expr = Trace(TensorProduct(A, X)) #assert expr.diff(X) == Trace(A)*Identity(k) ## Second order: # Cookbook example 106: expr = Trace(X**2) assert expr.diff(X) == 2*X.T # Cookbook example 107: expr = Trace(X**2*B) # TODO: wrong result #assert expr.diff(X) == (X*B + B*X).T expr = Trace(MatMul(X, X, B)) assert expr.diff(X) == (X*B + B*X).T # Cookbook example 108: expr = Trace(X.T*B*X) assert expr.diff(X) == B*X + B.T*X # Cookbook example 109: expr = Trace(B*X*X.T) assert expr.diff(X) == B*X + B.T*X # Cookbook example 110: expr = Trace(X*X.T*B) assert expr.diff(X) == B*X + B.T*X # Cookbook example 111: expr = Trace(X*B*X.T) assert expr.diff(X) == X*B.T + X*B # Cookbook example 112: expr = Trace(B*X.T*X) assert expr.diff(X) == X*B.T + X*B # Cookbook example 113: expr = Trace(X.T*X*B) assert expr.diff(X) == X*B.T + X*B # Cookbook example 114: expr = Trace(A*X*B*X) assert expr.diff(X) == A.T*X.T*B.T + B.T*X.T*A.T # Cookbook example 115: expr = Trace(X.T*X) assert expr.diff(X) == 2*X expr = Trace(X*X.T) assert expr.diff(X) == 2*X # Cookbook example 116: expr = Trace(B.T*X.T*C*X*B) assert expr.diff(X) == C.T*X*B*B.T + C*X*B*B.T # Cookbook example 117: expr = Trace(X.T*B*X*C) assert expr.diff(X) == B*X*C + B.T*X*C.T # Cookbook example 118: expr = Trace(A*X*B*X.T*C) assert expr.diff(X) == A.T*C.T*X*B.T + C*A*X*B # Cookbook example 119: expr = Trace((A*X*B + C)*(A*X*B + C).T) assert expr.diff(X) == 2*A.T*(A*X*B + C)*B.T # Cookbook example 120: # TODO: no support for TensorProduct. # expr = Trace(TensorProduct(X, X)) # expr = Trace(X)*Trace(X) # expr.diff(X) == 2*Trace(X)*Identity(k) # Higher Order # Cookbook example 121: expr = Trace(X**k) #assert expr.diff(X) == k*(X**(k-1)).T # Cookbook example 122: expr = Trace(A*X**k) #assert expr.diff(X) == # Needs indices # Cookbook example 123: expr = Trace(B.T*X.T*C*X*X.T*C*X*B) assert expr.diff(X) == C*X*X.T*C*X*B*B.T + C.T*X*B*B.T*X.T*C.T*X + C*X*B*B.T*X.T*C*X + C.T*X*X.T*C.T*X*B*B.T # Other # Cookbook example 124: expr = Trace(A*X**(-1)*B) assert expr.diff(X) == -Inverse(X).T*A.T*B.T*Inverse(X).T # Cookbook example 125: expr = Trace(Inverse(X.T*C*X)*A) # Warning: result in the cookbook is equivalent if B and C are symmetric: assert expr.diff(X) == - X.inv().T*A.T*X.inv()*C.inv().T*X.inv().T - X.inv().T*A*X.inv()*C.inv()*X.inv().T # Cookbook example 126: expr = Trace((X.T*C*X).inv()*(X.T*B*X)) assert expr.diff(X) == -2*C*X*(X.T*C*X).inv()*X.T*B*X*(X.T*C*X).inv() + 2*B*X*(X.T*C*X).inv() # Cookbook example 127: expr = Trace((A + X.T*C*X).inv()*(X.T*B*X)) # Warning: result in the cookbook is equivalent if B and C are symmetric: assert expr.diff(X) == B*X*Inverse(A + X.T*C*X) - C*X*Inverse(A + X.T*C*X)*X.T*B*X*Inverse(A + X.T*C*X) - C.T*X*Inverse(A.T + (C*X).T*X)*X.T*B.T*X*Inverse(A.T + (C*X).T*X) + B.T*X*Inverse(A.T + (C*X).T*X)
def test_arrayexpr_convert_matrix_to_array(): expr = M*N result = ArrayContraction(ArrayTensorProduct(M, N), (1, 2)) assert convert_matrix_to_array(expr) == result expr = M*N*M result = ArrayContraction(ArrayTensorProduct(M, N, M), (1, 2), (3, 4)) assert convert_matrix_to_array(expr) == result expr = Transpose(M) assert convert_matrix_to_array(expr) == PermuteDims(M, [1, 0]) expr = M*Transpose(N) assert convert_matrix_to_array(expr) == ArrayContraction(ArrayTensorProduct(M, PermuteDims(N, [1, 0])), (1, 2)) expr = 3*M*N res = convert_matrix_to_array(expr) rexpr = convert_array_to_matrix(res) assert expr == rexpr expr = 3*M + N*M.T*M + 4*k*N res = convert_matrix_to_array(expr) rexpr = convert_array_to_matrix(res) assert expr == rexpr expr = Inverse(M)*N rexpr = convert_array_to_matrix(convert_matrix_to_array(expr)) assert expr == rexpr expr = M**2 rexpr = convert_array_to_matrix(convert_matrix_to_array(expr)) assert expr == rexpr expr = M*(2*N + 3*M) res = convert_matrix_to_array(expr) rexpr = convert_array_to_matrix(res) assert expr == rexpr expr = Trace(M) result = ArrayContraction(M, (0, 1)) assert convert_matrix_to_array(expr) == result expr = 3*Trace(M) result = ArrayContraction(ArrayTensorProduct(3, M), (0, 1)) assert convert_matrix_to_array(expr) == result expr = 3*Trace(Trace(M) * M) result = ArrayContraction(ArrayTensorProduct(3, M, M), (0, 1), (2, 3)) assert convert_matrix_to_array(expr) == result expr = 3*Trace(M)**2 result = ArrayContraction(ArrayTensorProduct(3, M, M), (0, 1), (2, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardProduct(M, N) result = ArrayDiagonal(ArrayTensorProduct(M, N), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardProduct(M*N, N*M) result = ArrayDiagonal(ArrayContraction(ArrayTensorProduct(M, N, N, M), (1, 2), (5, 6)), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardPower(M, 2) result = ArrayDiagonal(ArrayTensorProduct(M, M), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardPower(M*N, 2) result = ArrayDiagonal(ArrayContraction(ArrayTensorProduct(M, N, M, N), (1, 2), (5, 6)), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = M**2 assert isinstance(expr, MatPow) assert convert_matrix_to_array(expr) == ArrayContraction(ArrayTensorProduct(M, M), (1, 2)) expr = a.T*b cg = convert_matrix_to_array(expr) assert cg == ArrayContraction(ArrayTensorProduct(a, b), (0, 2))
def _support_function_tp1_recognize(contraction_indices, args): subranks = [get_rank(i) for i in args] coeff = reduce(lambda x, y: x * y, [arg for arg, srank in zip(args, subranks) if srank == 0], S.One) mapping = _get_mapping_from_subranks(subranks) new_contraction_indices = list(contraction_indices) newargs = args[:] # make a copy of the list removed = [None for i in newargs] cumul = list(accumulate([0] + [get_rank(arg) for arg in args])) new_perms = [ list(range(cumul[i], cumul[i + 1])) for i, arg in enumerate(args) ] for pi, contraction_pair in enumerate(contraction_indices): if len(contraction_pair) != 2: continue i1, i2 = contraction_pair a1, e1 = mapping[i1] a2, e2 = mapping[i2] while removed[a1] is not None: a1, e1 = removed[a1] while removed[a2] is not None: a2, e2 = removed[a2] if a1 == a2: trace_arg = newargs[a1] newargs[a1] = Trace(trace_arg)._normalize() new_contraction_indices[pi] = None continue if not isinstance(newargs[a1], MatrixExpr) or not isinstance( newargs[a2], MatrixExpr): continue arg1 = newargs[a1] arg2 = newargs[a2] if (e1 == 1 and e2 == 1) or (e1 == 0 and e2 == 0): arg2 = Transpose(arg2) if e1 == 1: argnew = arg1 * arg2 else: argnew = arg2 * arg1 removed[a2] = a1, e1 new_perms[a1][e1] = new_perms[a2][1 - e2] new_perms[a2] = None newargs[a1] = argnew newargs[a2] = None new_contraction_indices[pi] = None new_contraction_indices = [ i for i in new_contraction_indices if i is not None ] newargs2 = [arg for arg in newargs if arg is not None] if len(newargs2) == 0: return coeff tp = _a2m_tensor_product(*newargs2) tc = ArrayContraction(tp, *new_contraction_indices) new_perms2 = ArrayContraction._push_indices_up( contraction_indices, [i for i in new_perms if i is not None]) permutation = _af_invert( [j for i in new_perms2 for j in i if j is not None]) if permutation == [1, 0] and len(newargs2) == 1: return Transpose(newargs2[0]).doit() tperm = PermuteDims(tc, permutation) return tperm
def test_mixed_deriv_mixed_expressions(): expr = 3 * Trace(A) assert expr.diff(A) == 3 * Identity(k) expr = k deriv = expr.diff(A) assert isinstance(deriv, ZeroMatrix) assert deriv == ZeroMatrix(k, k) expr = Trace(A)**2 assert expr.diff(A) == (2 * Trace(A)) * Identity(k) expr = Trace(A) * A # TODO: this is not yet supported: assert expr.diff(A) == Derivative(expr, A) expr = Trace(Trace(A) * A) assert expr.diff(A) == (2 * Trace(A)) * Identity(k) expr = Trace(Trace(Trace(A) * A) * A) assert expr.diff(A) == (3 * Trace(A)**2) * Identity(k)
def test_matrix_derivatives_of_traces(): expr = Trace(A)*A assert expr.diff(A) == Derivative(Trace(A)*A, A) ## First order: # Cookbook example 99: expr = Trace(X) assert expr.diff(X) == Identity(k) # Cookbook example 100: expr = Trace(X*A) assert expr.diff(X) == A.T # Cookbook example 101: expr = Trace(A*X*B) assert expr.diff(X) == A.T*B.T # Cookbook example 102: expr = Trace(A*X.T*B) assert expr.diff(X) == B*A # Cookbook example 103: expr = Trace(X.T*A) assert expr.diff(X) == A # Cookbook example 104: expr = Trace(A*X.T) assert expr.diff(X) == A # Cookbook example 105: # TODO: TensorProduct is not supported #expr = Trace(TensorProduct(A, X)) #assert expr.diff(X) == Trace(A)*Identity(k) ## Second order: # Cookbook example 106: expr = Trace(X**2) assert expr.diff(X) == 2*X.T # Cookbook example 107: expr = Trace(X**2*B) assert expr.diff(X) == (X*B + B*X).T expr = Trace(MatMul(X, X, B)) assert expr.diff(X) == (X*B + B*X).T # Cookbook example 108: expr = Trace(X.T*B*X) assert expr.diff(X) == B*X + B.T*X # Cookbook example 109: expr = Trace(B*X*X.T) assert expr.diff(X) == B*X + B.T*X # Cookbook example 110: expr = Trace(X*X.T*B) assert expr.diff(X) == B*X + B.T*X # Cookbook example 111: expr = Trace(X*B*X.T) assert expr.diff(X) == X*B.T + X*B # Cookbook example 112: expr = Trace(B*X.T*X) assert expr.diff(X) == X*B.T + X*B # Cookbook example 113: expr = Trace(X.T*X*B) assert expr.diff(X) == X*B.T + X*B # Cookbook example 114: expr = Trace(A*X*B*X) assert expr.diff(X) == A.T*X.T*B.T + B.T*X.T*A.T # Cookbook example 115: expr = Trace(X.T*X) assert expr.diff(X) == 2*X expr = Trace(X*X.T) assert expr.diff(X) == 2*X # Cookbook example 116: expr = Trace(B.T*X.T*C*X*B) assert expr.diff(X) == C.T*X*B*B.T + C*X*B*B.T # Cookbook example 117: expr = Trace(X.T*B*X*C) assert expr.diff(X) == B*X*C + B.T*X*C.T # Cookbook example 118: expr = Trace(A*X*B*X.T*C) assert expr.diff(X) == A.T*C.T*X*B.T + C*A*X*B # Cookbook example 119: expr = Trace((A*X*B + C)*(A*X*B + C).T) assert expr.diff(X) == 2*A.T*(A*X*B + C)*B.T # Cookbook example 120: # TODO: no support for TensorProduct. # expr = Trace(TensorProduct(X, X)) # expr = Trace(X)*Trace(X) # expr.diff(X) == 2*Trace(X)*Identity(k) # Higher Order # Cookbook example 121: expr = Trace(X**k) #assert expr.diff(X) == k*(X**(k-1)).T # Cookbook example 122: expr = Trace(A*X**k) #assert expr.diff(X) == # Needs indices # Cookbook example 123: expr = Trace(B.T*X.T*C*X*X.T*C*X*B) assert expr.diff(X) == C*X*X.T*C*X*B*B.T + C.T*X*B*B.T*X.T*C.T*X + C*X*B*B.T*X.T*C*X + C.T*X*X.T*C.T*X*B*B.T # Other # Cookbook example 124: expr = Trace(A*X**(-1)*B) assert expr.diff(X) == -Inverse(X).T*A.T*B.T*Inverse(X).T # Cookbook example 125: expr = Trace(Inverse(X.T*C*X)*A) # Warning: result in the cookbook is equivalent if B and C are symmetric: assert expr.diff(X) == - X.inv().T*A.T*X.inv()*C.inv().T*X.inv().T - X.inv().T*A*X.inv()*C.inv()*X.inv().T # Cookbook example 126: expr = Trace((X.T*C*X).inv()*(X.T*B*X)) assert expr.diff(X) == -2*C*X*(X.T*C*X).inv()*X.T*B*X*(X.T*C*X).inv() + 2*B*X*(X.T*C*X).inv() # Cookbook example 127: expr = Trace((A + X.T*C*X).inv()*(X.T*B*X)) # Warning: result in the cookbook is equivalent if B and C are symmetric: assert expr.diff(X) == B*X*Inverse(A + X.T*C*X) - C*X*Inverse(A + X.T*C*X)*X.T*B*X*Inverse(A + X.T*C*X) - C.T*X*Inverse(A.T + (C*X).T*X)*X.T*B.T*X*Inverse(A.T + (C*X).T*X) + B.T*X*Inverse(A.T + (C*X).T*X)
def test_matrix_derivatives_of_traces(): ## First order: # Cookbook example 99: expr = Trace(X) assert expr.diff(X) == Identity(k) # Cookbook example 100: expr = Trace(X*A) assert expr.diff(X) == A.T # Cookbook example 101: expr = Trace(A*X*B) assert expr.diff(X) == A.T*B.T # Cookbook example 102: expr = Trace(A*X.T*B) assert expr.diff(X) == B*A # Cookbook example 103: expr = Trace(X.T*A) assert expr.diff(X) == A # Cookbook example 104: expr = Trace(A*X.T) assert expr.diff(X) == A # Cookbook example 105: # TODO: TensorProduct is not supported #expr = Trace(TensorProduct(A, X)) #assert expr.diff(X) == Trace(A)*Identity(k) ## Second order: # Cookbook example 106: expr = Trace(X**2) assert expr.diff(X) == 2*X.T # Cookbook example 107: expr = Trace(X**2*B) # TODO: wrong result #assert expr.diff(X) == (X*B + B*X).T expr = Trace(MatMul(X, X, B)) assert expr.diff(X) == (X*B + B*X).T # Cookbook example 108: expr = Trace(X.T*B*X) assert expr.diff(X) == B*X + B.T*X # Cookbook example 109: expr = Trace(B*X*X.T) assert expr.diff(X) == B*X + B.T*X # Cookbook example 110: expr = Trace(X*X.T*B) assert expr.diff(X) == B*X + B.T*X # Cookbook example 111: expr = Trace(X*B*X.T) assert expr.diff(X) == X*B.T + X*B # Cookbook example 112: expr = Trace(B*X.T*X) assert expr.diff(X) == X*B.T + X*B # Cookbook example 113: expr = Trace(X.T*X*B) assert expr.diff(X) == X*B.T + X*B # Cookbook example 114: expr = Trace(A*X*B*X) assert expr.diff(X) == A.T*X.T*B.T + B.T*X.T*A.T # Cookbook example 115: expr = Trace(X.T*X) assert expr.diff(X) == 2*X expr = Trace(X*X.T) assert expr.diff(X) == 2*X # Cookbook example 116: expr = Trace(B.T*X.T*C*X*B) assert expr.diff(X) == C.T*X*B*B.T + C*X*B*B.T # Cookbook example 117: expr = Trace(X.T*B*X*C) assert expr.diff(X) == B*X*C + B.T*X*C.T # Cookbook example 118: expr = Trace(A*X*B*X.T*C) assert expr.diff(X) == A.T*C.T*X*B.T + C*A*X*B # Cookbook example 119: expr = Trace((A*X*B + C)*(A*X*B + C).T) assert expr.diff(X) == 2*A.T*(A*X*B + C)*B.T
def test_matrix_derivatives_of_traces(): ## First order: # Cookbook example 99: expr = Trace(X) assert expr.diff(X) == Identity(k) # Cookbook example 100: expr = Trace(X*A) assert expr.diff(X) == A.T # Cookbook example 101: expr = Trace(A*X*B) assert expr.diff(X) == A.T*B.T # Cookbook example 102: expr = Trace(A*X.T*B) assert expr.diff(X) == B*A # Cookbook example 103: expr = Trace(X.T*A) assert expr.diff(X) == A # Cookbook example 104: expr = Trace(A*X.T) assert expr.diff(X) == A # Cookbook example 105: # TODO: TensorProduct is not supported #expr = Trace(TensorProduct(A, X)) #assert expr.diff(X) == Trace(A)*Identity(k) ## Second order: # Cookbook example 106: expr = Trace(X**2) assert expr.diff(X) == 2*X.T # Cookbook example 107: expr = Trace(X**2*B) # TODO: wrong result #assert expr.diff(X) == (X*B + B*X).T expr = Trace(X*X*B) assert expr.diff(X) == (X*B + B*X).T # Cookbook example 108: expr = Trace(X.T*B*X) assert expr.diff(X) == B*X + B.T*X # Cookbook example 109: expr = Trace(B*X*X.T) assert expr.diff(X) == B*X + B.T*X # Cookbook example 110: expr = Trace(X*X.T*B) assert expr.diff(X) == B*X + B.T*X # Cookbook example 111: expr = Trace(X*B*X.T) assert expr.diff(X) == X*B.T + X*B # Cookbook example 112: expr = Trace(B*X.T*X) assert expr.diff(X) == X*B.T + X*B # Cookbook example 113: expr = Trace(X.T*X*B) assert expr.diff(X) == X*B.T + X*B # Cookbook example 114: expr = Trace(A*X*B*X) assert expr.diff(X) == A.T*X.T*B.T + B.T*X.T*A.T # Cookbook example 115: expr = Trace(X.T*X) assert expr.diff(X) == 2*X expr = Trace(X*X.T) assert expr.diff(X) == 2*X # Cookbook example 116: expr = Trace(B.T*X.T*C*X*B) assert expr.diff(X) == C.T*X*B*B.T + C*X*B*B.T # Cookbook example 117: expr = Trace(X.T*B*X*C) assert expr.diff(X) == B*X*C + B.T*X*C.T # Cookbook example 118: expr = Trace(A*X*B*X.T*C) assert expr.diff(X) == A.T*C.T*X*B.T + C*A*X*B # Cookbook example 119: expr = Trace((A*X*B + C)*(A*X*B + C).T) assert expr.diff(X) == 2*A.T*(A*X*B + C)*B.T
def density(self, expr): n, ZGOE = self.dimension, self.normalization_constant h_pspace = RandomMatrixPSpace("P", model=self) H = RandomMatrixSymbol("H", n, n, pspace=h_pspace) return Lambda(H, exp(-S(n) / 4 * Trace(H ** 2)) / ZGOE)