def form_size(expr: Expr) -> typing.Tuple[Size, typing.Optional[Symbol]]: """Form a size object from a SymPy expression.""" symbs = expr.atoms(Symbol) n_symbs = len(symbs) if n_symbs == 0: symb = None coeff_exprs = [expr] elif n_symbs == 1: symb = symbs.pop() coeff_exprs = Poly(expr, symb).all_coeffs() coeff_exprs.reverse() else: raise ValueError( 'Invalid expression', expr, 'expecting single variate polynomial (or number)' ) if all(i.is_integer for i in coeff_exprs): dtype = int else: dtype = float if len(coeff_exprs) > 1: coeffs = np.array(coeff_exprs, dtype=dtype) cost = SVPoly(coeffs) elif len(coeff_exprs) == 1: cost = dtype(coeff_exprs[0]) else: assert False return cost, symb
def _get_custom_constraint(self, constraint_expr: Expr, condition_template: str) -> Callable[..., Expr]: wilds = list(map(lambda x: x.name, constraint_expr.atoms(_WildAbstract))) lambdaargs = ', '.join(wilds) fullexpr = _get_srepr(constraint_expr) condition = condition_template.format(fullexpr) return matchpy.CustomConstraint( self._get_lambda(f"lambda {lambdaargs}: ({condition})"))
def _get_only_symb(expr: Expr): """Get the only symbol in the given expression. The expression has to have only one symbol. """ symbols = expr.atoms(Symbol) assert len(symbols) == 1 return symbols.pop()
def round_expr(self, expr: sympy.Expr, num_digits: int) -> sympy.Expr: """ Rounds all the numbers in a SymPy expression. This is useful for pretty-printing. :param expr: SymPy expression to round. :param num_digits: number of digits to leave. :return: expression with rounded numbers. """ return expr.xreplace( {n: round(n, num_digits) for n in expr.atoms(sympy.Number)})
def __call__(self, expr: Expr): """Try to resolve an expression.""" known = self._known if self._strict: if expr in known: return known[expr] else: for i in expr.atoms(Symbol): if i in known: return known[i] continue return None
def get_cost_key(cost: Expr) -> typing.Tuple[int, typing.List[Expr]]: """Get the key for ordering the cost. The cost should be a polynomial of at most one undetermined variable. The result gives ordering of the cost agreeing with our common sense. """ symbs = cost.atoms(Symbol) n_symbs = len(symbs) if n_symbs == 0: return 0, [cost] elif n_symbs == 1: symb = symbs.pop() coeffs = Poly(cost, symb).all_coeffs() return len(coeffs) - 1, coeffs else: raise ValueError('Invalid cost to compare', cost, 'expecting univariate polynomial or number')
def __sub__(self, other: Expr): """Subtract the current value with another. This method is mainly to be able to work together with the Kronecker delta class from SymPy. The difference is only guaranteed to have correct ``is_zero`` property. The actual difference might not make mathematical sense. """ if isinstance(other, type(self)): return self.args[0] - other.args[0] elif len(other.atoms(Symbol)) == 0: raise ValueError( 'Invalid operation for ', (self, other), 'concrete symbols can only be subtracted for the same type') else: # We are having a symbolic value at the other expression. We just # need to make sure that the result is fuzzy. assert other.is_zero is None return other
def __init__(self, f: Expr, g: Expr): self.f = f self.g = g x = sorted(f.atoms(), key=lambda s: s.name) self.m = m = len(g) self.n = len(x) l = array_sym("lambda", m) s = Symbol("obj_factor") L = s * f + sum(l_i * g_i for l_i, g_i in zip(l, g)) """Lagrangian""" jac_g = [[g_i.diff(x_i) for x_i in x] for g_i in g] jac_g_sparse, jac_g_sparsity_indices = sparsify(jac_g) h = [[dL.diff(x_j) for x_j in x] for dL in [L.diff(x_i) for x_i in x]] h_sparse, h_sparsity_indices = sparsify(ll_triangular(h)) self.grad_f = [f.diff(x_i) for x_i in x] self.jac_g = jac_g_sparse self.h = h_sparse self.h_sparsity_indices = transpose(h_sparsity_indices) self.jac_g_sparsity_indices = transpose(jac_g_sparsity_indices)
def _round_sympy_expr(expr: sympy.Expr, num_digits: int = 4) -> sympy.Expr: return expr.xreplace( {n: round(n, num_digits) for n in expr.atoms(sympy.Number)})
def common_denominator(expr: sp.Expr) -> sp.Expr: """Finds least common multiple of all denominators occurring in an expression""" denominators = [r.q for r in expr.atoms(sp.Rational)] return sp.lcm(denominators)
def check_max_constant(sympy_expr: sympy.Expr, options: dict) -> bool: """Check whether the expression contains constant that is higher than allowed""" for atom in sympy_expr.atoms(): if atom.is_real and abs(atom) > options['max_constant_allowed']: return False return True
def round_expr(self, expr: sympy.Expr, num_digits: int) -> sympy.Expr: return expr.xreplace( {n: round(n, num_digits) for n in expr.atoms(sympy.Number)})
def from_twoform(twoform: Expr): """Create a CoordSystem from a sympy.Expr that represents a metric as a twoform by extracting the coordinates from the given metric (reversing this dependency) """ cs = twoform.atoms(_CoordSystem).pop() return CoordSystem.from_sympy_coordsystem(cs)