Example #1
0
    def add_formula(self, formula: sp.Expr, coordinate):
        """
        Add a formula to serendipity interpolation method.
        :param formula: the formula to add.
        :param coordinate: the coordinate of the interpolation function.
        :return:
        """
        # Save the point for later usage.
        self.points.append(coordinate)

        # Convert the coordinate tuple to the dictionary for sympy subs.
        coordinate = utils.get_coordinate_sub_dict(self.axises, coordinate)

        # Deal with correlation.
        formula = formula.subs(self.correlation)

        # Normalize the new formula.
        formula = formula / formula.subs(coordinate)

        # Each old formula should minus the new one.
        # This is the core operation of serendipity interpolation method.
        self.formulas = [
            f - formula * f.subs(coordinate) for f in self.formulas
        ]

        # Add the new formula to formula list.
        self.formulas.append(formula)

        # Make all formulas more readable, by doing factors.
        self.formulas = [f.factor() for f in self.formulas]
Example #2
0
def round_nested(expression: sp.Expr, n_decimals: int) -> sp.Expr:
    for node in sp.preorder_traversal(expression):
        if node.free_symbols:
            continue
        if isinstance(node, (float, sp.Float)):
            expression = expression.subs(node, round(node, n_decimals))
        if isinstance(node, sp.Pow) and node.args[1] == 1 / 2:
            expression = expression.subs(node, round(node.n(), n_decimals))
    return expression
Example #3
0
def simplify_deriv_notation(expr: Expr,
                            metric: Metric,
                            max_order: int = 2,
                            use_dots: bool = False):
    """Utility for Simplifying LaTeX representation of a sympy Expression via substitutions. Note
    that this function simplifies the LaTeX output of the Expr at the cost of the Expr semantics,
    only use this after all operations on the Expr (including simplification) have been performed.

    Args:
        expr:
            Expr, the sympy expression
        metric:
            Metric, the metric containing components whose derivatives will be simplified
        max_order:
            int, default 2, the max derivative order to replace
        use_dots:
            bool, default False. If True use dot notation for derivatives of single-variable functions

    Returns:
        Expr, the modified expression. Recall this is only useful for LaTeX conversion, not semantically valid in sympy.
    """
    # Create Simplification Shorthand
    components = tuple(sorted(metric.components, key=lambda x: x.name))
    variables = metric.coord_system.base_symbols()
    rules = []
    for n in range(1, max_order + 1):
        n_order_rules = [
            _deriv_simplify_rule(c, vs, use_dots=use_dots)
            for c, vs in itertools.product(
                components, itertools.product(*(n * [variables])))
        ]
        rules.extend(n_order_rules)
    return expr.subs(dict(rules))
Example #4
0
def expend_cos(expr: Expr, x: Symbol) -> Tuple[Expr, Expr]:
    while True:
        term = expr.subs(x, pi / 2)
        yield term
        expr = cancel((expr - term) / cos(x))
        if expr == 0:
            return
Example #5
0
def evaluate_sympylike(sympy_eqn: sympy.Expr,
                       numbers: List[dict] = None) -> sympy.Expr:
    """
    Evaluate sympy-like expressions and compute/simplify its value using sympy.
    Using this function, we replace dummy operations into functions in sympy.

    :param sympy.Expr sympy_eqn: Expression to be evaluated.
    :param List[dict] numbers: List of dictionaries, which contain information about the numbers
    :rtype: sympy.Expr
    :return: Expression without dummy operations.
    """
    # Replace constant placeholders.
    symbols = sympy_eqn.free_symbols
    constant_map = {}
    for item in symbols:
        if _is_constant_string(item.name):
            name = item.name[len(CON_PREFIX):]
            positive = True
            if name.endswith('_NEG'):
                positive = False
                name = name[:-4]

            if name == 'pi':
                value = sympy.pi
            elif name == 'e':
                value = sympy.E
            else:
                value = float(name.replace('_', '.'))

            constant_map[item] = value if positive else -value

    # Apply special symbols.
    constant_map.update({'pi': sympy.pi, 'e': sympy.E})

    # Substitute constants.
    sympy_eqn = sympy_eqn.subs(constant_map)

    # Replace numbers(N0, N1, ..., T0, T1, ...)
    if numbers:
        number_map = {
            FORMAT_NUM % i: eval(item['value'])
            for i, item in enumerate(numbers)
        }
        sympy_eqn = sympy_eqn.subs(_wrap_key_as_symbol(number_map))

    return sympy_eqn
Example #6
0
def equalize_symbol(sym: sympy.Expr) -> sympy.Expr:
    """
    If a symbol or symbolic expressions has multiple symbols with the same
    name, it substitutes them with the last symbol (as they appear in
    s.free_symbols).
    """
    symdict = {s.name: s for s in sym.free_symbols}
    repldict = {s: symdict[s.name] for s in sym.free_symbols}
    return sym.subs(repldict)
Example #7
0
    def _expr_to_tensor(self, expr: sympy.Expr, result_units: sympy.Expr,
                        tf_symbols: typing.Dict[str, tf.Tensor]):
        # Do unit convertions
        # First, scale all input symbols to SI base units
        expr = expr.subs([(s.symbol, s.symbol * si_dimension_scale(s.units))
                          for s in self.symbols.values()])
        expr = expr / si_dimension_scale(
            result_units)  # Convert the result to the desired units

        # Make it into a tf.Tensor
        tf_lambda = sympy.lambdify(expr.free_symbols, expr, "tensorflow")
        return tf_lambda(*[tf_symbols[s.name] for s in expr.free_symbols])
Example #8
0
def get_symmetric_part(expr: sp.Expr, symbols: Iterable[sp.Symbol]) -> sp.Expr:
    """
    Returns the symmetric part of a sympy expressions.

    Args:
        expr: sympy expression, labeled here as :math:`f`
        symbols: sequence of symbols which are considered as degrees of freedom, labeled here as :math:`x_0, x_1,...`

    Returns:
        :math:`\frac{1}{2} [ f(x_0, x_1, ..) + f(-x_0, -x_1) ]`
    """
    substitution_dict = {e: -e for e in symbols}
    return sp.Rational(1, 2) * (expr + expr.subs(substitution_dict))
Example #9
0
def equalize_symbols(a: sympy.Expr,
                     b: sympy.Expr) -> Tuple[sympy.Expr, sympy.Expr]:
    """
    If the 2 input expressions use different symbols but with the same name,
    it substitutes the symbols of the second expressions with those of the
    first expression.
    """
    a = equalize_symbol(a)
    b = equalize_symbol(b)
    a_syms = {s.name: s for s in a.free_symbols}
    b_syms = {s.name: s for s in b.free_symbols}
    common_names = set(a_syms.keys()).intersection(set(b_syms.keys()))
    if common_names:
        repldict = dict()
        for name in common_names:
            repldict[b_syms[name]] = a_syms[name]
        b = b.subs(repldict)
    return a, b
Example #10
0
 def resolve_bottom_decisions(self, expr: sympy.Expr,
                              beta_point: float) -> Tuple[sympy.Expr, bool]:
     if type(expr) in [
             sympy.Float, sympy.Integer, sympy.numbers.NegativeOne,
             sympy.Symbol
     ]:
         return expr, True
     if type(expr) in [sympy.Heaviside, sympy.Max]:
         return expr.subs(self.beta, beta_point).simplify(), False
     all_args_plain = True
     arg_expressions = []
     for arg in expr.args:
         arg_expr, arg_plain = self.resolve_bottom_decisions(
             arg, beta_point)
         arg_expressions += [arg_expr]
         all_args_plain = all_args_plain and arg_plain
     #print(type(expr), arg_expressions)
     return type(expr)(*arg_expressions), all_args_plain
Example #11
0
def smart_subs(element: sp.Expr, old: sp.Symbol, new: sp.Expr) -> sp.Expr:
    """
    Optimized substitution that checks whether anything needs to be done first

    :param element:
        substitution target

    :param old:
        to be substituted

    :param new:
        subsitution value

    :return:
        substituted expression
    """

    if old in element.free_symbols:
        return element.subs(old, new)

    return element
Example #12
0
 def resolve_bottom_decisions(self, expr: sympy.Expr,
                              beta_point: float) -> sympy.Expr:
     """
     Resolve "bottom" Heaviside/Max subexpressions of an expression - the ones whose subexpressions
     are linear.   
     :param expr: expression to be simplified.
     :param beta_point: value of the parameter for which the expression is simplified.
     :return: expr with "bottom" subexpressions simplified.
     """
     if type(expr) in [
             sympy.Float, sympy.Integer, sympy.numbers.NegativeOne,
             sympy.Symbol
     ]:
         return expr
     if type(expr) in [sympy.Heaviside, sympy.Max]:
         return expr.subs(self.beta, beta_point).simplify()
     arg_expressions = [
         self.resolve_bottom_decisions(arg, beta_point) for arg in expr.args
     ]
     #print(type(expr), arg_expressions)
     return type(expr)(*arg_expressions)
Example #13
0
def complete_the_square(expr: sp.Expr, symbol_to_complete: sp.Symbol,
                        new_variable: sp.Symbol) -> Tuple[sp.Expr, Optional[Tuple[sp.Symbol, sp.Expr]]]:
    """Transforms second order polynomial into only squared part.

    Examples:
        >>> a, b, c, s, n = sp.symbols("a b c s n")
        >>> expr = a * s**2 + b * s + c
        >>> completed_expr, substitution = complete_the_square(expr, symbol_to_complete=s, new_variable=n)
        >>> completed_expr
        a*n**2 + c - b**2/(4*a)
        >>> substitution
        (n, s + b/(2*a))

    Returns:
        (replaced_expr, tuple to pass to subs, such that old expr comes out again)
    """
    p = sp.Poly(expr, symbol_to_complete)
    coefficients = p.all_coeffs()
    if len(coefficients) != 3:
        return expr, None
    a, b, _ = coefficients
    expr = expr.subs(symbol_to_complete, new_variable - b / (2 * a))
    return sp.simplify(expr), (new_variable, symbol_to_complete + b / (2 * a))
Example #14
0
def _subs_const_values(expr: Expr,
                       unit_system: UnitSystem = UnitSystem.SI) -> Expr:
    """Substitute any ConstantSymbols in an Expression with their value in a particular
    system of units

    Args:
        expr:
            Expr, the sympy expression in which to substitute constant symbols for values
        unit_system:
            UnitType, default SI. The system of units in which to evaluate constants

    Returns:
        Expr, the substituted expression
    """
    # Ensure unit_system is UnitType
    if not isinstance(unit_system, UnitSystem):
        unit_system = UnitSystem(unit_system)

    # Determine the free symbols that are ConstantSymbols
    const_syms = tuple(
        sorted({s
                for s in expr.free_symbols if isinstance(s, ConstantSymbol)},
               key=lambda s: s.name))

    # Check if using Natural units that all are natural unit capable
    if unit_system == UnitSystem.NATURAL and not all(s.is_natural_unit
                                                     for s in const_syms):
        raise ValueError(
            'Cannot substitute natural units for the following ConstantSymbols: {}'
            .format(', '.join(
                [str(s) for s in const_syms if not s.is_natural_unit])))

    # Build substitution dictionary
    sub_rules = [(s, getattr(s, unit_system.value).value) for s in const_syms]

    # Perform substitution and return
    return expr.subs(sub_rules)
Example #15
0
def smart_subs_dict(sym: sp.Expr,
                    subs: SymbolDef,
                    field: Optional[str] = None,
                    reverse: bool = True) -> sp.Expr:
    """
    Subsitutes expressions completely flattening them out. Requires
    sorting of expressions with toposort.

    :param sym:
        Symbolic expression in which expressions will be substituted

    :param subs:
        Substitutions

    :param field:
        Field of substitution expressions in subs.values(), if applicable

    :param reverse:
        Whether ordering in subs should be reversed. Note that substitution
        requires the reverse order of what is required for evaluation.

    :return:
        Substituted symbolic expression
    """
    s = [
        (eid, expr[field] if field is not None else expr)
        for eid, expr in subs.items()
    ]
    if reverse:
        s.reverse()
    for substitution in s:
        # note that substitution may change free symbols, so we have to do
        # this recursively
        if substitution[0] in sym.free_symbols:
            sym = sym.subs(*substitution)
    return sym
Example #16
0
 def substitute(self, expression: sympy.Expr, substitutions: dict):
     for key, value in substitutions.items():
         if not isinstance(value, sympy.Expr):
             substitutions[key] = sympy.sympify(value)
     return expression.subs(substitutions, simultaneous=True).doit()
Example #17
0
def _sub_symbols_in_expression(
        parameter: sympy.Expr, symbols_map: Dict[sympy.Symbol,
                                                 Parameter]) -> sympy.Expr:
    return parameter.subs(symbols_map)
Example #18
0
 def _apply_substitutions(self, expr: sp.Expr) -> sp.Expr:
     for left, right in map(lambda eq: eq.args,
                            self._substitution_equations):
         expr = expr.subs(right, left)
     return expr
Example #19
0
def amp_and_shift(expr: Expr, x: Symbol) -> Tuple[Expr, Expr]:
    amp = simplify(cancel(sqrt(expr**2 + expr.diff(x)**2).subs(x, 0)))
    shift = arg(expr.subs(x, 0) + I * expr.diff(x).subs(x, 0))
    return amp, shift