예제 #1
0
    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)
예제 #2
0
    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))
예제 #3
0
    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
예제 #4
0
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
예제 #5
0
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
예제 #6
0
    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$.