Пример #1
0
 def init(self, expr):
     super(PatternObject, self).init(expr)
     if self.arg_counts is not None:
         if len(expr.leaves) not in self.arg_counts:
             self.error_args(len(expr.leaves), *self.arg_counts)
     self.expr = expr
     self.head = Pattern.create(expr.head)
     self.leaves = [Pattern.create(leaf) for leaf in expr.leaves]
Пример #2
0
 def init(self, expr):
     super(PatternObject, self).init(expr)
     if self.arg_counts is not None:
         if len(expr.leaves) not in self.arg_counts:
             self.error_args(len(expr.leaves), *self.arg_counts)
     self.expr = expr
     self.head = Pattern.create(expr.head)
     self.leaves = [Pattern.create(leaf) for leaf in expr.leaves]
Пример #3
0
    def apply(self, expr, patterns, f, evaluation):
        'Reap[expr_, {patterns___}, f_]'

        patterns = patterns.get_sequence()
        sown = [(Pattern.create(pattern), []) for pattern in patterns]

        def listener(e, tag):
            result = False
            for pattern, items in sown:
                if pattern.does_match(tag, evaluation):
                    for item in items:
                        if item[0].same(tag):
                            item[1].append(e)
                            break
                    else:
                        items.append((tag, [e]))
                    result = True
            return result

        evaluation.add_listener('sow', listener)
        try:
            result = expr.evaluate(evaluation)
            items = []
            for pattern, tags in sown:
                list = Expression('List')
                for tag, elements in tags:
                    list.leaves.append(
                        Expression(f, tag, Expression('List', *elements)))
                items.append(list)
            return Expression('List', result, Expression('List', *items))
        finally:
            evaluation.remove_listener('sow', listener)
Пример #4
0
    def apply(self, expr, pattern, test, evaluation):
        'ArrayQ[expr_, pattern_, test_]'

        pattern = Pattern.create(pattern)

        dims = [len(expr.get_leaves())]  # to ensure an atom is not an array

        def check(level, expr):
            if not expr.has_form('List', None):
                test_expr = Expression(test, expr)
                if test_expr.evaluate(evaluation) != Symbol('True'):
                    return False
                level_dim = None
            else:
                level_dim = len(expr.leaves)

            if len(dims) > level:
                if dims[level] != level_dim:
                    return False
            else:
                dims.append(level_dim)
            if level_dim is not None:
                for leaf in expr.leaves:
                    if not check(level + 1, leaf):
                        return False
            return True

        if not check(0, expr):
            return Symbol('False')

        depth = len(dims) - 1  # None doesn't count
        if not pattern.does_match(Integer(depth), evaluation):
            return Symbol('False')
        return Symbol('True')
Пример #5
0
 def apply(self, expr, patterns, f, evaluation):
     'Reap[expr_, {patterns___}, f_]'
     
     patterns = patterns.get_sequence()
     sown = [(Pattern.create(pattern), []) for pattern in patterns]
     
     def listener(e, tag):
         result = False
         for pattern, items in sown:
             if pattern.does_match(tag, evaluation):
                 for item in items:
                     if item[0].same(tag):
                         item[1].append(e)
                         break
                 else:
                     items.append((tag, [e]))
                 result = True
         return result
     
     evaluation.add_listener('sow', listener)
     try:
         result = expr.evaluate(evaluation)
         items = []
         for pattern, tags in sown:
             list = Expression('List')
             for tag, elements in tags:
                 list.leaves.append(Expression(f, tag, Expression('List', *elements)))
             items.append(list)
         return Expression('List', result, Expression('List', *items))
     finally:
         evaluation.remove_listener('sow', listener)
Пример #6
0
    def apply(self, f, x, evaluation):
        'D[f_, x_?NotListQ]'

        if f == x:
            return Integer(1)
        elif not f.is_atom() and len(f.leaves) == 1 and f.leaves[0] == x:
            return Expression(
                Expression(Expression('Derivative', Integer(1)), f.head), x)
        elif not f.is_atom() and len(f.leaves) == 1:
            g = f.leaves[0]
            return Expression(
                'Times', Expression('D', Expression(f.head, g), g),
                Expression('D', g, x))
        elif not f.is_atom() and len(f.leaves) > 1:
            def summand(leaf, index):
                if leaf.same(x):
                    result = Expression(Expression(
                        Expression(
                            'Derivative',
                            *([Integer(0)] * (index) + [Integer(1)] +
                              [Integer(0)] * (len(f.leaves) - index - 1))),
                        f.head), *f.leaves)
                else:
                    result = Expression('D', f, leaf)
                return Expression('Times', result, Expression('D', leaf, x))
            x_pattern = Pattern.create(x)
            result = Expression(
                'Plus', *[
                    summand(leaf, index) for index, leaf in enumerate(f.leaves)
                    if not leaf.is_free(x_pattern, evaluation)])
            if len(result.leaves) == 1:
                return result.leaves[0]
            else:
                return result
Пример #7
0
    def apply(self, expr, pattern, test, evaluation):
        'ArrayQ[expr_, pattern_, test_]'

        pattern = Pattern.create(pattern)

        dims = [len(expr.get_leaves())]  # to ensure an atom is not an array

        def check(level, expr):
            if not expr.has_form('List', None):
                test_expr = Expression(test, expr)
                if test_expr.evaluate(evaluation) != Symbol('True'):
                    return False
                level_dim = None
            else:
                level_dim = len(expr.leaves)

            if len(dims) > level:
                if dims[level] != level_dim:
                    return False
            else:
                dims.append(level_dim)
            if level_dim is not None:
                for leaf in expr.leaves:
                    if not check(level + 1, leaf):
                        return False
            return True

        if not check(0, expr):
            return Symbol('False')

        depth = len(dims) - 1  # None doesn't count
        if not pattern.does_match(Integer(depth), evaluation):
            return Symbol('False')
        return Symbol('True')
Пример #8
0
    def apply(self, f, x, evaluation):
        'D[f_, x_?NotListQ]'

        if f == x:
            return Integer(1)
        elif not f.is_atom() and len(f.leaves) == 1 and f.leaves[0] == x:
            return Expression(
                Expression(Expression('Derivative', Integer(1)), f.head), x)
        elif not f.is_atom() and len(f.leaves) == 1:
            g = f.leaves[0]
            return Expression(
                'Times', Expression('D', Expression(f.head, g), g),
                Expression('D', g, x))
        elif not f.is_atom() and len(f.leaves) > 1:
            def summand(leaf, index):
                if leaf.same(x):
                    result = Expression(Expression(
                        Expression(
                            'Derivative',
                            *([Integer(0)] * (index) + [Integer(1)] +
                              [Integer(0)] * (len(f.leaves) - index - 1))),
                        f.head), *f.leaves)
                else:
                    result = Expression('D', f, leaf)
                return Expression('Times', result, Expression('D', leaf, x))
            x_pattern = Pattern.create(x)
            result = Expression(
                'Plus', *[
                    summand(leaf, index) for index, leaf in enumerate(f.leaves)
                    if not leaf.is_free(x_pattern, evaluation)])
            if len(result.leaves) == 1:
                return result.leaves[0]
            else:
                return result
Пример #9
0
    def apply(self, expr, form, evaluation):
        "FreeQ[expr_, form_]"

        form = Pattern.create(form)
        if expr.is_free(form, evaluation):
            return Symbol("True")
        else:
            return Symbol("False")
Пример #10
0
    def apply(self, expr, form, evaluation):
        "FreeQ[expr_, form_]"

        form = Pattern.create(form)
        if expr.is_free(form, evaluation):
            return Symbol("True")
        else:
            return Symbol("False")
Пример #11
0
    def apply(self, expr, form, evaluation):
        'FreeQ[expr_, form_]'

        form = Pattern.create(form)
        if expr.is_free(form, evaluation):
            return Symbol('True')
        else:
            return Symbol('False')
Пример #12
0
    def apply(self, expr, form, evaluation):
        'FreeQ[expr_, form_]'

        form = Pattern.create(form)
        if expr.is_free(form, evaluation):
            return Symbol('True')
        else:
            return Symbol('False')
Пример #13
0
    def apply(self, expr, form, evaluation):
        'FreeQ[expr_, form_]'
        """def is_free(sub):
            for vars, rest in form.match(sub, {}, evaluation, fully=False):
                return False
            if sub.is_atom():
                return True
            else:
                return is_free(sub.head) and all(is_free(leaf) for leaf in sub.leaves)"""

        form = Pattern.create(form)
        if expr.is_free(form, evaluation):
            return Symbol('True')
        else:
            return Symbol('False')
Пример #14
0
 def apply(self, expr, form, evaluation):
     'FreeQ[expr_, form_]'
     
     """def is_free(sub):
         for vars, rest in form.match(sub, {}, evaluation, fully=False):
             return False
         if sub.is_atom():
             return True
         else:
             return is_free(sub.head) and all(is_free(leaf) for leaf in sub.leaves)"""
         
     form = Pattern.create(form)
     if expr.is_free(form, evaluation):
         return Symbol('True')
     else:
         return Symbol('False')
Пример #15
0
    def apply(self, eqs, vars, evaluation):
        'Solve[eqs_, vars_]'

        vars_original = vars
        head_name = vars.get_head_name()
        if head_name == 'System`List':
            vars = vars.leaves
        else:
            vars = [vars]
        for var in vars:
            if ((var.is_atom() and not var.is_symbol()) or  # noqa
                head_name in ('System`Plus', 'System`Times', 'System`Power') or
                'System`Constant' in var.get_attributes(evaluation.definitions)):

                evaluation.message('Solve', 'ivar', vars_original)
                return
        eqs_original = eqs
        if eqs.get_head_name() in ('System`List', 'System`And'):
            eqs = eqs.leaves
        else:
            eqs = [eqs]
        sympy_eqs = []
        sympy_denoms = []
        for eq in eqs:
            symbol_name = eq.get_name()
            if symbol_name == 'System`True':
                pass
            elif symbol_name == 'System`False':
                return Expression('List')
            elif not eq.has_form('Equal', 2):
                return evaluation.message('Solve', 'eqf', eqs_original)
            else:
                left, right = eq.leaves
                left = left.to_sympy()
                right = right.to_sympy()
                if left is None or right is None:
                    return
                eq = left - right
                eq = sympy.together(eq)
                eq = sympy.cancel(eq)
                sympy_eqs.append(eq)
                numer, denom = eq.as_numer_denom()
                sympy_denoms.append(denom)

        vars_sympy = [var.to_sympy() for var in vars]
        if None in vars_sympy:
            return

        # delete unused variables to avoid SymPy's
        # PolynomialError: Not a zero-dimensional system
        # in e.g. Solve[x^2==1&&z^2==-1,{x,y,z}]
        all_vars = vars[:]
        all_vars_sympy = vars_sympy[:]
        vars = []
        vars_sympy = []
        for var, var_sympy in zip(all_vars, all_vars_sympy):
            pattern = Pattern.create(var)
            if not eqs_original.is_free(pattern, evaluation):
                vars.append(var)
                vars_sympy.append(var_sympy)

        def transform_dict(sols):
            if not sols:
                yield sols
            for var, sol in six.iteritems(sols):
                rest = sols.copy()
                del rest[var]
                rest = transform_dict(rest)
                if not isinstance(sol, (tuple, list)):
                    sol = [sol]
                if not sol:
                    for r in rest:
                        yield r
                else:
                    for r in rest:
                        for item in sol:
                            new_sols = r.copy()
                            new_sols[var] = item
                            yield new_sols
                break

        def transform_solution(sol):
            if not isinstance(sol, dict):
                if not isinstance(sol, (list, tuple)):
                    sol = [sol]
                sol = dict(list(zip(vars_sympy, sol)))
            return transform_dict(sol)

        if not sympy_eqs:
            sympy_eqs = True
        elif len(sympy_eqs) == 1:
            sympy_eqs = sympy_eqs[0]

        try:
            if isinstance(sympy_eqs, bool):
                result = sympy_eqs
            else:
                result = sympy.solve(sympy_eqs, vars_sympy)
            if not isinstance(result, list):
                result = [result]
            if (isinstance(result, list) and len(result) == 1 and
                    result[0] is True):
                return Expression('List', Expression('List'))
            if result == [None]:
                return Expression('List')
            results = []
            for sol in result:
                results.extend(transform_solution(sol))
            result = results
            if any(sol and any(var not in sol for var in all_vars_sympy)
                   for sol in result):
                evaluation.message('Solve', 'svars')

            # Filter out results for which denominator is 0
            # (SymPy should actually do that itself, but it doesn't!)
            result = [sol for sol in result if all(
                sympy.simplify(denom.subs(sol)) != 0 for denom in sympy_denoms)]

            return Expression('List', *(Expression(
                'List',
                *(Expression('Rule', var, from_sympy(sol[var_sympy]))
                  for var, var_sympy in zip(vars, vars_sympy)
                  if var_sympy in sol)
            ) for sol in result))
        except sympy.PolynomialError:
            # raised for e.g. Solve[x^2==1&&z^2==-1,{x,y,z}] when not deleting
            # unused variables beforehand
            pass
        except NotImplementedError:
            pass
        except TypeError as exc:
            if str(exc).startswith("expected Symbol, Function or Derivative"):
                evaluation.message('Solve', 'ivar', vars_original)
Пример #16
0
    def apply(self, f, x, evaluation):
        "D[f_, x_?NotListQ]"
        x_pattern = Pattern.create(x)
        if f.is_free(x_pattern, evaluation):
            return IntegerZero
        elif f == x:
            return Integer1
        elif f.is_atom():  # Shouldn't happen
            1 / 0
            return
        # So, this is not an atom...

        head = f.get_head()
        if head == SymbolPlus:
            terms = [
                Expression("D", term, x) for term in f.leaves
                if not term.is_free(x_pattern, evaluation)
            ]
            if len(terms) == 0:
                return IntegerZero
            return Expression(SymbolPlus, *terms)
        elif head == SymbolTimes:
            terms = []
            for i, factor in enumerate(f.leaves):
                if factor.is_free(x_pattern, evaluation):
                    continue
                factors = [leaf for j, leaf in enumerate(f.leaves) if j != i]
                factors.append(Expression("D", factor, x))
                terms.append(Expression(SymbolTimes, *factors))
            if len(terms) != 0:
                return Expression(SymbolPlus, *terms)
            else:
                return IntegerZero
        elif head == SymbolPower and len(f.leaves) == 2:
            base, exp = f.leaves
            terms = []
            if not base.is_free(x_pattern, evaluation):
                terms.append(
                    Expression(
                        SymbolTimes,
                        exp,
                        Expression(
                            SymbolPower,
                            base,
                            Expression(SymbolPlus, exp, IntegerMinusOne),
                        ),
                        Expression("D", base, x),
                    ))
            if not exp.is_free(x_pattern, evaluation):
                if base.is_atom() and base.get_name() == "System`E":
                    terms.append(
                        Expression(SymbolTimes, f, Expression("D", exp, x)))
                else:
                    terms.append(
                        Expression(
                            SymbolTimes,
                            f,
                            Expression("Log", base),
                            Expression("D", exp, x),
                        ))

            if len(terms) == 0:
                return IntegerZero
            elif len(terms) == 1:
                return terms[0]
            else:
                return Expression(SymbolPlus, *terms)
        elif len(f.leaves) == 1:
            if f.leaves[0] == x:
                return Expression(
                    Expression(Expression("Derivative", Integer(1)), f.head),
                    x)
            else:
                g = f.leaves[0]
                return Expression(
                    SymbolTimes,
                    Expression("D", Expression(f.head, g), g),
                    Expression("D", g, x),
                )
        else:  # many leaves

            def summand(leaf, index):
                result = Expression(
                    Expression(
                        Expression(
                            "Derivative",
                            *([IntegerZero] * (index) + [Integer1] +
                              [IntegerZero] * (len(f.leaves) - index - 1))),
                        f.head,
                    ), *f.leaves)
                if leaf.sameQ(x):
                    return result
                else:
                    return Expression("Times", result,
                                      Expression("D", leaf, x))

            result = [
                summand(leaf, index) for index, leaf in enumerate(f.leaves)
                if not leaf.is_free(x_pattern, evaluation)
            ]

            if len(result) == 1:
                return result[0]
            elif len(result) == 0:
                return IntegerZero
            else:
                return Expression("Plus", *result)
Пример #17
0
    def apply(self, f, xs, evaluation, options):
        "Integrate[f_, xs__, OptionsPattern[]]"
        self.patpow0 = Pattern.create(
            Expression("Power", Integer0, Expression("Blank")))
        assuming = options["System`Assumptions"].evaluate(evaluation)
        f_sympy = f.to_sympy()
        if f_sympy is None or isinstance(f_sympy, SympyExpression):
            return
        xs = xs.get_sequence()
        vars = []
        prec = None
        for x in xs:
            if x.has_form("List", 3):
                x, a, b = x.leaves
                prec_a = a.get_precision()
                prec_b = b.get_precision()
                if prec_a is not None and prec_b is not None:
                    prec_new = min(prec_a, prec_b)
                    if prec is None or prec_new < prec:
                        prec = prec_new
                a = a.to_sympy()
                b = b.to_sympy()
                if a is None or b is None:
                    return
            else:
                a = b = None
            if not x.get_name():
                evaluation.message("Integrate", "ilim")
                return
            x = x.to_sympy()
            if x is None:
                return
            if a is None or b is None:
                vars.append(x)
            else:
                vars.append((x, a, b))
        try:
            result = sympy.integrate(f_sympy, *vars)
        except sympy.PolynomialError:
            return
        except ValueError:
            # e.g. ValueError: can't raise polynomial to a negative power
            return
        except NotImplementedError:
            # e.g. NotImplementedError: Result depends on the sign of
            # -sign(_Mathics_User_j)*sign(_Mathics_User_w)
            return
        if prec is not None and isinstance(result, sympy.Integral):
            # TODO MaxExtaPrecision -> maxn
            result = result.evalf(dps(prec))
        else:
            result = from_sympy(result)
        # If the result is defined as a Piecewise expression,
        # use ConditionalExpression.
        # This does not work now because the form sympy returns the values
        if result.get_head_name() == "System`Piecewise":
            cases = result._leaves[0]._leaves
            if len(result._leaves) == 1:
                if cases[-1]._leaves[1].is_true():
                    default = cases[-1]._leaves[0]
                    cases = result._leaves[0]._leaves[:-1]
                else:
                    default = SymbolUndefined
            else:
                cases = result._leaves[0]._leaves
                default = result._leaves[1]
            if default.has_form("Integrate", None):
                if default._leaves[0] == f:
                    default = SymbolUndefined

            simplified_cases = []
            for case in cases:
                # TODO: if something like 0^n or 1/expr appears,
                # put the condition n!=0 or expr!=0 accordingly in the list of
                # conditions...
                cond = Expression("Simplify", case._leaves[1],
                                  assuming).evaluate(evaluation)
                resif = Expression("Simplify", case._leaves[0],
                                   assuming).evaluate(evaluation)
                if cond.is_true():
                    return resif
                if resif.has_form("ConditionalExpression", 2):
                    cond = Expression("And", resif._leaves[1], cond)
                    cond = Expression("Simplify", cond,
                                      assuming).evaluate(evaluation)
                    resif = resif._leaves[0]
                simplified_cases.append(Expression(SymbolList, resif, cond))
            cases = simplified_cases
            if default == SymbolUndefined and len(cases) == 1:
                cases = cases[0]
                result = Expression("ConditionalExpression", *(cases._leaves))
            else:
                result = Expression(result._head, cases, default)
        else:
            result = Expression("Simplify", result,
                                assuming).evaluate(evaluation)
        return result
Пример #18
0
    def apply(self, eqs, vars, evaluation):
        'Solve[eqs_, vars_]'

        vars_original = vars
        head_name = vars.get_head_name()
        if head_name == 'List':
            vars = vars.leaves
        else:
            vars = [vars]
        for var in vars:
            if (var.is_atom()
                    and not var.is_symbol()) or head_name in ('Plus', 'Times',
                                                              'Power'):
                evaluation.message('Solve', 'ivar', vars_original)
                return
        eqs_original = eqs
        if eqs.get_head_name() in ('List', 'And'):
            eqs = eqs.leaves
        else:
            eqs = [eqs]
        sympy_eqs = []
        sympy_denoms = []
        for eq in eqs:
            symbol_name = eq.get_name()
            if symbol_name == 'True':
                #return Expression('List', Expression('List'))
                pass
            elif symbol_name == 'False':
                return Expression('List')
            elif not eq.has_form('Equal', 2):
                return evaluation.message('Solve', 'eqf', eqs_original)
            else:
                left, right = eq.leaves
                left = left.to_sympy()
                right = right.to_sympy()
                #vars_sympy = [var.to_sympy() for var in vars]
                eq = left - right
                eq = sympy.together(eq)
                eq = sympy.cancel(eq)
                sympy_eqs.append(eq)
                numer, denom = eq.as_numer_denom()
                sympy_denoms.append(denom)
        #eqs = actual_eqs

        #left, right = eq.leaves

        vars_sympy = [var.to_sympy() for var in vars]

        # delete unused variables to avoid SymPy's
        # PolynomialError: Not a zero-dimensional system
        # in e.g. Solve[x^2==1&&z^2==-1,{x,y,z}]
        all_vars = vars[:]
        all_vars_sympy = vars_sympy[:]
        #for index, var in enumerate(all_vars):
        #    if eqs_original.is_free(var, evaluation):
        vars = []
        vars_sympy = []
        for var, var_sympy in zip(all_vars, all_vars_sympy):
            pattern = Pattern.create(var)
            if not eqs_original.is_free(pattern, evaluation):
                vars.append(var)
                vars_sympy.append(var_sympy)

        def transform_dict(sols):
            #print "Transform %s" % sols
            if not sols:
                yield sols
            for var, sol in sols.iteritems():
                rest = sols.copy()
                del rest[var]
                rest = transform_dict(rest)
                if not isinstance(sol, (tuple, list)):
                    #print "Convert %s (type %s)" % (sol, type(sol))
                    sol = [sol]
                if not sol:
                    for r in rest:
                        #print "Yield %s" % r
                        yield r
                else:
                    for r in rest:
                        for item in sol:
                            #print "Yield %s with new %s" % (r, item)
                            new_sols = r.copy()
                            new_sols[var] = item
                            yield new_sols
                break

        def transform_solution(sol):
            #if isinstance(sol, (list, tuple)):
            if not isinstance(sol, dict):
                if not isinstance(sol, (list, tuple)):
                    sol = [sol]
                sol = dict(zip(vars_sympy, sol))
            #return sol
            return transform_dict(sol)

        if not sympy_eqs:
            sympy_eqs = True
        elif len(sympy_eqs) == 1:
            sympy_eqs = sympy_eqs[0]

        #eq = left - right
        #eq = sympy.together(eq)
        #eq = sympy.cancel(eq)   # otherwise Solve[f''[x]==0,x] for f[x_]:=4 x / (x ^ 2 + 3 x + 5) takes forever
        try:
            #print sympy_eqs
            result = sympy.solve(sympy_eqs, vars_sympy)
            #print result
            if not isinstance(result, list):
                result = [result]
            if result == [True]:
                return Expression('List', Expression('List'))
            if result == [None]:
                return Expression('List')
            #print result
            #result = [transform_solution(sol) for sol in result]
            results = []
            for sol in result:
                results.extend(transform_solution(sol))
            result = results
            #print result
            if any(sol and any(var not in sol for var in all_vars_sympy)
                   for sol in result):
                evaluation.message('Solve', 'svars')
            #numer, denom = eq.as_numer_denom()
            #for sol in result:
            #    sol_denom = denom.subs({var_sympy: sol})
            result = [
                sol for sol in result if all(
                    sympy.simplify(denom.subs(sol)) != 0
                    for denom in sympy_denoms)
            ]  # filter out results for which denominator is 0
            # (SymPy should actually do that itself, but it doesn't!)
            return Expression(
                'List',
                *(Expression(
                    'List',
                    *(Expression('Rule', var, from_sympy(sol[var_sympy]))
                      for var, var_sympy in zip(vars, vars_sympy)
                      if var_sympy in sol)) for sol in result))
        #except TypeError:
        #evaluation.message('Solve', 'ivar', vars_original)
        #raise
        except sympy.PolynomialError:
            # raised for e.g. Solve[x^2==1&&z^2==-1,{x,y,z}] when not deleting unused variables beforehand
            pass
        except NotImplementedError:
            pass
Пример #19
0
    def apply(self, eqs, vars, evaluation):
        'Solve[eqs_, vars_]'

        vars_original = vars
        head_name = vars.get_head_name()
        if head_name == 'System`List':
            vars = vars.leaves
        else:
            vars = [vars]
        for var in vars:
            if ((var.is_atom() and not var.is_symbol()) or  # noqa
                head_name in ('System`Plus', 'System`Times', 'System`Power') or
                'System`Constant' in var.get_attributes(evaluation.definitions)):

                evaluation.message('Solve', 'ivar', vars_original)
                return
        eqs_original = eqs
        if eqs.get_head_name() in ('System`List', 'System`And'):
            eqs = eqs.leaves
        else:
            eqs = [eqs]
        sympy_eqs = []
        sympy_denoms = []
        for eq in eqs:
            symbol_name = eq.get_name()
            if symbol_name == 'System`True':
                pass
            elif symbol_name == 'System`False':
                return Expression('List')
            elif not eq.has_form('Equal', 2):
                return evaluation.message('Solve', 'eqf', eqs_original)
            else:
                left, right = eq.leaves
                left = left.to_sympy()
                right = right.to_sympy()
                eq = left - right
                eq = sympy.together(eq)
                eq = sympy.cancel(eq)
                sympy_eqs.append(eq)
                numer, denom = eq.as_numer_denom()
                sympy_denoms.append(denom)

        vars_sympy = [var.to_sympy() for var in vars]

        # delete unused variables to avoid SymPy's
        # PolynomialError: Not a zero-dimensional system
        # in e.g. Solve[x^2==1&&z^2==-1,{x,y,z}]
        all_vars = vars[:]
        all_vars_sympy = vars_sympy[:]
        vars = []
        vars_sympy = []
        for var, var_sympy in zip(all_vars, all_vars_sympy):
            pattern = Pattern.create(var)
            if not eqs_original.is_free(pattern, evaluation):
                vars.append(var)
                vars_sympy.append(var_sympy)

        def transform_dict(sols):
            if not sols:
                yield sols
            for var, sol in six.iteritems(sols):
                rest = sols.copy()
                del rest[var]
                rest = transform_dict(rest)
                if not isinstance(sol, (tuple, list)):
                    sol = [sol]
                if not sol:
                    for r in rest:
                        yield r
                else:
                    for r in rest:
                        for item in sol:
                            new_sols = r.copy()
                            new_sols[var] = item
                            yield new_sols
                break

        def transform_solution(sol):
            if not isinstance(sol, dict):
                if not isinstance(sol, (list, tuple)):
                    sol = [sol]
                sol = dict(list(zip(vars_sympy, sol)))
            return transform_dict(sol)

        if not sympy_eqs:
            sympy_eqs = True
        elif len(sympy_eqs) == 1:
            sympy_eqs = sympy_eqs[0]

        try:
            if isinstance(sympy_eqs, bool):
                result = sympy_eqs
            else:
                result = sympy.solve(sympy_eqs, vars_sympy)
            if not isinstance(result, list):
                result = [result]
            if (isinstance(result, list) and len(result) == 1 and
                    result[0] is True):
                return Expression('List', Expression('List'))
            if result == [None]:
                return Expression('List')
            results = []
            for sol in result:
                results.extend(transform_solution(sol))
            result = results
            if any(sol and any(var not in sol for var in all_vars_sympy)
                   for sol in result):
                evaluation.message('Solve', 'svars')

            # Filter out results for which denominator is 0
            # (SymPy should actually do that itself, but it doesn't!)
            result = [sol for sol in result if all(
                sympy.simplify(denom.subs(sol)) != 0 for denom in sympy_denoms)]

            return Expression('List', *(Expression(
                'List',
                *(Expression('Rule', var, from_sympy(sol[var_sympy]))
                  for var, var_sympy in zip(vars, vars_sympy)
                  if var_sympy in sol)
            ) for sol in result))
        except sympy.PolynomialError:
            # raised for e.g. Solve[x^2==1&&z^2==-1,{x,y,z}] when not deleting
            # unused variables beforehand
            pass
        except NotImplementedError:
            pass
        except TypeError as exc:
            if str(exc).startswith("expected Symbol, Function or Derivative"):
                evaluation.message('Solve', 'ivar', vars_original)
Пример #20
0
 def apply(self, eqs, vars, evaluation):
     'Solve[eqs_, vars_]'
     
     vars_original = vars
     head_name = vars.get_head_name()
     if head_name == 'List':
         vars = vars.leaves
     else:
         vars = [vars]
     for var in vars:
         if (var.is_atom() and not var.is_symbol()) or head_name in ('Plus', 'Times', 'Power'):
             evaluation.message('Solve', 'ivar', vars_original)
             return
     eqs_original = eqs
     if eqs.get_head_name() in ('List', 'And'):
         eqs = eqs.leaves
     else:
         eqs = [eqs]
     sympy_eqs = []
     sympy_denoms = []
     for eq in eqs:
         symbol_name = eq.get_name()
         if symbol_name == 'True':
             #return Expression('List', Expression('List'))
             pass
         elif symbol_name == 'False':
             return Expression('List')
         elif not eq.has_form('Equal', 2):
             return evaluation.message('Solve', 'eqf', eqs_original)
         else:
             left, right = eq.leaves
             left = left.to_sympy()
             right = right.to_sympy()
             #vars_sympy = [var.to_sympy() for var in vars]
             eq = left - right
             eq = sympy.together(eq)
             eq = sympy.cancel(eq)                
             sympy_eqs.append(eq)
             numer, denom = eq.as_numer_denom()
             sympy_denoms.append(denom)
     #eqs = actual_eqs
     
     #left, right = eq.leaves
     
     vars_sympy = [var.to_sympy() for var in vars]
     
     # delete unused variables to avoid SymPy's
     # PolynomialError: Not a zero-dimensional system
     # in e.g. Solve[x^2==1&&z^2==-1,{x,y,z}]
     all_vars = vars[:]
     all_vars_sympy = vars_sympy[:]
     #for index, var in enumerate(all_vars):
     #    if eqs_original.is_free(var, evaluation):
     vars = []
     vars_sympy = []   
     for var, var_sympy in zip(all_vars, all_vars_sympy):
         pattern = Pattern.create(var)
         if not eqs_original.is_free(pattern, evaluation):
             vars.append(var)
             vars_sympy.append(var_sympy)
     
     def transform_dict(sols):
         #print "Transform %s" % sols
         if not sols:
             yield sols
         for var, sol in sols.iteritems():
             rest = sols.copy()
             del rest[var]
             rest = transform_dict(rest)
             if not isinstance(sol, (tuple, list)):
                 #print "Convert %s (type %s)" % (sol, type(sol))
                 sol = [sol]
             if not sol:
                 for r in rest:
                     #print "Yield %s" % r
                     yield r
             else:
                 for r in rest:
                     for item in sol:
                         #print "Yield %s with new %s" % (r, item)
                         new_sols = r.copy()
                         new_sols[var] = item
                         yield new_sols
             break
     
     def transform_solution(sol):
         #if isinstance(sol, (list, tuple)):
         if not isinstance(sol, dict):
             if not isinstance(sol, (list, tuple)):
                 sol = [sol]
             sol = dict(zip(vars_sympy, sol))
         #return sol
         return transform_dict(sol)
     
     if not sympy_eqs:
         sympy_eqs = True
     elif len(sympy_eqs) == 1:
         sympy_eqs = sympy_eqs[0]
         
     #eq = left - right
     #eq = sympy.together(eq)
     #eq = sympy.cancel(eq)   # otherwise Solve[f''[x]==0,x] for f[x_]:=4 x / (x ^ 2 + 3 x + 5) takes forever
     try:
         #print sympy_eqs
         result = sympy.solve(sympy_eqs, vars_sympy)
         #print result
         if not isinstance(result, list):
             result = [result]
         if result == [True]:
             return Expression('List', Expression('List'))
         if result == [None]:
             return Expression('List')
         #print result
         #result = [transform_solution(sol) for sol in result]
         results = []
         for sol in result:
             results.extend(transform_solution(sol))
         result = results
         #print result
         if any(sol and any(var not in sol for var in all_vars_sympy) for sol in result):
             evaluation.message('Solve', 'svars')
         #numer, denom = eq.as_numer_denom()
         #for sol in result:
         #    sol_denom = denom.subs({var_sympy: sol})
         result = [sol for sol in result if all(sympy.simplify(denom.subs(sol)) != 0 for denom in sympy_denoms)]   # filter out results for which denominator is 0
             # (SymPy should actually do that itself, but it doesn't!)
         return Expression('List', *(Expression('List', *(Expression('Rule', var, from_sympy(sol[var_sympy]))
             for var, var_sympy in zip(vars, vars_sympy) if var_sympy in sol)) for sol in result))
     #except TypeError:
         #evaluation.message('Solve', 'ivar', vars_original)
         #raise
     except sympy.PolynomialError:
         # raised for e.g. Solve[x^2==1&&z^2==-1,{x,y,z}] when not deleting unused variables beforehand
         pass
     except NotImplementedError:
         pass