def __new__(cls, *args, **kwargs): args = list(map(sympify, args)) check = kwargs.get('check', False) obj = Basic.__new__(cls, *args) if check: if all(not isinstance(i, MatrixExpr) for i in args): return Add.fromiter(args) validate(*args) return obj
def _matrix_derivative(expr, x): from sympy import Derivative lines = expr._eval_derivative_matrix_lines(x) ranks = [i.rank() for i in lines] assert len(set(ranks)) == 1 rank = ranks[0] if rank <= 2: return Add.fromiter([i.matrix_form() for i in lines]) return Derivative(expr, x)
def __new__(cls, *args, **kwargs): if not args: return GenericZeroMatrix() # This must be removed aggressively in the constructor to avoid # TypeErrors from GenericZeroMatrix().shape args = filter(lambda i: GenericZeroMatrix() != i, args) args = list(map(sympify, args)) check = kwargs.get('check', False) obj = Basic.__new__(cls, *args) if check: if all(not isinstance(i, MatrixExpr) for i in args): return Add.fromiter(args) validate(*args) return obj
def _matrix_derivative(expr, x): from sympy import Derivative lines = expr._eval_derivative_matrix_lines(x) parts = [i.build() for i in lines] from sympy.codegen.array_utils import recognize_matrix_expression parts = [[recognize_matrix_expression(j).doit() for j in i] for i in parts] def _get_shape(elem): if isinstance(elem, MatrixExpr): return elem.shape return (1, 1) def get_rank(parts): return sum([j not in (1, None) for i in parts for j in _get_shape(i)]) ranks = [get_rank(i) for i in parts] rank = ranks[0] def contract_one_dims(parts): if len(parts) == 1: return parts[0] else: p1, p2 = parts[:2] if p2.is_Matrix: p2 = p2.T if p1 == Identity(1): pbase = p2 elif p2 == Identity(1): pbase = p1 else: pbase = p1 * p2 if len(parts) == 2: return pbase else: # len(parts) > 2 if pbase.is_Matrix: raise ValueError("") return pbase * Mul.fromiter(parts[2:]) if rank <= 2: return Add.fromiter([contract_one_dims(i) for i in parts]) return Derivative(expr, x)
def _matrix_derivative(expr, x): from sympy.tensor.array.array_derivatives import ArrayDerivative lines = expr._eval_derivative_matrix_lines(x) parts = [i.build() for i in lines] from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix parts = [[convert_array_to_matrix(j) for j in i] for i in parts] def _get_shape(elem): if isinstance(elem, MatrixExpr): return elem.shape return 1, 1 def get_rank(parts): return sum([j not in (1, None) for i in parts for j in _get_shape(i)]) ranks = [get_rank(i) for i in parts] rank = ranks[0] def contract_one_dims(parts): if len(parts) == 1: return parts[0] else: p1, p2 = parts[:2] if p2.is_Matrix: p2 = p2.T if p1 == Identity(1): pbase = p2 elif p2 == Identity(1): pbase = p1 else: pbase = p1 * p2 if len(parts) == 2: return pbase else: # len(parts) > 2 if pbase.is_Matrix: raise ValueError("") return pbase * Mul.fromiter(parts[2:]) if rank <= 2: return Add.fromiter([contract_one_dims(i) for i in parts]) return ArrayDerivative(expr, x)
def _matrix_derivative(expr, x): from sympy import Derivative lines = expr._eval_derivative_matrix_lines(x) parts = [i.build() for i in lines] from sympy.codegen.array_utils import recognize_matrix_expression parts = [[recognize_matrix_expression(j).doit() for j in i] for i in parts] def _get_shape(elem): if isinstance(elem, MatrixExpr): return elem.shape return (1, 1) def get_rank(parts): return sum([j not in (1, None) for i in parts for j in _get_shape(i)]) ranks = [get_rank(i) for i in parts] rank = ranks[0] def contract_one_dims(parts): if len(parts) == 1: return parts[0] else: p1, p2 = parts[:2] if p2.is_Matrix: p2 = p2.T pbase = p1*p2 if len(parts) == 2: return pbase else: # len(parts) > 2 if pbase.is_Matrix: raise ValueError("") return pbase*Mul.fromiter(parts[2:]) if rank <= 2: return Add.fromiter([contract_one_dims(i) for i in parts]) return Derivative(expr, x)
def __new__(cls, *args, evaluate=False, check=False, _sympify=True): if not args: return cls.identity # This must be removed aggressively in the constructor to avoid # TypeErrors from GenericZeroMatrix().shape args = list(filter(lambda i: cls.identity != i, args)) if _sympify: args = list(map(sympify, args)) obj = Basic.__new__(cls, *args) if check: if not any(isinstance(i, MatrixExpr) for i in args): return Add.fromiter(args) validate(*args) if evaluate: if not any(isinstance(i, MatrixExpr) for i in args): return Add(*args, evaluate=True) obj = canonicalize(obj) return obj
def recurse_expr(expr, index_ranges={}): if expr.is_Mul: nonmatargs = [] pos_arg = [] pos_ind = [] dlinks = {} link_ind = [] counter = 0 args_ind = [] for arg in expr.args: retvals = recurse_expr(arg, index_ranges) assert isinstance(retvals, list) if isinstance(retvals, list): for i in retvals: args_ind.append(i) else: args_ind.append(retvals) for arg_symbol, arg_indices in args_ind: if arg_indices is None: nonmatargs.append(arg_symbol) continue if isinstance(arg_symbol, MatrixElement): arg_symbol = arg_symbol.args[0] pos_arg.append(arg_symbol) pos_ind.append(arg_indices) link_ind.append([None]*len(arg_indices)) for i, ind in enumerate(arg_indices): if ind in dlinks: other_i = dlinks[ind] link_ind[counter][i] = other_i link_ind[other_i[0]][other_i[1]] = (counter, i) dlinks[ind] = (counter, i) counter += 1 counter2 = 0 lines = {} while counter2 < len(link_ind): for i, e in enumerate(link_ind): if None in e: line_start_index = (i, e.index(None)) break cur_ind_pos = line_start_index cur_line = [] index1 = pos_ind[cur_ind_pos[0]][cur_ind_pos[1]] while True: d, r = cur_ind_pos if pos_arg[d] != 1: if r % 2 == 1: cur_line.append(transpose(pos_arg[d])) else: cur_line.append(pos_arg[d]) next_ind_pos = link_ind[d][1-r] counter2 += 1 # Mark as visited, there will be no `None` anymore: link_ind[d] = (-1, -1) if next_ind_pos is None: index2 = pos_ind[d][1-r] lines[(index1, index2)] = cur_line break cur_ind_pos = next_ind_pos ret_indices = list(j for i in lines for j in i) lines = {k: MatMul.fromiter(v) if len(v) != 1 else v[0] for k, v in lines.items()} return [(Mul.fromiter(nonmatargs), None)] + [ (MatrixElement(a, i, j), (i, j)) for (i, j), a in lines.items() ] elif expr.is_Add: res = [recurse_expr(i) for i in expr.args] d = collections.defaultdict(list) for res_addend in res: scalar = 1 for elem, indices in res_addend: if indices is None: scalar = elem continue indices = tuple(sorted(indices, key=default_sort_key)) d[indices].append(scalar*remove_matelement(elem, *indices)) scalar = 1 return [(MatrixElement(Add.fromiter(v), *k), k) for k, v in d.items()] elif isinstance(expr, KroneckerDelta): i1, i2 = expr.args if dimensions is not None: identity = Identity(dimensions[0]) else: identity = S.One return [(MatrixElement(identity, i1, i2), (i1, i2))] elif isinstance(expr, MatrixElement): matrix_symbol, i1, i2 = expr.args if i1 in index_ranges: r1, r2 = index_ranges[i1] if r1 != 0 or matrix_symbol.shape[0] != r2+1: raise ValueError("index range mismatch: {0} vs. (0, {1})".format( (r1, r2), matrix_symbol.shape[0])) if i2 in index_ranges: r1, r2 = index_ranges[i2] if r1 != 0 or matrix_symbol.shape[1] != r2+1: raise ValueError("index range mismatch: {0} vs. (0, {1})".format( (r1, r2), matrix_symbol.shape[1])) if (i1 == i2) and (i1 in index_ranges): return [(trace(matrix_symbol), None)] return [(MatrixElement(matrix_symbol, i1, i2), (i1, i2))] elif isinstance(expr, Sum): return recurse_expr( expr.args[0], index_ranges={i[0]: i[1:] for i in expr.args[1:]} ) else: return [(expr, None)]