def expand(prod): if not isinstance(prod, Product): return prod leading = [] for i in prod.children: if isinstance(i, Sum): break else: leading.append(i) if len(leading) == len(prod.children): # no more sums found result = pymbolic.flattened_product(prod.children) return result else: sum = prod.children[len(leading)] assert isinstance(sum, Sum) rest = prod.children[len(leading)+1:] if rest: rest = expand(Product(rest)) else: rest = 1 result = self.collector(pymbolic.flattened_sum( pymbolic.flattened_product(leading) * expand(sumchild*rest) for sumchild in sum.children )) return result
def sexpr_to_pymbolic(expr): from pymbolic.primitives import Variable, Sum, Product, Power stack = [] def error(token): raise ParserError("unexpected token at position %d (got '%r')" % (token.pos, token)) for token in tokenize(expr): if token.token_type in (TokenType.LPAREN, TokenType.IDENT): stack.append(token) elif token.token_type in (TokenType.FLOAT, TokenType.INT, TokenType.STRING): stack.append(token.data) elif token.token_type == TokenType.RPAREN: args = [] while stack and not (isinstance(stack[-1], Token) and stack[-1].token_type == TokenType.LPAREN): args.append(stack.pop()) if not stack: error(token) lparen = stack.pop() args = tuple(reversed(args)) if not args: error(token) sym = args[0] if not isinstance(sym, Token): error(lparen) assert sym.token_type == TokenType.IDENT if sym.data == "Sum": val = Sum(args[1:]) elif sym.data == "Product": val = Product(args[1:]) elif sym.data == "Power": val = Power(*args[1:]) elif sym.data == "Var": val = Variable(*args[1:]) else: error(sym) stack.append(val) elif token.token_type == TokenType.END: if len(stack) != 1: error(token) if isinstance(stack[0], Token): error(token) return stack[0]
def vec_dot(lvec, rvec): if lvec.shape != rvec.shape: raise ValueError('mismatched dimensions: %s and %s' % (str(lvec.shape), str(rvec.shape))) if lvec.shape[0] != 1 and lvec.shape[0] != 1: raise ValueError("expected vectors, got %s matrix instead" % str(lvec.shape)) lvec, rvec = lvec.flatten(), rvec.flatten() return Sum( tuple(Product((el1, el2)) for el1, el2 in zip(lvec, rvec)))
def __call__(self, array): """ Computes the determinant of array, the given matrix. :param array: a `numpy.ndarray` representing the matrix :return: An expression tree that can be simplified further into the value of the determinant of `array`. :raise TypeError: if not array is not of type `numpy.ndarray` :raise ValueError: if array is not square in shape """ if not isinstance(array, np.ndarray): raise TypeError('expected numpy.ndarray, got %s instead' % str(type(array))) rows, cols = array.shape if rows != cols: raise ValueError('non-square matrix') if rows == 1: return array[0][0] if rows == 2: return Sum((Product((array[0][0], array[1][1])), Product((-array[0][1], array[1][0])))) triu = array[np.triu_indices(rows, k=1)] tril = array[np.tril_indices(rows, k=-1)] if not np.any(triu) or not np.any(tril): # upper or lower triangular matrix return Product(tuple(entry for entry in array.diagonal())) def _minor(arr, i, j): return np.delete(np.delete(arr, i, axis=0), j, axis=1) def _coeff_det(coeff, j): return Product((coeff if j % 2 == 0 else -coeff, Call(self, (_minor(array, 0, j), )))) coeffs = array[0] return Sum(tuple(_coeff_det(c, j) for j, c in enumerate(coeffs)))
def get_neg_product(expr): from pymbolic.primitives import is_zero, Product if isinstance(expr, Product) \ and len(expr.children) and is_zero(expr.children[0]+1): if len(expr.children) == 2: # only the minus sign and the other child return expr.children[1] else: return Product(expr.children[1:]) else: return None
def test_pymbolic_sexprs(): def check_round_trip(expr): assert sexpr_to_pymbolic(pymbolic_to_sexpr(expr)) == expr from pymbolic.primitives import Variable, Sum, Product, Power check_round_trip(Variable("x")) check_round_trip(1) check_round_trip(-11) check_round_trip(1.1) check_round_trip(1.1e-2) check_round_trip(Sum((7, ))) check_round_trip(Sum((1, 2, 3))) check_round_trip( Sum((1, Product((2, 3, Power(1, Sum((Product((-1, 2)), 2))))), 3))) check_round_trip(Product((1, 2, 3))) check_round_trip(Power(1, Variable("x"))) check_round_trip(Power(Power(1, 2), 3)) check_round_trip(Power(1, Power(2, 3))) check_round_trip(Power(Power(Sum((1, 2)), 3), 3.5)) from pymbolic import parse check_round_trip( parse("c_m2l * (40 * ((p_fmm + 1)**2)" "** 1.5 * (p_qbx + 1) ** 0.5 + 1)")) def check_error(expr): with pytest.raises(ParserError): sexpr_to_pymbolic(expr) check_error("") check_error("(") check_error(")") check_error("()") check_error("1 2 3") check_error("(Var ''')") check_error("(Power (Var 'x'") check_error("(Product 1 2) (Sum 1 2)") check_error("(Sum (Sum 1 2) 3") check_error("(Error)") check_error("Sum")
def mat_mul(op1, op2): if not isinstance(op1, np.ndarray) or not isinstance( op2, np.ndarray): return op1 * op2 if op1.shape[1] != op2.shape[0]: # mat1 cols must equal mat2 rows raise ValueError('mismatched dimensions %s and %s' % (str(op1.shape), str(op2.shape))) return np.array( [[Product((el1, el2)) for el1, el2 in zip(row1, row2)] for row1, row2 in zip(op1.transpose(), op2)])
def _coeff_det(coeff, j): return Product((coeff if j % 2 == 0 else -coeff, Call(self, (_minor(array, 0, j), ))))