def apply(self, f, i, evaluation): 'Root[f_, i_]' try: if not f.has_form('Function', 1): raise sympy.PolynomialError body = f.leaves[0] poly = body.replace_slots([f, Symbol('_1')], evaluation) idx = i.to_sympy() - 1 # Check for negative indeces (they are not allowed in Mathematica) if idx < 0: evaluation.message('Root', 'iidx', i) return r = sympy.CRootOf(poly.to_sympy(), idx) except sympy.PolynomialError: evaluation.message('Root', 'nuni', f) return except TypeError: evaluation.message('Root', 'nint', i) return except IndexError: evaluation.message('Root', 'iidx', i) return return from_sympy(r)
def apply(self, f, x, x0, evaluation, options): "FindRoot[f_, {x_, x0_}, OptionsPattern[]]" # First, determine x0 and x x0 = apply_N(x0, evaluation) if not isinstance(x0, Number): evaluation.message("FindRoot", "snum", x0) return x_name = x.get_name() if not x_name: evaluation.message("FindRoot", "sym", x, 2) return # Now, get the explicit form of f, depending of x # keeping x without evaluation (Like inside a "Block[{x},f]) f = dynamic_scoping(lambda ev: f.evaluate(ev), {x_name: None}, evaluation) # If after evaluation, we get an "Equal" expression, # convert it in a function by substracting both # members. Again, ensure the scope in the evaluation if f.get_head_name() == "System`Equal": f = Expression("Plus", f.leaves[0], Expression("Times", Integer(-1), f.leaves[1])) f = dynamic_scoping(lambda ev: f.evaluate(ev), {x_name: None}, evaluation) # Determine the method method = options["System`Method"] if isinstance(method, Symbol): method = method.get_name().split("`")[-1] if method == "Automatic": method = "Newton" elif not isinstance(method, String): method = None evaluation.message("FindRoot", "bdmthd", method, [String(m) for m in self.methods.keys()]) return else: method = method.value # Determine the "jacobian" if method in ("Newton", ) and options["System`Jacobian"].sameQ( Symbol("Automatic")): def diff(evaluation): return Expression("D", f, x).evaluate(evaluation) d = dynamic_scoping(diff, {x_name: None}, evaluation) options["System`Jacobian"] = d method = self.methods.get(method, None) if method is None: evaluation.message("FindRoot", "bdmthd", method, [String(m) for m in self.methods.keys()]) return x0, success = method(f, x0, x, options, evaluation) if not success: return return Expression(SymbolList, Expression(SymbolRule, x, x0))
def to_sympy(self, expr, **kwargs): try: if not expr.has_form('Root', 2): return None f = expr.leaves[0] if not f.has_form('Function', 1): return None body = f.leaves[0].replace_slots([f, Symbol('_1')], None) poly = body.to_sympy(**kwargs) i = expr.leaves[1].get_int_value(**kwargs) if i is None: return None return sympy.CRootOf(poly, i) except: return None
def find_root_newton(f, x0, x, opts, evaluation) -> (Number, bool): df = opts["System`Jacobian"] maxit = opts["System`MaxIterations"] x_name = x.get_name() if maxit.sameQ(Symbol("Automatic")): maxit = 100 else: maxit = maxit.evaluate(evaluation).get_int_value() def sub(evaluation): d_value = df.evaluate(evaluation) if d_value == Integer(0): return None return Expression( "Times", f, Expression("Power", d_value, Integer(-1)) ).evaluate(evaluation) count = 0 while count < maxit: minus = dynamic_scoping(sub, {x_name: x0}, evaluation) if minus is None: evaluation.message("FindRoot", "dsing", x, x0) return x0, False x1 = Expression("Plus", x0, Expression("Times", Integer(-1), minus)).evaluate( evaluation ) if not isinstance(x1, Number): evaluation.message("FindRoot", "nnum", x, x0) return x0, False # TODO: use Precision goal... if x1 == x0: break x0 = Expression(SymbolN, x1).evaluate( evaluation ) # N required due to bug in sympy arithmetic count += 1 else: evaluation.message("FindRoot", "maxiter") return x0, True
def find_root_secant(f, x0, x, opts, evaluation) -> (Number, bool): region = opts.get("$$Region", None) if not type(region) is list: if x0.is_zero: region = (Real(-1), Real(1)) else: xmax = 2 * x0.to_python() xmin = -2 * x0.to_python() if xmin > xmax: region = (Real(xmax), Real(xmin)) else: region = (Real(xmin), Real(xmax)) maxit = opts["System`MaxIterations"] x_name = x.get_name() if maxit.sameQ(Symbol("Automatic")): maxit = 100 else: maxit = maxit.evaluate(evaluation).get_int_value() x0 = from_python(region[0]) x1 = from_python(region[1]) f0 = dynamic_scoping(lambda ev: f.evaluate(evaluation), {x_name: x0}, evaluation) f1 = dynamic_scoping(lambda ev: f.evaluate(evaluation), {x_name: x1}, evaluation) if not isinstance(f0, Number): return x0, False if not isinstance(f1, Number): return x0, False f0 = f0.to_python(n_evaluation=True) f1 = f1.to_python(n_evaluation=True) count = 0 while count < maxit: if f0 == f1: x1 = Expression( "Plus", x0, Expression( "Times", Real(0.75), Expression("Plus", x1, Expression("Times", Integer(-1), x0)), ), ) x1 = x1.evaluate(evaluation) f1 = dynamic_scoping(lambda ev: f.evaluate(evaluation), {x_name: x1}, evaluation) if not isinstance(f1, Number): return x0, False f1 = f1.to_python(n_evaluation=True) continue inv_deltaf = from_python(1.0 / (f1 - f0)) num = Expression( "Plus", Expression("Times", x0, f1), Expression("Times", x1, f0, Integer(-1)), ) x2 = Expression("Times", num, inv_deltaf) x2 = x2.evaluate(evaluation) f2 = dynamic_scoping(lambda ev: f.evaluate(evaluation), {x_name: x2}, evaluation) if not isinstance(f2, Number): return x0, False f2 = f2.to_python(n_evaluation=True) f1, f0 = f2, f1 x1, x0 = x2, x1 if x1 == x0 or abs(f2) == 0: break count = count + 1 else: evaluation.message("FindRoot", "maxiter") return x0, False return x0, True
SymbolFalse, SymbolList, SymbolRule, SymbolUndefined, from_python, ) from mathics.core.convert import sympy_symbol_prefix, SympyExpression, from_sympy from mathics.core.rules import Pattern from mathics.core.numbers import dps from mathics.builtin.scoping import dynamic_scoping from mathics.builtin.numeric import apply_N from mathics import Symbol import sympy SymbolPlus = Symbol("Plus") SymbolTimes = Symbol("Times") SymbolPower = Symbol("Power") IntegerZero = Integer(0) IntegerMinusOne = Integer(-1) class D(SympyFunction): """ <dl> <dt>'D[$f$, $x$]' <dd>gives the partial derivative of $f$ with respect to $x$. <dt>'D[$f$, $x$, $y$, ...]' <dd>differentiates successively with respect to $x$, $y$, etc. <dt>'D[$f$, {$x$, $n$}]' <dd>gives the multiple derivative of order $n$.