Ejemplo n.º 1
0
    def get_xy_ref(self):
        '''
        Gets x in function of 'xi' and 'eta'
        Gets y in function of 'xi; and 'eta'

        X is the Sum of N_i * X_i for each node of the element.
        Y is the Sum of N_i * Y_i for each node of the element.
        '''
        if self.Ne_ref is None:
            self.get_Ne_ref()

        x_coord = 0
        y_coord = 0

        for i in range(self.num_nodes):
            x_coord = x_coord + (self.nodes[i].x * self.Ne_ref[i])
            y_coord = y_coord + (self.nodes[i].y * self.Ne_ref[i])

        for i in sy.preorder_traversal(x_coord):
            if isinstance(i, sy.Float) and abs(i) < 1e-10:
                x_coord = x_coord.subs(i, round(i, 1))
            elif isinstance(i, sy.Float):
                x_coord = x_coord.subs(i, round(i, 15))

        for i in sy.preorder_traversal(y_coord):
            if isinstance(i, sy.Float) and abs(i) < 1e-10:
                y_coord = y_coord.subs(i, round(i, 1))
            elif isinstance(i, sy.Float):
                y_coord = y_coord.subs(i, round(i, 15))

        self.x_coord = x_coord
        self.y_coord = y_coord
 def checkanswer(self, user_answer):
     user_answer = user_answer.lower()
     user_answer = user_answer.replace('^', '**')
     user_answer = parse_expr(user_answer, transformations=transformations, evaluate=False)
     print('user stuff', user_answer, type(user_answer))
     if isinstance(user_answer, sy.Pow):
         if user_answer.args[1] == -1:
             # print('My fault!')
             print(user_answer.args)
             if isinstance(user_answer.args[0], sy.Pow):
                 user_base = user_answer.args[0].args[0]
                 user_expo = -user_answer.args[0].args[1]
                 user_answer = sy.Pow(user_base, sy.simplify(user_expo), evaluate=False)
                 print('alt', user_answer, type(user_answer))
                 for arg in sy.preorder_traversal(user_answer):
                     print(arg)
         else:
             user_base = user_answer.args[0]
             user_expo = user_answer.args[1]
             user_answer = sy.Pow(user_base, sy.simplify(user_expo), evaluate=False)
             print('standard', user_answer, type(user_answer))
             for arg in sy.preorder_traversal(user_answer):
                 print(arg)
     print('self.answer', self.answer)
     answer = self.answer
     # answer = parse_expr(str(self.answer), transformations=transformations)
     print('answer stuff', answer, type(answer))
     for arg in sy.preorder_traversal(answer):
         print(arg)
     return user_answer == answer
Ejemplo n.º 3
0
def cse_postprocess(cse_output):
    replaced, reduced = cse_output
    i = 0
    while i < len(replaced):
        sym, expr = replaced[i]
        # Search through replaced expressions for negative symbols
        if (expr.func == sp.Mul and len(expr.args) == 2 and \
                any((arg.func == sp.Symbol) for arg in expr.args) and \
                any((arg == sp.S.NegativeOne or '_NegativeOne_' in str(arg)) for arg in expr.args)):
            for k in range(i + 1, len(replaced)):
                if sym in replaced[k][1].free_symbols:
                    replaced[k] = (replaced[k][0],
                                   replaced[k][1].subs(sym, expr))
            for k in range(len(reduced)):
                if sym in reduced[k].free_symbols:
                    reduced[k] = reduced[k].subs(sym, expr)
            # Remove the replaced expression from the list
            replaced.pop(i)
            if i != 0: i -= 1
        # Search through replaced expressions for addition/product of 2 or less symbols
        if ((expr.func == sp.Add or expr.func == sp.Mul) and 0 < len(expr.args) < 3 and \
                all((arg.func == sp.Symbol or arg.is_integer or arg.is_rational) for arg in expr.args)) or \
                (expr.func == sp.Pow and expr.args[0].func == sp.Symbol and expr.args[1] == 2):
            sym_count = 0  # Count the number of occurrences of the substituted symbol
            for k in range(len(replaced) - i):
                # Check if the substituted symbol appears in the replaced expressions
                if sym in replaced[i + k][1].free_symbols:
                    for arg in sp.preorder_traversal(replaced[i + k][1]):
                        if arg.func == sp.Symbol and str(arg) == str(sym):
                            sym_count += 1
            for k in range(len(reduced)):
                # Check if the substituted symbol appears in the reduced expression
                if sym in reduced[k].free_symbols:
                    for arg in sp.preorder_traversal(reduced[k]):
                        if arg.func == sp.Symbol and str(arg) == str(sym):
                            sym_count += 1
            # If the number of occurrences of the substituted symbol is 2 or less, back-substitute
            if 0 < sym_count < 3:
                for k in range(i + 1, len(replaced)):
                    if sym in replaced[k][1].free_symbols:
                        replaced[k] = (replaced[k][0],
                                       replaced[k][1].subs(sym, expr))
                for k in range(len(reduced)):
                    if sym in reduced[k].free_symbols:
                        reduced[k] = reduced[k].subs(sym, expr)
                # Remove the replaced expression from the list
                replaced.pop(i)
                i -= 1
        i += 1
    return replaced, reduced
Ejemplo n.º 4
0
def get_index_derivatives(expr):
    """
    """
    coord = ['x', 'y', 'z']

    d = OrderedDict()
    for c in coord:
        d[c] = 0

    ops = [
        a for a in preorder_traversal(expr)
        if isinstance(a, _partial_derivatives)
    ]
    for i in ops:
        op = type(i)

        if isinstance(i, dx):
            d['x'] += 1

        elif isinstance(i, dy):
            d['y'] += 1

        elif isinstance(i, dz):
            d['z'] += 1

    return d
Ejemplo n.º 5
0
def get_index_logical_derivatives(expr):
    """
    """
    coord = ['x1', 'x2', 'x3']

    d = OrderedDict()
    for c in coord:
        d[c] = 0

    ops = [
        a for a in preorder_traversal(expr)
        if isinstance(a, _logical_partial_derivatives)
    ]
    for i in ops:
        op = type(i)

        if isinstance(i, dx1):
            d['x1'] += 1

        elif isinstance(i, dx2):
            d['x2'] += 1

        elif isinstance(i, dx3):
            d['x3'] += 1

    return d
Ejemplo n.º 6
0
def gelatize(expr, dim):
    # ... in the case of a Lambda expression
    args = None
    if isinstance(expr, Lambda):
        args = expr.variables
        expr = expr.expr
    # ...

    # ... we first need to find the ordered list of generic operators
    ops = [a for a in preorder_traversal(expr) if isinstance(a, _generic_ops)]
    # ...

    # ...
    for i in ops:
        # if i = Grad(u) then type(i) is Grad
        op = type(i)

        new = eval('{0}_{1}d'.format(op, dim))
        expr = expr.subs(op, new)
    # ...

    if args:
        return Lambda(args, expr)
    else:
        return expr
Ejemplo n.º 7
0
def filter_expr2(expr, threshold=0.01):
    """Sets all constants under threshold to 0
    TODO: Test"""
    for a in sym.preorder_traversal(expr):
        if isinstance(a, sym.Float) and a < threshold:
            expr = expr.subs(a, 0)
    return expr
Ejemplo n.º 8
0
 def _eval_is_zero(self):
     if self.shape:
         return 
     
     if len(self.args) == 2:
         if self.is_extended_real:
             if self.min().is_extended_positive:
                 return False
             if self.max().is_extended_negative:
                 return False    
     
     from sympy import preorder_traversal, KroneckerDelta 
     delta = None
     for arg in preorder_traversal(self):
         if isinstance(arg, KroneckerDelta):
             delta = arg
             break
         
     if delta is not None:
         #to prevent infinite loop!
         this = self._subs(delta, S.Zero)
         if this is self:
             return 
         delta0 = this.is_zero
         
         this = self._subs(delta, S.One)
         if this is self:
             return             
         delta1 = this.is_zero
         if delta0 and delta1:
             return True
         if delta0 == False and delta1 == False:
             return False
def round_sympy_expr(expr, decimals):
    """Returns the expression with every float rounded to the given number of decimals."""
    rounded_expr = expr
    for a in sympy.preorder_traversal(expr):
        if isinstance(a, sympy.Float):
            rounded_expr = rounded_expr.subs(a, round(a, decimals))
    return rounded_expr
Ejemplo n.º 10
0
def traversal(expr):
    """Traverse sympy expression tree
    Args:
        expr (sympy expression)
    """

    return list(preorder_traversal(expr))
Ejemplo n.º 11
0
def round_sympy_expr(expr, decimals):
    """Returns the expression with every float rounded to the given number of decimals."""
    rounded_expr = expr
    for a in sympy.preorder_traversal(expr):
        if isinstance(a, sympy.Float):
            rounded_expr = rounded_expr.subs(a, round(a, decimals))
    return rounded_expr
Ejemplo n.º 12
0
def expr_to_infix(expr, mul_add_arity_fixed=False):
    """
    Returns preorder traversal of the symbolic expression
    """

    pre = []
    pre_arity = []

    for expr_node in snp.preorder_traversal(expr):
        if expr_node.func.is_symbol:
            pre.append(expr_node.name)
            pre_arity.append(len(expr_node.args))
        elif expr_node.is_Function or expr_node.is_Add or expr_node.is_Mul or expr_node.is_Pow:
            if mul_add_arity_fixed and (expr_node.is_Add or expr_node.is_Mul):
                for i in range(len(expr_node.args) - 1):
                    pre_arity.append(2)
                    pre.append(type(expr_node).__name__)
            else:
                pre_arity.append(len(expr_node.args))
                pre.append(type(expr_node).__name__)
        elif expr_node.is_constant():
            pre.append(float(expr_node))
            post_arity.append(len(expr_node.args))

    return pre, pre_arity
Ejemplo n.º 13
0
 def _extract_advection(self, order_dict):
     node = Add(*flatten(order_dict.itervalues()))
     divs = filter(lambda x: isinstance(x, div), preorder_traversal(node))
     div_args = map(lambda d: d.args[0], divs)
     split_div_args = flatten(map(self._split_on_add, div_args))
     div_args = filter(lambda n: not self._has_grad(n), split_div_args)
     return Add(*div_args)
Ejemplo n.º 14
0
def traversal(expr):
    '''Traverse sympy expression tree
    Args:
        expr (sympy expression)
    '''

    return list(preorder_traversal(expr))
Ejemplo n.º 15
0
def to_monomials(expr):
    try:
        e = expr.expand()
    except Exception:
        if hasattr(expr, 'copy'):
            e = expr.copy()
        else:
            e = expr
    
    while True:
        has_change = False
        for x in preorder_traversal(e):
            # print("Doing %s" % str(x))
            if hasattr(x, 'is_Mul') and x.is_Mul:
                # print("here")
                for i, y in enumerate(x.args):
                    if hasattr(y, 'is_Add') and y.is_Add and\
                       noncommutative(y.args):
                        if i == 0:
                            terms = add_list_head(y.args, x.args[1:])
                        elif i == len(y.args)-1:
                            terms = add_list_tail(y.args, x.args[:-1])
                        else:
                            terms = add_list_middle(
                                y.args, x.args[:i], x.args[i+1:])
                        enew = e.xreplace({x: terms})
                        if enew != e:
                            has_change = True
                            e = enew
                        break
            if has_change:
                break
        if not has_change:
            break
    return e
Ejemplo n.º 16
0
 def _extract_advection(self, order_dict):
     node = Add(*flatten(order_dict.itervalues()))
     divs = filter(lambda x: isinstance(x, div), preorder_traversal(node))
     div_args = map(lambda d: d.args[0], divs)
     split_div_args = flatten(map(self._split_on_add, div_args))
     div_args = filter(lambda n: not self._has_grad(n), split_div_args)
     return Add(*div_args)
def _conditional_replace(expr, condition, replacement):
    for x in preorder_traversal(expr):
        try:
            if condition(x):
                expr = expr.xreplace({x: replacement(x)})
        except AttributeError:  # scalar ops like Add won't have is_Trace
            pass
    return expr
def contain_exp(expr):
    """ Return True if expression contains the exponential operator.
    """
    for arg in sym.preorder_traversal(expr):
        # check if there is an exponential function
        if arg.func == sym.exp:
            return True
    return False
Ejemplo n.º 19
0
 def _extract_potential(self, order_dict):
     second_order = order_dict.get(2, 0)
     div_grads = filter(self._is_div_grad, preorder_traversal(second_order))
     div_grad_args = map(lambda d: d.args[0], div_grads)
     potentials = flatten((map(self._find_grad_args, div_grad_args)))
     if len(potentials) == 1:
         potentials = potentials[0]
     return potentials
Ejemplo n.º 20
0
def tree_size(eq):
    i = 0
    for e in sympy.preorder_traversal(self.expr):
        if e.is_Integer:
            i += int(abs(e))
            continue
        i += 1
    return i
def symbolic_equal(expression1, expression2, x, mu):
    locals = {"x": x, "mu": mu}
    difference = sympify(expression1, locals=locals) - sympify(expression2, locals=locals)
    difference = simplify(difference)
    for node in preorder_traversal(difference):
        if isinstance(node, Float):
            difference = difference.subs(node, round(node, 10))
    return difference == 0
Ejemplo n.º 22
0
def tree_size(eq):
	i = 0
	for e in sympy.preorder_traversal(self.expr):
		if e.is_Integer:
			i += int(abs(e))
			continue
		i+=1
	return i
Ejemplo n.º 23
0
 def _extract_potential(self, order_dict):
     second_order = order_dict.get(2, 0)
     div_grads = filter(self._is_div_grad, preorder_traversal(second_order))
     div_grad_args = map(lambda d: d.args[0], div_grads)
     potentials = flatten((map(self._find_grad_args, div_grad_args)))
     if len(potentials) == 1:
         potentials = potentials[0]
     return potentials
Ejemplo n.º 24
0
def count_occurrences2(expr):
    """
    Count atom occurrences in an expression.
    """
    result = {}
    for sub_expr in sp.preorder_traversal(expr):
        if sub_expr.is_Atom:
            result[sub_expr] = result.get(sub_expr, 0) + 1
    return result
Ejemplo n.º 25
0
        def exprIsPositive(expr):
            '''This function is *incredibly* sketchy. It sometimes determines 
            whether an expression is positive or negative. It's true for "x*y" 
            and false for "-x*y".'''

            for a in preorder_traversal(expr):
                if issubclass(a.func, Number):
                    if a < 0:
                        return False
Ejemplo n.º 26
0
    def generate_propagator_solver(self, output_timestep_symbol="__h"):
        r"""
        Generate the propagator matrix and symbolic expressions for propagator-based updates; return as JSON.
        """
        #
        #   generate the propagator matrix
        #

        P = sympy.simplify(sympy.exp(self.A_ * sympy.Symbol(output_timestep_symbol)))

        if sympy.I in sympy.preorder_traversal(P):
            raise PropagatorGenerationException("The imaginary unit was found in the propagator matrix. This can happen if the dynamical system that was passed to ode-toolbox is unstable, i.e. one or more state variables will diverge to minus or positive infinity.")

        #
        #   generate symbols for each nonzero entry of the propagator matrix
        #

        P_sym = sympy.zeros(*P.shape)   # each entry in the propagator matrix is assigned its own symbol
        P_expr = {}     # the expression corresponding to each propagator symbol
        update_expr = {}    # keys are str(variable symbol), values are str(expressions) that evaluate to the new value of the corresponding key
        for row in range(P_sym.shape[0]):
            if not _is_zero(self.c_[row]):
                raise PropagatorGenerationException("For symbol " + str(self.x_[row]) + ": nonlinear part should be zero for propagators")

            if not _is_zero(self.b_[row]) and self.shape_order_from_system_matrix(row) > 1:
                raise PropagatorGenerationException("For symbol " + str(self.x_[row]) + ": higher-order inhomogeneous ODEs are not supported")

            update_expr_terms = []
            for col in range(P_sym.shape[1]):
                if not _is_zero(P[row, col]):
                    sym_str = "__P__{}__{}".format(str(self.x_[row]), str(self.x_[col]))
                    P_sym[row, col] = sympy.parsing.sympy_parser.parse_expr(sym_str, global_dict=Shape._sympy_globals)
                    P_expr[sym_str] = P[row, col]
                    if _is_zero(self.b_[row]):
                        # homogeneous ODE
                        update_expr_terms.append(sym_str + " * " + str(self.x_[col]))
                    else:
                        # inhomogeneous ODE
                        particular_solution = -self.b_[row] / self.A_[row, row]
                        update_expr_terms.append(sym_str + " * (" + str(self.x_[col]) + " - (" + str(particular_solution) + "))" + " + (" + str(particular_solution) + ")")

            update_expr[str(self.x_[row])] = " + ".join(update_expr_terms)
            update_expr[str(self.x_[row])] = sympy.parsing.sympy_parser.parse_expr(update_expr[str(self.x_[row])], global_dict=Shape._sympy_globals)
            if not _is_zero(self.b_[row]):
                # only simplify in case an inhomogeneous term is present
                update_expr[str(self.x_[row])] = sympy.simplify(update_expr[str(self.x_[row])])

        all_state_symbols = [str(sym) for sym in self.x_]

        initial_values = {sym: str(self.get_initial_value(sym)) for sym in all_state_symbols}

        solver_dict = {"propagators": P_expr,
                       "update_expressions": update_expr,
                       "state_variables": all_state_symbols,
                       "initial_values": initial_values}

        return solver_dict
Ejemplo n.º 27
0
 def exprIsPositive(expr):
     '''This function is *incredibly* sketchy. It sometimes determines 
     whether an expression is positive or negative. It's true for "x*y" 
     and false for "-x*y".'''
 
     for a in preorder_traversal(expr):
         if issubclass(a.func,Number):
             if a<0:
                 return False
Ejemplo n.º 28
0
def list_indices(expr):
    "Gathers the list of pulse indices present in expr. Returns a sorted list"
    return sorted(
        list(
            set(
                chain(*[
                    map(abs, a.k) for a in sy.preorder_traversal(expr)
                    if isinstance(a, Signal)
                ]))))
Ejemplo n.º 29
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
Ejemplo n.º 30
0
 def _is_div_grad(node):
     """Returns true node is a div with a grad argument inside"""
     is_div = isinstance(node, div)
     div_grad = False
     if is_div:
         for arg in preorder_traversal(node.args[0]):
             if isinstance(arg, grad):
                 div_grad = True
                 break
     return div_grad
Ejemplo n.º 31
0
 def _is_div_grad(node):
     """Returns true node is a div with a grad argument inside"""
     is_div = isinstance(node, div)
     div_grad = False
     if is_div:
         for arg in preorder_traversal(node.args[0]):
             if isinstance(arg, grad):
                 div_grad = True
                 break
     return div_grad
Ejemplo n.º 32
0
def round_and_simplify(stuff):
    simplified_stuff = simplify(stuff)
    rounded_stuff = simplified_stuff

    for a in preorder_traversal(rounded_stuff):
        if isinstance(a, Float):
            rounded_stuff = rounded_stuff.subs(a, round(a, 10))

    rounded_and_simplified_stuff = simplify(rounded_stuff)
    return rounded_and_simplified_stuff
Ejemplo n.º 33
0
def round_and_simplify(stuff):
    simplified_stuff = simplify(stuff)
    rounded_stuff = simplified_stuff

    for a in preorder_traversal(rounded_stuff):
        if isinstance(a, Float):
            rounded_stuff = rounded_stuff.subs(a, round(a, 10))

    rounded_and_simplified_stuff = simplify(rounded_stuff)
    return rounded_and_simplified_stuff
Ejemplo n.º 34
0
def extract_funcs(expr):
    """
    Given a sympy expression, return a tuple of all the functions contained
    within that expression.
    """
    functions = set()
    for arg in preorder_traversal(expr):
        if isinstance(arg, Function):
            functions.add(arg)
    return tuple(functions)
Ejemplo n.º 35
0
 def calc_tree_size(self):
     i = 0
     p = 0
     for e in sympy.preorder_traversal(self.expr):
         if e.is_Integer:
             i += int(abs(e))
             continue
         if e.is_Function:
             p += 2  # add an extra penalty
         i += 1
     return i, i + p
Ejemplo n.º 36
0
def dse_dimensions(expr):
    """
    Collect all function dimensions used in a sympy expression.
    """
    dimensions = []

    for e in preorder_traversal(expr):
        if isinstance(e, SymbolicData):
            dimensions += [i for i in e.indices if i not in dimensions]

    return dimensions
Ejemplo n.º 37
0
 def calc_jac_size(self):
     i, p = 0, 0
     for jac in self.jac:
         for e in sympy.preorder_traversal(jac):
             if e.is_Integer:
                 i += int(abs(e))
                 continue
             if e.is_Function:
                 p += 2  # add an extra penalty
             i += 1
     return i, i + p
Ejemplo n.º 38
0
	def calc_tree_size(self):
		i = 0
		p = 0
		for e in sympy.preorder_traversal(self.expr):
			if e.is_Integer:
				i += int(abs(e))
				continue
			if e.is_Function:
				p += 2  # add an extra penalty
			i+=1
		return i, i+p
Ejemplo n.º 39
0
	def calc_jac_size(self):
		i,p = 0,0
		for jac in self.jac:
			for e in sympy.preorder_traversal(jac):
				if e.is_Integer:
					i += int(abs(e))
					continue
				if e.is_Function:
					p += 2  # add an extra penalty
				i+=1
		return i, i+p
def indexed_terms_appearing_in(term, indexed, only_subscripts=False, do_traversal=False):

    indexed_terms_set = set()

    for subterm in preorder_traversal(term) if do_traversal else flatten(term.args, cls=Add):
        try:
            with bind_Mul_indexed(subterm, indexed) as (_, subscripts):
                indexed_terms_set.add(subscripts if only_subscripts else indexed[subscripts])
        except DestructuringError:
            continue

    return list(indexed_terms_set)
Ejemplo n.º 41
0
	def encode(self,expr):
		# print expr
		iis = []
		ffs = []
		for i,e in enumerate(sympy.preorder_traversal(expr)):
			# print i, e.func
			ii, ff = self.mapper.get(e)
			iis = iis + ii
			if ff is not None:
				iis.append(len(ffs))
				ffs = ffs + ff
			# print "   ", ii, ff
		return iis, ffs
Ejemplo n.º 42
0
def symbols_from_expr(expr, include_numbers=False, include_derivatives=False):
    """
    Returns a set of all symbols of an expression

    Arguments:
    ----------
    expr : sympy expression
        A sympy expression containing sympy.Symbols or sympy.AppliedUndef
        functions.
    include_numbers : bool
        If True numbers will also be returned
    include_derivatives : bool
        If True derivatives will be returned instead of its variables
    """
    from sympy.core.function import AppliedUndef

    symbols = set()
    
    pt = sp.preorder_traversal(expr)
    
    for node in pt:
        
        # Do not traverse AppliedUndef
        if isinstance(node, AppliedUndef):
            pt.skip()
            symbols.add(node)
        
        elif isinstance(node, sp.Symbol) and not isinstance(node, sp.Dummy) \
                 and node.name:
            symbols.add(node)

        elif include_numbers and isinstance(node, sp.Number):
            symbols.add(node)

        elif include_derivatives and isinstance(node, sp.Derivative):
            # Do not traverse Derivative
            pt.skip()
            symbols.add(node)
            
    return symbols
Ejemplo n.º 43
0
 def rearangeForDerivs(self,eoms,secondOrder=False):
   suffix = self.derivative_suffix
   if secondOrder:
       suffix += suffix
   derivSet = set()
   for eom in eoms:
     for x in sympy.preorder_traversal(eom):
       if type(x) == sympy.Symbol and suffix in str(x):
         derivSet.add(x)
   derivList = list(derivSet)
   if len(derivList) == 0:
     raise Exception("No time derivative was found in eom: '{0}', where derivative has suffix of '{1}'".format(eom,suffix))
   solns = sympy.solve(eoms,derivList)
   if len(solns) < len(derivList):
     raise Exception("Too few solutions, {2}, were found for '{1}'".format(eom,derivList,solns))
   if len(solns) > len(derivList):
     raise Exception("Too many solutions, {2}, were found for '{1}'".format(eom,derivList,solns))
   for deriv in derivList:
     try:
       solns[deriv]
     except KeyError:
       raise Exception("Couldn't find solution for {1}, in solutions {2}, in EOMs '{0}'".format(eom,deriv,solns))
   return solns
Ejemplo n.º 44
0
def positif(expression, variable=None, strict=False, _niveau=0, _changement_variable=None):
    """Retourne l'ensemble sur lequel une expression à variable réelle est positive (resp. strictement positive)."""
    from .sympy_functions import factor
    # L'étude du signe se fait dans R, on indique donc à sympy que la variable est réelle.
    if variable is None:
        variable = extract_var(expression)
    if hasattr(expression, "subs"):
        old_variable = variable
        variable = Dummy(real=True)
        expression = expression.subs({old_variable:variable})

    # Ensemble de définition et périodicité
    ens_def = ensemble_definition(expression, variable)
    T = periode(expression, variable)
    if T not in (0, oo):
        ens_def &= Intervalle(0, T)
        if param.debug:
            print('Fonction périodique %s détectée. Résolution sur [0;%s]' % (expression, T))

    # On remplace sqrt(x^2) par |x|.
    a = Wild('a', exclude=[expression])
    dic = expression.match(sqrt(a**2))
    if dic is not None:
        sub_expr = dic[a]
        # On évite de détecter sqrt(x) comme étant sqrt(sqrt(x)**2) !
        if not (sub_expr.is_Pow and sub_expr.as_base_exp()[1].is_integer):
            expression = expression.replace(sqrt(a**2),Abs(a))
    expression = expression.replace(Abs(sqrt(a)),sqrt(a))
    del a

    # On factorise au maximum.
    try:
        expression = factor(expression, variable, "R", decomposer_entiers = False)
    except NotImplementedError:
        if param.debug:
            print("Warning: Factorisation impossible de ", expression)

    if expression.is_Pow and expression.as_base_exp()[1].is_rational:
        base, p = expression.as_base_exp()
        # Le dénominateur ne doit pas s'annuler :
        if p < 0:
            strict = True
        if p.is_integer and p.is_even:
            if strict:
                return ens_def & (R - (positif(base, variable, strict=False) - positif(base, variable, strict=True)))
            else:
                return ens_def
        else:
            return ens_def & positif(base, variable, strict=strict)

    if expression.is_Mul:
        posit = R
        posit_nul = R
        for facteur in expression.args:
            # pos : ensemble des valeurs pour lequelles l'expression est positive
            # pos_nul : ensemble des valeurs pour lequelles l'expression est positive ou nulle
            pos = positif(facteur, variable, strict = True)
            pos_nul = positif(facteur, variable, strict = False)
            # posit : les deux sont strictements positifs, ou les deux sont strictements négatifs
            # posit_nul : les deux sont positifs ou nuls, ou les deux sont négatifs ou nuls
            posit, posit_nul = ((posit & pos) + (-posit_nul & -pos_nul) & ens_def,
                                ((posit_nul & pos_nul) + (-posit & -pos)) & ens_def)
        if strict:
            return posit
        else:
            return posit_nul

    if expression.is_positive is True: # > 0
        return ens_def
    if expression.is_negative is True: # < 0
        return vide
    if expression.is_positive is False and strict: # <= 0
        return vide
    if expression.is_negative is False and not strict: # >= 0
        return ens_def
    if expression.is_zero is True and not strict: # == 0
        return ens_def

    if isinstance(expression, (int, float)):
        if expression > 0 or (expression == 0 and not strict):
            return ens_def
        else:
            return vide

    # Inutile de se préoccuper de l'ensemble de définition pour les fonctions polynômiales.
    if expression.is_polynomial():
        P = expression.as_poly(variable)
        if P.degree() == 1:
            a, b = P.all_coeffs()
            if a > 0:
                return Intervalle(-b/a, +oo, inf_inclus = not strict)
            else: # a<0 (car a != 0)
                return Intervalle(-oo, -b/a, sup_inclus = not strict)
        elif P.degree() == 2:
            a, b, c = P.all_coeffs()
            d = b**2 - 4*a*c
            if d > 0:
                x1 = (-b - sqrt(d))/(2*a)
                x2 = (-b + sqrt(d))/(2*a)
                x1, x2 = min(x1, x2), max(x1, x2)
                if a > 0:
                    return Intervalle(-oo, x1, sup_inclus = not strict) + Intervalle(x2, +oo, inf_inclus = not strict)
                else: # a<0 (car a != 0)
                    return Intervalle(x1, x2, inf_inclus = not strict, sup_inclus = not strict)
            elif d == 0:
                x0 = -b/(2*a)
                if a > 0:
                    return Intervalle(-oo, x0, sup_inclus  = not strict) + Intervalle(x0, +oo, inf_inclus = not strict)
                else:
                    return Intervalle(x0, x0, sup_inclus  = not strict)
            else: # d < 0
               if a > 0:
                   return R
               else:
                   return vide

    # Valeur absolue seule:
    if isinstance(expression, Abs):
        return ens_def

    # Valeur absolue: cas général. L'idée est simplement de supprimer la valeur
    # absolue en faisant deux cas: |f(x)| = f(x) si f(x)>=0 et -f(x) si f(x)<0.
    # (Le `for` est trompeur: on ne supprime qu'une seule valeur absolue à la fois, la récursivité fait le reste...)
    for subexpr in expression.find(Abs):
        # subexpr = |f(x)|
        # val = f(x)
        val = subexpr.args[0]
        pos = positif(val, variable)
        # g(|f(x)|, x) > 0 <=> g(f(x), x) > 0 et f(x) >= 0 ou g(-f(x), x) > 0 et f(x) < 0
        return ((positif(expression.xreplace({subexpr: val}), variable, strict=strict) & pos) |
                (positif(expression.xreplace({subexpr: -val}), variable, strict=strict) & -pos))

    # Puissances
    # Résolution de a*x^q-b > 0, où q n'est pas entier
    if expression.is_Add:
        a = Wild('a', exclude=[variable, 0])
        q = Wild('q', exclude=[variable, 1])
        b = Wild('b', exclude=[variable])
        X = Wild('X')
        # match ne semble pas fonctionner avec a*X**q - b
        match = expression.match(a*X**q + b)
        if match and X in match:
            a = match[a]
            q = match[q]
            b = -match[b]/a
            X = match[X]
            # Le cas où q est entier est déjà traité par ailleurs (polynômes).
            # Lorsque q est de la forme 1/n, on peut définir la fonction x−>x^(1/n)
            # sur R si n est impair et sur R+ sinon.
            # Dans tous les autres cas, on définit la fonction x->x^q sur ]0;+oo[.
            if not q.is_integer:
                if a.is_negative:
                    # si a < 0, a*x^q-b > 0 <=> x^q-b/a < 0 <=> non(x^q-b/a >= 0)
                    strict = not strict
                if b.is_negative:
                    # pour X > 0, X^(2/3)-b > X^2/3 > 0
                    sols = ens_def
                else:
                    # pour X > 0, X^(2/3)-b > 0 <=> X > b^(3/2)
                    sols = ens_def & positif(X - b**(1/q), strict=strict)
                # si a < 0, a*x^q-b > 0 <=> x^q-b/a < 0 <=> non(x^q-b/a >= 0)
                if a.is_negative:
                    sols = ens_def - sols
                return sols
        del a, q, b, X

    # résolution de a*sqrt(B)-c*sqrt(D) > 0 où signe(c) = signe(a)
    if expression.is_Add:
        a = Wild('a', exclude=[0, variable])
        B = Wild('B', exclude=[0])
        c = Wild('c', exclude=[0, variable])
        D = Wild('D', exclude=[0])
        match = expression.match(a*sqrt(B) - c*sqrt(D))
        if match:
            a = match[a]
            B = match[B]
            c = match[c]
            D = match[D]
            if a.is_positive and c.is_positive:
                return ens_def & positif(a**2*B - c**2*D, variable, strict=strict)
            elif a.is_negative and c.is_negative:
                return ens_def & positif(c**2*D - a**2*B, variable, strict=strict)
        del a, B, c, D

    # Logarithme :
    if isinstance(expression, ln):
        return positif(expression.args[0] - 1, variable, strict=strict)

    # Sommes contenant des logarithmes :
    # Résolution de ln(X1) + ln(X2) + ... + b > 0, où X1=f1(x), X2 = f2(x) ...
    if expression.is_Add and expression.has(ln):
        args = expression.args
        liste_constantes = []
        liste_ln = []
        # Premier passage : on remplace a*ln(X1) par ln(X1**a)
        for arg in args:
            if getattr(arg, "is_Mul", False):
                liste_constantes = []
                liste_ln = []
                for facteur in arg.args:
                    if isinstance(facteur, ln) and is_var(facteur, variable):
                        liste_ln.append(facteur)
                    elif not is_var(facteur, variable):
                        liste_constantes.append(facteur)
                if len(liste_constantes) == len(arg.args) - 1 and len(liste_ln) == 1:
                    expression += ln(liste_ln[0].args[0]**Add(*liste_constantes)) - arg
        # Deuxième passage : ln(X1)+ln(X2)+b>0 <=> X1*X2-exp(-b)>0
        for arg in args:
            if isinstance(arg, ln) and hasattr(arg, "has") and arg.has(variable):
                liste_ln.append(arg)
            elif not hasattr(arg, "has") or not arg.has(variable):
                liste_constantes.append(arg)

        if liste_ln and len(liste_ln) + len(liste_constantes) == len(args):
            # ln(X1)+ln(X2)+b>0 <=> X1*X2-exp(-b)>0
            contenu_log = Mul(*(logarithme.args[0] for logarithme in liste_ln))
            contenu_cst = exp(- Add(*liste_constantes))
            return ens_def & positif(contenu_log - contenu_cst, variable, strict=strict)

        # Cas très particulier : on utilise le fait que ln(x)<=x-1 sur ]0;+oo[
        expr = expression
        changements = False
        for arg in expr.args:
            if isinstance(arg, ln):
                changements = True
                expr += arg.args[0] + 1 - arg
        if changements:
            try:
                non_positif = positif(-expr, variable, strict = not strict) # complementaire
                (ens_def - positif(expr, variable, strict = not strict) == vide)
                if (ens_def - non_positif == vide):
                    return vide
            except NotImplementedError:
                pass

        # Si aucune autre méthode n'a fonctionné, on tente ln(a)+ln(b)>0 <=> a*b>1 (pour a>0 et b>0)
        expr = Mul(*(exp(arg) for arg in expression.args)) - 1
        try:
            return ens_def*positif(expr, variable, strict=strict)
        except NotImplementedError:
            pass

    # Exponentielle
    # Résolution de a*exp(f(x)) + b > 0
    if expression.is_Add and expression.has(exp):
        a = Wild('a', exclude=[variable, 0])
        b = Wild('b', exclude=[variable])
        X = Wild('X')
        match = expression.match(a*exp(X) + b)
        if match:
            a = match[a]
            b = match[b]
            X = match[X]
            if is_pos(b):
                if is_pos(a):
                    return ens_def
                elif is_neg(a):
                    # l'ensemble de définition ne change pas
                    return positif(- X + ln(-b/a), variable, strict=strict)
            elif is_neg(b):
                if is_pos(a):
                    return positif(X - ln(-b/a), variable, strict=strict)
                elif is_neg(a):
                    return vide
        del a, b, X

        # Cas très particulier : on utilise le fait que exp(x)>=x+1 sur R
        expr = expression
        changements = False
        for arg in expr.args:
            if isinstance(arg, exp):
                changements = True
                expr += arg.args[0] + 1 - arg
        if changements and (ens_def - positif(expr, variable, strict=strict) == vide):
            return ens_def

        # Cas très particulier : si a≥0, b*(a*x-1+exp(x))>0 <=> b*x>0
        a = Wild('a', exclude=[variable, 0])
        b = Wild('b', exclude=[variable, 0])
        X = Wild('X')
        match = expression.match(b*(a*X - 1 + exp(X)))
        if match is not None and X in match:
            a = match[a]
            if a >= 0:
                b = match[b]
                X = match[X]
                return positif(b*X, variable, strict=strict)
        del a, b, X

    # Aucun cas connu n'a été détecté, on tente un changement de variable.
    # NB: _niveau sert à éviter les récursions infinies !
    if _niveau > 10:
        print("Infinite recursion suspected. Aborting...")
        raise NotImplementedError

    # La technique globalement est la suivante :
    # sqrt(x² + 5) - 9 > 0 <=> sqrt(X) - 9 > 0 (avec X = x² + 5) <=> X in ]3;+oo[ <=> X - 3 > 0 <=> x² + 5 - 3 > 0, etc.

    def _resolution_par_substitution(expr, X):
        try:
            solutions_intermediaires = positif(expr, X, strict=strict,
                                  _niveau=_niveau + 1,
                                  _changement_variable=Lambda(variable,sub))
            solution = vide
            for intervalle in solutions_intermediaires.intervalles:
                sol = R
                a = intervalle.inf
                b = intervalle.sup
                if a != - oo:
                    sol &= positif(sub - a, variable, strict=(not intervalle.inf_inclus))
                if b != oo:
                    sol &= positif(b - sub, variable, strict=(not intervalle.sup_inclus))
                solution += sol
            return ens_def & solution
        except NotImplementedError:
            return None

    # On commence par lister tous les changements de variable potentiels,
    # c'est-à-dire toutes les sous-expressions qui contiennent la variable.
    changements = sorted(set(subexpr for subexpr in preorder_traversal(expression)
                         if subexpr.has(variable)) - {variable, expression},
                         key=count_ops)
    a = Wild('a', exclude=[variable, 0])
    b = Wild('b', exclude=[variable, 0])
    X = Dummy(real=True)
    changements_incomplets = []
    for sub in changements:
        if _changement_variable is not None:
            enchainement = _changement_variable(sub)
            if enchainement.match(a*variable) or enchainement.match(a*abs(variable)):
                # On enchaîne deux changements de variable réciproque,
                # comme ln() et exp() ou encore x->x² et x-> sqrt(x).
                # Ce qui conduirait à une récursion infinie.
                continue
        match = expression.match(a*sub + b)
        if match and match[a] in (-1, 1):
            # Ceci conduirait à des récursions infinies du genre :
            # sqrt(x² + 5) - 9 > 0 <=> X - 9 > 0 (avec X = sqrt(x² + 5)) <=> X in ]9;+oo[ <=> X - 9 > 0 <=> sqrt(x² + 5) - 9 > 0, etc.
            continue
        # On tente le changement de variable.
        new = expression.subs(sub, X)
        if new.has(variable):
            # Changement de variable incomplet.
            # On le garde en réserve pour une 2e passe si on n'a pas trouvé mieux.
            changements_incomplets.append(sub)
        else:
            sols = _resolution_par_substitution(new, X)
            if sols is not None:
                return sols
    for sub in changements_incomplets:
        # On cherche si le changement de variable est inversible.
        # Si oui, au lieu de remplacer f(x) par X, on remplace x par f-¹(X)
        # Bizarrement, l'assertion real=True fait planter le solver() de sympy
        # lorsqu'on lance solve(sqrt(x)-y, x). On utilise donc des variables
        # temporaires sans assertions.
        var1 = Dummy()
        var2 = Dummy()
        antecedents = solve((sub - X).xreplace({variable:var1, X:var2}), var1)
        if len(antecedents) == 1:
            new = expression.subs(variable, antecedents[0].xreplace({var1:variable, var2:X}))
            sols = _resolution_par_substitution(new, X)
            if sols is not None:
                return sols

    # En dernier ressort, résolution par continuité.
    # Les fonctions usuelles sont continues sur tout intervalle de leur ensemble de définition.
    # Il suffit donc de rechercher les zéros de la fonction, et d'évaluer le signe
    # de l'expression sur chaque tronçon.
    # Cette méthode est simple, mais elle suppose que **tous** les zéros aient bien
    # été trouvés par solve(), ce qui n'est pas toujours le cas.
    # C'est pourquoi elle est proposée seulement en dernier recours.
    if param.debug:
        print("Warning: résolution par continuité. Les résultats peuvent être\n"
              "faux si certaines racines ne sont pas touvées !")

    racines = nul(expression, variable, intervalle=False)
    solutions = vide
    for intervalle in ens_def.intervalles:
        inf = intervalle.inf
        sup = intervalle.sup
        decoupage = {S(inf), S(sup)}
        for borne in decoupage:
            if borne in intervalle:
                if expression.subs(variable, borne) > 0:
                    solutions |= Intervalle(borne, borne)
        for rac in racines:
            if rac in intervalle:
                if not strict:
                    solutions |= Intervalle(rac, rac)
                decoupage.add(rac)
        decoupage = sorted(decoupage)
        for val1, val2 in zip(decoupage[:-1], decoupage[1:]):
            if val1 == -oo and val2 == oo:
                milieu = 0
            elif val2 == oo:
                milieu = val1 + 1
            elif val1 == -oo:
                milieu = val2 - 1
            else:
                milieu = (val1 + val2)/2
            if expression.subs(variable, milieu) > 0:
                solutions |= Intervalle(val1, val2, False, False)
    return ens_def&solutions
Ejemplo n.º 45
0
 def _has_grad(node):
     """Return true if node has a grad in it"""
     return len(filter(lambda n: isinstance(n, grad),
                       preorder_traversal(node))) > 0
Ejemplo n.º 46
0
 def _has_div(node):
     """Return true if node has a div in it"""
     return len(filter(lambda n: isinstance(n, div),
                       preorder_traversal(node))) > 0
Ejemplo n.º 47
0
 def _extract_diffusion(self, order_dict):
     second_order = order_dict.get(2, 0)
     div_grads = filter(self._is_div_grad, preorder_traversal(second_order))
     div_grad_args = map(lambda d: d.args[0], div_grads)
     grads = map(self._find_grad_coefficient, div_grad_args)
     return Add(*list(grads))
Ejemplo n.º 48
0
def has_sqrt(sympy_obj):
  return any(el.func is C.Pow and el.args[-1] is S.Half
             for el in preorder_traversal(sympy_obj))