def apply(self, expr, x, x0, evaluation, options={}): 'Limit[expr_, x_->x0_, OptionsPattern[Limit]]' expr = expr.to_sympy() x = x.to_sympy() x0 = x0.to_sympy() direction = self.get_option(options, 'Direction', evaluation) value = direction.get_int_value() if value not in (-1, 1): evaluation.message('Limit', 'ldir', direction) if value > 0: dir_sympy = '-' else: dir_sympy = '+' try: result = sympy.limit(expr, x, x0, dir_sympy) return from_sympy(result) except sympy.PoleError: pass except RuntimeError: # Bug in Sympy: RuntimeError: maximum recursion depth exceeded while calling a Python object pass except NotImplementedError: pass
def apply(self, expr, evaluation): 'Together[expr_]' expr_sympy = expr.to_sympy() result = sympy.together(expr_sympy) result = from_sympy(result) result = cancel(result) return result
def apply(self, expr, var, evaluation): 'Apart[expr_, var_Symbol]' expr_sympy = expr.to_sympy() var_sympy = var.to_sympy() result = sympy.apart(expr_sympy, var_sympy) result = from_sympy(result) return result
def cancel(expr): if expr.has_form('Plus', None): return Expression('Plus', *[cancel(leaf) for leaf in expr.leaves]) else: result = expr.to_sympy() #result = sympy.powsimp(result, deep=True) result = sympy.cancel(result) result = sympy_factor(result) # cancel factors out rationals, so we factor them again return from_sympy(result)
def apply(self, expr, evaluation): 'Simplify[expr_]' expr_sympy = expr.to_sympy() result = expr_sympy result = sympy.simplify(result) result = sympy.trigsimp(result) result = sympy.together(result) result = sympy.cancel(result) result = from_sympy(result) return result
def apply(self, expr, var, evaluation): 'Apart[expr_, var_Symbol]' expr_sympy = expr.to_sympy() var_sympy = var.to_sympy() try: result = sympy.apart(expr_sympy, var_sympy) result = from_sympy(result) return result except sympy.PolynomialError: # raised e.g. for apart(sin(1/(x**2-y**2))) return expr
def cancel(expr): if expr.has_form('Plus', None): return Expression('Plus', *[cancel(leaf) for leaf in expr.leaves]) else: try: result = expr.to_sympy() #result = sympy.powsimp(result, deep=True) result = sympy.cancel(result) result = sympy_factor(result) # cancel factors out rationals, so we factor them again return from_sympy(result) except sympy.PolynomialError: # e.g. for non-commutative expressions return expr
def apply(self, expr, evaluation): 'Factor[expr_]' expr_sympy = expr.to_sympy() try: result = sympy.together(expr_sympy) numer, denom = result.as_numer_denom() if denom == 1: result = sympy.factor(expr_sympy) else: result = sympy.factor(numer) / sympy.factor(denom) except sympy.PolynomialError: return expr return from_sympy(result)
def cancel(expr): if expr.has_form('Plus', None): return Expression('Plus', *[cancel(leaf) for leaf in expr.leaves]) else: try: result = expr.to_sympy() #result = sympy.powsimp(result, deep=True) result = sympy.cancel(result) result = sympy_factor( result ) # cancel factors out rationals, so we factor them again return from_sympy(result) except sympy.PolynomialError: # e.g. for non-commutative expressions return expr
def apply(self, expr, evaluation): 'Simplify[expr_]' expr_sympy = expr.to_sympy() result = expr_sympy try: result = sympy.simplify(result) except TypeError: #XXX What's going on here? pass result = sympy.trigsimp(result) result = sympy.together(result) result = sympy.cancel(result) result = from_sympy(result) return result
def apply(self, f, xs, evaluation): 'Integrate[f_, xs__]' f_sympy = f.to_sympy() if 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() else: a = b = None a_mathics, b_mathics = a, b if not x.get_name(): evaluation.message('Integrate', 'ilim') return x = x.to_sympy() 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: result = sympy.N(result) result = from_sympy(result) return result
def apply(self, f, xs, evaluation): 'Integrate[f_, xs__]' f_sympy = f.to_sympy() if 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() else: a = b = None a_mathics, b_mathics = a, b if not x.get_name(): evaluation.message('Integrate', 'ilim') return x = x.to_sympy() 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 if prec is not None: result = sympy.N(result) result = from_sympy(result) return result
def apply(self, f, xs, evaluation): "Integrate[f_, xs__]" f_sympy = f.to_sympy() if 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() else: a = b = None a_mathics, b_mathics = a, b if not x.get_name(): evaluation.message("Integrate", "ilim") return x = x.to_sympy() 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 if prec is not None: result = sympy.N(result) result = from_sympy(result) return result
def apply(self, expr, x, x0, evaluation, options={}): "Limit[expr_, x_->x0_, OptionsPattern[Limit]]" expr = expr.to_sympy() x = x.to_sympy() x0 = x0.to_sympy() direction = self.get_option(options, "Direction", evaluation) value = direction.get_int_value() if value not in (-1, 1): evaluation.message("Limit", "ldir", direction) if value > 0: dir_sympy = "-" else: dir_sympy = "+" try: result = sympy.limit(expr, x, x0, dir_sympy) return from_sympy(result) except sympy.PoleError: pass except NotImplementedError: pass
def apply(self, expr, evaluation): 'Denominator[expr_]' sympy_expr = expr.to_sympy() numer, denom = sympy_expr.as_numer_denom() return from_sympy(denom)
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
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
def apply(self, eqn, y, x, evaluation): 'DSolve[eqn_, y_, x_]' if eqn.has_form('List', eqn): #TODO: Try and solve BVPs using Solve or something analagous OR add this functonality to sympy. evaluation.message('DSolve', 'symsys') return if eqn.get_head_name() != 'Equal': evaluation.message('DSolve', 'deqn', eqn) return if (x.is_atom() and not x.is_symbol()) or \ x.get_head_name() in ('Plus', 'Times', 'Power') or \ 'Constant' in x.get_attributes(evaluation.definitions): evaluation.message('DSolve', 'dsvar') return # Fixes pathalogical DSolve[y''[x] == y[x], y, x] try: y.leaves function_form = None func = y except AttributeError: func = Expression(y, x) function_form = Expression('List', x) if func.is_atom(): evaluation.message('DSolve', 'dsfun', y) return if len(func.leaves) != 1: evaluation.message('DSolve', 'symmua') return if x not in func.leaves: evaluation.message('DSolve', 'deqx') return left, right = eqn.leaves eqn = Expression('Plus', left, Expression('Times', -1, right)).evaluate(evaluation) sym_eq = eqn.to_sympy(converted_functions = set([func.get_head_name()])) sym_x = sympy.symbols(str(sympy_symbol_prefix + x.name)) sym_func = sympy.Function(str(sympy_symbol_prefix + func.get_head_name())) (sym_x) try: sym_result = sympy.dsolve(sym_eq, sym_func) if not isinstance(sym_result, list): sym_result = [sym_result] except ValueError as e: evaluation.message('DSolve', 'symimp') return except NotImplementedError as e: evaluation.message('DSolve', 'symimp') return except AttributeError as e: evaluation.message('DSolve', 'litarg', eqn) return except KeyError: evaluation.message('DSolve', 'litarg', eqn) return if function_form is None: return Expression('List', *[Expression('List', Expression('Rule', *from_sympy(soln).leaves)) for soln in sym_result]) else: return Expression('List', *[Expression('List', Expression('Rule', y, Expression('Function', function_form, *from_sympy(soln).leaves[1:]))) for soln in sym_result])
def apply(self, eqns, a, n, evaluation): 'RSolve[eqns_, a_, n_]' #TODO: Do this with rules? if not eqns.has_form('List', None): eqns = Expression('List', eqns) if len(eqns.leaves) == 0: return for eqn in eqns.leaves: if eqn.get_head_name() != 'Equal': evaluation.message('RSolve', 'deqn', eqn) return if (n.is_atom() and not n.is_symbol()) or \ n.get_head_name() in ('Plus', 'Times', 'Power') or \ 'Constant' in n.get_attributes(evaluation.definitions): evaluation.message('RSolve', 'dsvar') return try: a.leaves function_form = None func = a except AttributeError: func = Expression(a, n) function_form = Expression('List', n) if func.is_atom() or len(func.leaves) != 1: evaluation.message('RSolve', 'dsfun', a) if n not in func.leaves: evaluation.message('DSolve', 'deqx') # Seperate relations from conditions conditions = {} def is_relation(eqn): left, right = eqn.leaves for l,r in [(left, right), (right, left)]: if left.get_head_name() == func.get_head_name() and len(left.leaves) == 1 \ and isinstance(l.leaves[0].to_python(), int) and r.is_numeric(): conditions[l.leaves[0].to_python()] = r.to_sympy() return False return True relation = filter(is_relation, eqns.leaves)[0] left, right = relation.leaves relation = Expression('Plus', left, Expression('Times', -1, right)).evaluate(evaluation) sym_eq = relation.to_sympy(converted_functions = set([func.get_head_name()])) sym_n = sympy.symbols(str(sympy_symbol_prefix + n.name)) sym_func = sympy.Function(str(sympy_symbol_prefix + func.get_head_name())) (sym_n) sym_conds = {} for cond in conditions: sym_conds[sympy.Function(str(sympy_symbol_prefix + func.get_head_name()))(cond)] = conditions[cond] try: # Sympy raises error when given empty conditions. Fixed in upcomming sympy release. if sym_conds != {}: sym_result = sympy.rsolve(sym_eq, sym_func, sym_conds) else: sym_result = sympy.rsolve(sym_eq, sym_func) if not isinstance(sym_result, list): sym_result = [sym_result] except ValueError as ve: return if function_form is None: return Expression('List', *[Expression('List', Expression('Rule', a, from_sympy(soln))) for soln in sym_result]) else: return Expression('List', *[Expression('List', Expression('Rule', a, Expression('Function', function_form, from_sympy(soln)))) for soln in sym_result])
def apply(self, eqns, a, n, evaluation): 'RSolve[eqns_, a_, n_]' #TODO: Do this with rules? if not eqns.has_form('List', None): eqns = Expression('List', eqns) if len(eqns.leaves) == 0: return for eqn in eqns.leaves: if eqn.get_head_name() != 'Equal': evaluation.message('RSolve', 'deqn', eqn) return if (n.is_atom() and not n.is_symbol()) or \ n.get_head_name() in ('Plus', 'Times', 'Power') or \ 'Constant' in n.get_attributes(evaluation.definitions): evaluation.message('RSolve', 'dsvar') return try: a.leaves function_form = None func = a except AttributeError: func = Expression(a, n) function_form = Expression('List', n) if func.is_atom() or len(func.leaves) != 1: evaluation.message('RSolve', 'dsfun', a) if n not in func.leaves: evaluation.message('DSolve', 'deqx') # Seperate relations from conditions conditions = {} def is_relation(eqn): left, right = eqn.leaves for l, r in [(left, right), (right, left)]: if left.get_head_name() == func.get_head_name() and len(left.leaves) == 1 \ and isinstance(l.leaves[0].to_python(), int) and r.is_numeric(): conditions[l.leaves[0].to_python()] = r.to_sympy() return False return True relation = filter(is_relation, eqns.leaves)[0] left, right = relation.leaves relation = Expression('Plus', left, Expression('Times', -1, right)).evaluate(evaluation) sym_eq = relation.to_sympy( converted_functions=set([func.get_head_name()])) sym_n = sympy.symbols(str(sympy_symbol_prefix + n.name)) sym_func = sympy.Function( str(sympy_symbol_prefix + func.get_head_name()))(sym_n) sym_conds = {} for cond in conditions: sym_conds[sympy.Function( str(sympy_symbol_prefix + func.get_head_name()))(cond)] = conditions[cond] try: # Sympy raises error when given empty conditions. Fixed in upcomming sympy release. if sym_conds != {}: sym_result = sympy.rsolve(sym_eq, sym_func, sym_conds) else: sym_result = sympy.rsolve(sym_eq, sym_func) if not isinstance(sym_result, list): sym_result = [sym_result] except ValueError as ve: return if function_form is None: return Expression( 'List', *[ Expression('List', Expression('Rule', a, from_sympy(soln))) for soln in sym_result ]) else: return Expression( 'List', *[ Expression( 'List', Expression( 'Rule', a, Expression('Function', function_form, from_sympy(soln)))) for soln in sym_result ])
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') or \ 'Constant' in var.get_attributes(evaluation.definitions): 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': 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() 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 sols.iteritems(): 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(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 result == [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') 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 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, exc: if str(exc).startswith("expected Symbol, Function or Derivative"): evaluation.message('Solve', 'ivar', vars_original)