Ejemplo n.º 1
0
    def _eval_(self, f, x):
        """
        EXAMPLES::

            sage: from sage.symbolic.integration.integral import indefinite_integral
            sage: indefinite_integral(exp(x), x) # indirect doctest
            e^x
            sage: indefinite_integral(exp(x), x^2)
            2*(x - 1)*e^x
        """
        # Check for x
        if not is_SymbolicVariable(x):
            if len(x.variables()) == 1:
                nx = x.variables()[0]
                f = f*x.diff(nx)
                x = nx
            else:
                return None

        # we try all listed integration algorithms
        for integrator in self.integrators:
            res = integrator(f, x)
            try:
                return integrator(f, x)
            except NotImplementedError:
                pass
        return None
Ejemplo n.º 2
0
    def _eval_(self, f, x, a, b):
        """
        Returns the results of symbolic evaluation of the integral

        EXAMPLES::

            sage: from sage.symbolic.integration.integral import definite_integral
            sage: definite_integral(exp(x),x,0,1) # indirect doctest
            e - 1
        """
        # Check for x
        if not is_SymbolicVariable(x):
            if len(x.variables()) == 1:
                nx = x.variables()[0]
                f = f*x.diff(nx)
                x = nx
            else:
                return None

        args = (f,x,a,b)

        # we try all listed integration algorithms
        for integrator in self.integrators:
            try:
                return integrator(*args)
            except NotImplementedError:
                pass
        return None
Ejemplo n.º 3
0
    def __init__(self, coordinates, metric = None):
        """
        An open subset of Euclidian space with a specific set of
        coordinates. See ``CoordinatePatch`` for details.

        INPUT::

        - ``coordinates`` -- a set of symbolic variables that serve
        as coordinates on this space.

        - ``metric`` (default: None) -- a metric tensor on this
        coordinate patch.  Providing anything other than ``None``
        is currently not defined.


        EXAMPLES::

            sage: x, y, z = var('x, y, z')
            sage: S = CoordinatePatch((x, y, z)); S
            Open subset of R^3 with coordinates x, y, z

        """

        from sage.symbolic.ring import is_SymbolicVariable

        if not all(is_SymbolicVariable(c) for c in coordinates):
            raise TypeError, "%s is not a valid vector of coordinates." % \
                coordinates

        self._coordinates = tuple(coordinates)
        dim = len(self._coordinates)

        if metric is not None:
            raise NotImplementedError, "Metric geometry not supported yet."
Ejemplo n.º 4
0
def preprocess_assumptions(args):
    """
    Turn a list of the form ``(var1, var2, ..., 'property')`` into a
    sequence of declarations ``(var1 is property), (var2 is property),
    ...``

    EXAMPLES::

        sage: from sage.symbolic.assumptions import preprocess_assumptions
        sage: preprocess_assumptions([x, 'integer', x > 4])
        [x is integer, x > 4]
        sage: var('x, y')
        (x, y)
        sage: preprocess_assumptions([x, y, 'integer', x > 4, y, 'even'])
        [x is integer, y is integer, x > 4, y is even]
    """
    args = list(args)
    last = None
    for i, x in reversed(list(enumerate(args))):
        if isinstance(x, str):
            del args[i]
            last = x
        elif ((not hasattr(x, 'assume') or is_SymbolicVariable(x))
              and last is not None):
            args[i] = GenericDeclaration(x, last)
        else:
            last = None
    return args
Ejemplo n.º 5
0
    def __init__(self, coordinates, metric = None):
        """
        An open subset of Euclidian space with a specific set of
        coordinates. See ``CoordinatePatch`` for details.

        INPUT:

        - ``coordinates`` -- a set of symbolic variables that serve
          as coordinates on this space.

        - ``metric`` (default: ``None``) -- a metric tensor on this
          coordinate patch.  Providing anything other than ``None``
          is currently not defined.

        EXAMPLES::

            sage: x, y, z = var('x, y, z')
            sage: S = CoordinatePatch((x, y, z)); S
            doctest:...: DeprecationWarning: Use Manifold instead.
            See http://trac.sagemath.org/24444 for details.
            Open subset of R^3 with coordinates x, y, z
        """
        from sage.symbolic.ring import is_SymbolicVariable
        from sage.misc.superseded import deprecation
        deprecation(24444, 'Use Manifold instead.')

        if not all(is_SymbolicVariable(c) for c in coordinates):
            raise TypeError("%s is not a valid vector of coordinates." % \
                coordinates)

        self._coordinates = tuple(coordinates)
        dim = len(self._coordinates)

        if metric is not None:
            raise NotImplementedError("Metric geometry not supported yet.")
Ejemplo n.º 6
0
    def __call__(self, *args):
        """
        EXAMPLES::

            sage: from sage.symbolic.operators import FDerivativeOperator
            sage: x,y = var('x,y')
            sage: f = function('foo')
            sage: op = FDerivativeOperator(f, [0,1])
            sage: op(x,y)
            D[0, 1](foo)(x, y)
        """
        if (not all(is_SymbolicVariable(x) for x in args) or
            len(args) != len(set(args))):
            raise NotImplementedError, "currently all arguments must be distinct variables"
        vars = [args[i] for i in self._parameter_set]
        return self._f(*args).diff(*vars)
Ejemplo n.º 7
0
    def create_key(self, args, check=True):
        """
        EXAMPLES::

            sage: x,y = var('x,y')
            sage: CallableSymbolicExpressionRing.create_key((x,y))
            (x, y)
        """
        if check:
            from sage.symbolic.ring import is_SymbolicVariable
            if len(args) == 1 and isinstance(args[0], (list, tuple)):
                args, = args
            for arg in args:
                if not is_SymbolicVariable(arg):
                    raise TypeError("Must construct a function with a tuple (or list) of variables.")
            args = tuple(args)
        return args
Ejemplo n.º 8
0
    def _print_latex_(self, f, x):
        """
        EXAMPLES::
        
            sage: from sage.symbolic.integration.integral import indefinite_integral
            sage: print_latex = indefinite_integral._print_latex_
            sage: var('x,a,b')
            (x, a, b)
            sage: f = function('f')
            sage: print_latex(f(x),x)
            '\\int f\\left(x\\right)\\,{d x}'
        """
        from sage.misc.latex import latex
        if not is_SymbolicVariable(x):
            dx_str = "{d \\left(%s\\right)}"%(latex(x))
        else:
            dx_str = "{d %s}"%(latex(x))

        return "\\int %s\\,%s"%(latex(f), dx_str)
Ejemplo n.º 9
0
    def _print_latex_(self, f, x):
        """
        EXAMPLES::

            sage: from sage.symbolic.integration.integral import indefinite_integral
            sage: print_latex = indefinite_integral._print_latex_
            sage: var('x,a,b')
            (x, a, b)
            sage: f = function('f')
            sage: print_latex(f(x),x)
            '\\int f\\left(x\\right)\\,{d x}'
            sage: latex(integrate(tan(x)/x, x))
            \int \frac{\tan\left(x\right)}{x}\,{d x}
        """
        from sage.misc.latex import latex
        if not is_SymbolicVariable(x):
            dx_str = "{d \\left(%s\\right)}"%(latex(x))
        else:
            dx_str = "{d %s}"%(latex(x))

        return "\\int %s\\,%s"%(latex(f), dx_str)
Ejemplo n.º 10
0
    def _print_latex_(self, f, x, a, b):
        r"""
        Returns LaTeX expression for integration of a symbolic function.

        EXAMPLES::

            sage: from sage.symbolic.integration.integral import definite_integral
            sage: print_latex = definite_integral._print_latex_
            sage: var('x,a,b')
            (x, a, b)
            sage: f = function('f')
            sage: print_latex(f(x),x,0,1)
            '\\int_{0}^{1} f\\left(x\\right)\\,{d x}'
            sage: latex(integrate(tan(x)/x, x, 0, 1))
            \int_{0}^{1} \frac{\tan\left(x\right)}{x}\,{d x}
        """
        from sage.misc.latex import latex
        if not is_SymbolicVariable(x):
            dx_str = "{d \\left(%s\\right)}"%(latex(x))
        else:
            dx_str = "{d %s}"%(latex(x))
        return "\\int_{%s}^{%s} %s\\,%s"%(latex(a), latex(b), latex(f), dx_str)
Ejemplo n.º 11
0
    def _print_latex_(self, f, x, a, b):
        r"""
        Convert this integral to LaTeX notation

        EXAMPLES::

            sage: from sage.symbolic.integration.integral import definite_integral
            sage: print_latex = definite_integral._print_latex_
            sage: var('x,a,b')
            (x, a, b)
            sage: f = function('f')
            sage: print_latex(f(x),x,0,1)
            '\\int_{0}^{1} f\\left(x\\right)\\,{d x}'
            sage: latex(integrate(tan(x)/x, x, 0, 1))
            \int_{0}^{1} \frac{\tan\left(x\right)}{x}\,{d x}
        """
        from sage.misc.latex import latex
        if not is_SymbolicVariable(x):
            dx_str = "{d \\left(%s\\right)}"%(latex(x))
        else:
            dx_str = "{d %s}"%(latex(x))
        return "\\int_{%s}^{%s} %s\\,%s"%(latex(a), latex(b), latex(f), dx_str)
Ejemplo n.º 12
0
 def _print_latex_(self, f, x, a, b):
     r"""
     Returns LaTeX expression for integration of a symbolic function.
     
     EXAMPLES::
     
         sage: from sage.symbolic.integration.integral import definite_integral
         sage: print_latex = definite_integral._print_latex_
         sage: var('x,a,b')
         (x, a, b)
         sage: f = function('f')
         sage: print_latex(f(x),x,0,1)
         '\\int_{0}^{1} f\\left(x\\right)\\,{d x}'
         sage: latex(integrate(1/(1+sqrt(x)),x,0,1))
         \int_{0}^{1} \frac{1}{\sqrt{x} + 1}\,{d x}
     """
     from sage.misc.latex import latex
     if not is_SymbolicVariable(x):
         dx_str = "{d \\left(%s\\right)}"%(latex(x))
     else:
         dx_str = "{d %s}"%(latex(x))
     return "\\int_{%s}^{%s} %s\\,%s"%(latex(a), latex(b), latex(f), dx_str)
Ejemplo n.º 13
0
    def __call__(self, *args):
        """
        EXAMPLES::

            sage: from sage.symbolic.operators import FDerivativeOperator
            sage: x,y = var('x,y')
            sage: f = function('foo')
            sage: op = FDerivativeOperator(f, [0,1])
            sage: op(x,y)
            diff(foo(x, y), x, y)
            sage: op(x,x^2)
            D[0, 1](foo)(x, x^2)

        TESTS:

        We should be able to operate on functions evaluated at a
        point, not just a symbolic variable, :trac:`12796`::

           sage: from sage.symbolic.operators import FDerivativeOperator
           sage: f = function('f')
           sage: op = FDerivativeOperator(f, [0])
           sage: op(1)
           D[0](f)(1)

        """
        if (not all(is_SymbolicVariable(x) for x in args) or
                len(args) != len(set(args))):
            # An evaluated derivative of the form f'(1) is not a
            # symbolic variable, yet we would like to treat it
            # like one. So, we replace the argument `1` with a
            # temporary variable e.g. `t0` and then evaluate the
            # derivative f'(t0) symbolically at t0=1. See trac
            # #12796.
            temp_args=[SR.var("t%s"%i) for i in range(len(args))]
            vars=[temp_args[i] for i in self._parameter_set]
            return self._f(*temp_args).diff(*vars).function(*temp_args)(*args)
        vars = [args[i] for i in self._parameter_set]
        return self._f(*args).diff(*vars)
Ejemplo n.º 14
0
    def __call__(self, *args):
        """
        EXAMPLES::

            sage: from sage.symbolic.operators import FDerivativeOperator
            sage: x,y = var('x,y')
            sage: f = function('foo')
            sage: op = FDerivativeOperator(f, [0,1])
            sage: op(x,y)
            D[0, 1](foo)(x, y)
            sage: op(x,x^2)
            D[0, 1](foo)(x, x^2)

        TESTS:

        We should be able to operate on functions evaluated at a
        point, not just a symbolic variable, :trac:`12796`::

           sage: from sage.symbolic.operators import FDerivativeOperator
           sage: f = function('f')
           sage: op = FDerivativeOperator(f, [0])
           sage: op(1)
           D[0](f)(1)

        """
        if (not all(is_SymbolicVariable(x) for x in args)
                or len(args) != len(set(args))):
            # An evaluated derivative of the form f'(1) is not a
            # symbolic variable, yet we would like to treat it
            # like one. So, we replace the argument `1` with a
            # temporary variable e.g. `t0` and then evaluate the
            # derivative f'(t0) symbolically at t0=1. See trac
            # #12796.
            temp_args = [SR.var("t%s" % i) for i in range(len(args))]
            vars = [temp_args[i] for i in self._parameter_set]
            return self._f(*temp_args).diff(*vars).function(*temp_args)(*args)
        vars = [args[i] for i in self._parameter_set]
        return self._f(*args).diff(*vars)
Ejemplo n.º 15
0
    def _eval_(self, f, x, a, b):
        """
        Return the results of symbolic evaluation of the integral.

        EXAMPLES::

            sage: from sage.symbolic.integration.integral import definite_integral
            sage: definite_integral(exp(x),x,0,1) # indirect doctest
            e - 1
        """
        # Check for x
        if not is_SymbolicVariable(x):
            if len(x.variables()) == 1:
                nx = x.variables()[0]
                f = f * x.diff(nx)
                x = nx
            else:
                return None

        args = (f, x, a, b)

        # we try all listed integration algorithms
        A = None
        for integrator in self.integrators:
            try:
                A = integrator(*args)
            except (NotImplementedError, TypeError, AttributeError,
                    RuntimeError):
                pass
            except ValueError:
                # maxima is telling us something
                raise
            else:
                if not hasattr(A, 'operator'):
                    return A
                elif not isinstance(A.operator(), DefiniteIntegral):
                    return A
        return A
Ejemplo n.º 16
0
def wronskian(*args):
    """
    Returns the Wronskian of the provided functions, differentiating with
    respect to the given variable. If no variable is provided,
    diff(f) is called for each function f.

    wronskian(f1,...,fn, x) returns the Wronskian of f1,...,fn, with
    derivatives taken with respect to x.

    wronskian(f1,...,fn) returns the Wronskian of f1,...,fn where
    k'th derivatives are computed by doing `.derivative(k)' on each
    function.

    The Wronskian of a list of functions is a determinant of derivatives.
    The nth row (starting from 0) is a list of the nth derivatives of the
    given functions.

    For two functions::

                              | f   g  |
                 W(f, g) = det|        | = f*g' - g*f'.
                              | f'  g' |

    EXAMPLES::
    
        sage: wronskian(e^x, x^2)
        -x^2*e^x + 2*x*e^x

        sage: x,y = var('x, y')
        sage: wronskian(x*y, log(x), x)
        -y*log(x) + y

    If your functions are in a list, you can use `*' to turn them into
    arguments to :func:`wronskian`::
    
        sage: wronskian(*[x^k for k in range(1, 5)])
        12*x^4

    If you want to use 'x' as one of the functions in the Wronskian,
    you can't put it last or it will be interpreted as the variable
    with respect to which we differentiate. There are several ways to
    get around this.

    Two-by-two Wronskian of sin(x) and e^x::
    
        sage: wronskian(sin(x), e^x, x)
        e^x*sin(x) - e^x*cos(x)

    Or don't put x last::
    
        sage: wronskian(x, sin(x), e^x)
        (e^x*sin(x) + e^x*cos(x))*x - 2*e^x*sin(x)

    Example where one of the functions is constant::
    
        sage: wronskian(1, e^(-x), e^(2*x))
        -6*e^x

    NOTES:

    - http://en.wikipedia.org/wiki/Wronskian
    - http://planetmath.org/encyclopedia/WronskianDeterminant.html

    AUTHORS: 

    - Dan Drake (2008-03-12)
    """
    if len(args) == 0:
        raise TypeError('wronskian() takes at least one argument (0 given)')
    elif len(args) == 1:
        # a 1x1 Wronskian is just its argument
        return args[0]
    else:
        if is_SymbolicVariable(args[-1]):
            # if last argument is a variable, peel it off and
            # differentiate the other args
            v = args[-1]
            fs = args[0:-1]
            row = lambda n: map(lambda f: diff(f, v, n), fs)
        else:
            # if the last argument isn't a variable, just run
            # .derivative on everything
            fs = args
            row = lambda n: map(lambda f: diff(f, n), fs)
        # NOTE: I rewrote the below as two lines to avoid a possible subtle
        # memory management problem on some platforms (only VMware as far
        # as we know?).  See trac #2990.
        # There may still be a real problem that this is just hiding for now.
        A = matrix(map(row, range(len(fs))))
        return A.determinant()
Ejemplo n.º 17
0
def solve(f, *args, **kwds):
    r"""
    Algebraically solve an equation or system of equations (over the
    complex numbers) for given variables. Inequalities and systems
    of inequalities are also supported.

    INPUT:

    -  ``f`` - equation or system of equations (given by a
       list or tuple)

    -  ``*args`` - variables to solve for.

    -  ``solution_dict`` - bool (default: False); if True or non-zero,
       return a list of dictionaries containing the solutions. If there
       are no solutions, return an empty list (rather than a list containing
       an empty dictionary). Likewise, if there's only a single solution,
       return a list containing one dictionary with that solution.

    There are a few optional keywords if you are trying to solve a single
    equation.  They may only be used in that context.

    -  ``multiplicities`` - bool (default: False); if True,
       return corresponding multiplicities.  This keyword is
       incompatible with ``to_poly_solve=True`` and does not make
       any sense when solving inequalities.

    -  ``explicit_solutions`` - bool (default: False); require that
       all roots be explicit rather than implicit. Not used
       when solving inequalities.

    -  ``to_poly_solve`` - bool (default: False) or string; use
       Maxima's ``to_poly_solver`` package to search for more possible
       solutions, but possibly encounter approximate solutions.
       This keyword is incompatible with ``multiplicities=True``
       and is not used when solving inequalities. Setting ``to_poly_solve``
       to 'force' (string) omits Maxima's solve command (useful when
       some solutions of trigonometric equations are lost).


    EXAMPLES::

        sage: x, y = var('x, y')
        sage: solve([x+y==6, x-y==4], x, y)
        [[x == 5, y == 1]]
        sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
        [[x == -1/2*I*sqrt(3) - 1/2, y == -sqrt(-1/2*I*sqrt(3) + 3/2)],
         [x == -1/2*I*sqrt(3) - 1/2, y == sqrt(-1/2*I*sqrt(3) + 3/2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == -sqrt(1/2*I*sqrt(3) + 3/2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == sqrt(1/2*I*sqrt(3) + 3/2)],
         [x == 0, y == -1],
         [x == 0, y == 1]]
        sage: solve([sqrt(x) + sqrt(y) == 5, x + y == 10], x, y)
        [[x == -5/2*I*sqrt(5) + 5, y == 5/2*I*sqrt(5) + 5], [x == 5/2*I*sqrt(5) + 5, y == -5/2*I*sqrt(5) + 5]]
        sage: solutions=solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y, solution_dict=True)
        sage: for solution in solutions: print("{} , {}".format(solution[x].n(digits=3), solution[y].n(digits=3)))
        -0.500 - 0.866*I , -1.27 + 0.341*I
        -0.500 - 0.866*I , 1.27 - 0.341*I
        -0.500 + 0.866*I , -1.27 - 0.341*I
        -0.500 + 0.866*I , 1.27 + 0.341*I
        0.000 , -1.00
        0.000 , 1.00

    Whenever possible, answers will be symbolic, but with systems of
    equations, at times approximations will be given, due to the
    underlying algorithm in Maxima::

        sage: sols = solve([x^3==y,y^2==x],[x,y]); sols[-1], sols[0]
        ([x == 0, y == 0], [x == (0.3090169943749475 + 0.9510565162951535*I), y == (-0.8090169943749475 - 0.5877852522924731*I)])
        sage: sols[0][0].rhs().pyobject().parent()
        Complex Double Field

    If ``f`` is only one equation or expression, we use the solve method
    for symbolic expressions, which defaults to exact answers only::

        sage: solve([y^6==y],y)
        [y == 1/4*sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, y == -1/4*sqrt(5) + 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, y == -1/4*sqrt(5) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, y == 1/4*sqrt(5) - 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, y == 1, y == 0]
        sage: solve( [y^6 == y], y)==solve( y^6 == y, y)
        True

    Here we demonstrate very basic use of the optional keywords for
    a single expression to be solved::

        sage: ((x^2-1)^2).solve(x)
        [x == -1, x == 1]
        sage: ((x^2-1)^2).solve(x,multiplicities=True)
        ([x == -1, x == 1], [2, 2])
        sage: solve(sin(x)==x,x)
        [x == sin(x)]
        sage: solve(sin(x)==x,x,explicit_solutions=True)
        []
        sage: solve(abs(1-abs(1-x)) == 10, x)
        [abs(abs(x - 1) - 1) == 10]
        sage: solve(abs(1-abs(1-x)) == 10, x, to_poly_solve=True)
        [x == -10, x == 12]

    .. note::

        For more details about solving a single equation, see
        the documentation for the single-expression
        :meth:`~sage.symbolic.expression.Expression.solve`.

    ::

        sage: from sage.symbolic.expression import Expression
        sage: Expression.solve(x^2==1,x)
        [x == -1, x == 1]

    We must solve with respect to actual variables::

        sage: z = 5
        sage: solve([8*z + y == 3, -z +7*y == 0],y,z)
        Traceback (most recent call last):
        ...
        TypeError: 5 is not a valid variable.

    If we ask for dictionaries containing the solutions, we get them::

        sage: solve([x^2-1],x,solution_dict=True)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-4*x+4],x,solution_dict=True)
        [{x: 2}]
        sage: res = solve([x^2 == y, y == 4],x,y,solution_dict=True)
        sage: for soln in res: print("x: %s, y: %s" % (soln[x], soln[y]))
        x: 2, y: 4
        x: -2, y: 4

    If there is a parameter in the answer, that will show up as
    a new variable.  In the following example, ``r1`` is a real free
    variable (because of the ``r``)::

        sage: solve([x+y == 3, 2*x+2*y == 6],x,y)
        [[x == -r1 + 3, y == r1]]

    Especially with trigonometric functions, the dummy variable may
    be implicitly an integer (hence the ``z``)::

        sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y)
        [[x == 1/4*pi + pi*z79, y == -1/4*pi - pi*z79]]

    Expressions which are not equations are assumed to be set equal
    to zero, as with `x` in the following example::

        sage: solve([x, y == 2],x,y)
        [[x == 0, y == 2]]

    If ``True`` appears in the list of equations it is
    ignored, and if ``False`` appears in the list then no
    solutions are returned. E.g., note that the first
    ``3==3`` evaluates to ``True``, not to a
    symbolic equation.

    ::

        sage: solve([3==3, 1.00000000000000*x^3 == 0], x)
        [x == 0]
        sage: solve([1.00000000000000*x^3 == 0], x)
        [x == 0]

    Here, the first equation evaluates to ``False``, so
    there are no solutions::

        sage: solve([1==3, 1.00000000000000*x^3 == 0], x)
        []

    Completely symbolic solutions are supported::

        sage: var('s,j,b,m,g')
        (s, j, b, m, g)
        sage: sys = [ m*(1-s) - b*s*j, b*s*j-g*j ];
        sage: solve(sys,s,j)
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,(s,j))
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,[s,j])
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]

    Inequalities can be also solved::

        sage: solve(x^2>8,x)
        [[x < -2*sqrt(2)], [x > 2*sqrt(2)]]

    We use ``use_grobner`` in Maxima if no solution is obtained from
    Maxima's ``to_poly_solve``::

       sage: x,y=var('x y'); c1(x,y)=(x-5)^2+y^2-16; c2(x,y)=(y-3)^2+x^2-9
       sage: solve([c1(x,y),c2(x,y)],[x,y])
       [[x == -9/68*sqrt(55) + 135/68, y == -15/68*sqrt(11)*sqrt(5) + 123/68], [x == 9/68*sqrt(55) + 135/68, y == 15/68*sqrt(11)*sqrt(5) + 123/68]]

    TESTS::

        sage: solve([sin(x)==x,y^2==x],x,y)
        [sin(x) == x, y^2 == x]
        sage: solve(0==1,x)
        Traceback (most recent call last):
        ...
        TypeError:  The first argument must be a symbolic expression or a list of symbolic expressions.

    Test if the empty list is returned, too, when (a list of)
    dictionaries (is) are requested (#8553)::

        sage: solve([SR(0)==1],x)
        []
        sage: solve([SR(0)==1],x,solution_dict=True)
        []
        sage: solve([x==1,x==-1],x)
        []
        sage: solve([x==1,x==-1],x,solution_dict=True)
        []
        sage: solve((x==1,x==-1),x,solution_dict=0)
        []

    Relaxed form, suggested by Mike Hansen (#8553)::

        sage: solve([x^2-1],x,solution_dict=-1)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-1],x,solution_dict=1)
        [{x: -1}, {x: 1}]
        sage: solve((x==1,x==-1),x,solution_dict=-1)
        []
        sage: solve((x==1,x==-1),x,solution_dict=1)
        []

    This inequality holds for any real ``x`` (:trac:`8078`)::

        sage: solve(x^4+2>0,x)
        [x < +Infinity]

    Test for user friendly input handling :trac:`13645`::

        sage: poly.<a,b> = PolynomialRing(RR)
        sage: solve([a+b+a*b == 1], a)
        Traceback (most recent call last):
        ...
        TypeError: The first argument to solve() should be a symbolic expression or a list of symbolic expressions, cannot handle <type 'bool'>
        sage: solve([a, b], (1, a))
        Traceback (most recent call last):
        ...
        TypeError: 1 is not a valid variable.
        sage: solve([x == 1], (1, a))
        Traceback (most recent call last):
        ...
        TypeError: (1, a) are not valid variables.

    Test that the original version of a system in the French Sage book
    now works (:trac:`14306`)::

        sage: var('y,z')
        (y, z)
        sage: solve([x^2 * y * z == 18, x * y^3 * z == 24, x * y * z^4 == 6], x, y, z)
        [[x == 3, y == 2, z == 1], [x == (1.337215067... - 2.685489874...*I), y == (-1.700434271... + 1.052864325...*I), z == (0.9324722294... - 0.3612416661...*I)], ...]
    """
    from sage.symbolic.expression import is_Expression
    if is_Expression(f): # f is a single expression
        ans = f.solve(*args,**kwds)
        return ans

    if not isinstance(f, (list, tuple)):
        raise TypeError("The first argument must be a symbolic expression or a list of symbolic expressions.")

    if len(f)==1:
        # f is a list with a single element
        if is_Expression(f[0]):
            # if its a symbolic expression call solve method of this expression
            return f[0].solve(*args,**kwds)
        # otherwise complain
        raise TypeError("The first argument to solve() should be a symbolic "
                        "expression or a list of symbolic expressions, "
                        "cannot handle %s"%repr(type(f[0])))

    # f is a list of such expressions or equations
    from sage.symbolic.ring import is_SymbolicVariable

    if len(args)==0:
        raise TypeError("Please input variables to solve for.")
    if is_SymbolicVariable(args[0]):
        variables = args
    else:
        variables = tuple(args[0])

    for v in variables:
        if not is_SymbolicVariable(v):
            raise TypeError("%s is not a valid variable."%repr(v))

    try:
        f = [s for s in f if s is not True]
    except TypeError:
        raise ValueError("Unable to solve %s for %s"%(f, args))

    if any(s is False for s in f):
        return []

    from sage.calculus.calculus import maxima
    m = maxima(f)

    try:
        s = m.solve(variables)
    except Exception: # if Maxima gave an error, try its to_poly_solve
        try:
            s = m.to_poly_solve(variables)
        except TypeError as mess: # if that gives an error, raise an error.
            if "Error executing code in Maxima" in str(mess):
                raise ValueError("Sage is unable to determine whether the system %s can be solved for %s"%(f,args))
            else:
                raise

    if len(s)==0: # if Maxima's solve gave no solutions, try its to_poly_solve
        try:
            s = m.to_poly_solve(variables)
        except Exception: # if that gives an error, stick with no solutions
            s = []

    if len(s)==0: # if to_poly_solve gave no solutions, try use_grobner
        try:
            s = m.to_poly_solve(variables,'use_grobner=true')
        except Exception: # if that gives an error, stick with no solutions
            s = []

    sol_list = string_to_list_of_solutions(repr(s))

    # Relaxed form suggested by Mike Hansen (#8553):
    if kwds.get('solution_dict', False):
        if len(sol_list)==0: # fixes IndexError on empty solution list (#8553)
            return []
        if isinstance(sol_list[0], list):
            sol_dict=[dict([[eq.left(),eq.right()] for eq in solution])
                    for solution in sol_list]
        else:
            sol_dict=[{eq.left():eq.right()} for eq in sol_list]

        return sol_dict
    else:
        return sol_list
Ejemplo n.º 18
0
def solve(f, *args, **kwds):
    r"""
    Algebraically solve an equation or system of equations (over the
    complex numbers) for given variables. Inequalities and systems 
    of inequalities are also supported.    
    
    INPUT:
    
    -  ``f`` - equation or system of equations (given by a
       list or tuple)
    
    -  ``*args`` - variables to solve for.
    
    -  ``solution_dict`` - bool (default: False); if True or non-zero, 
       return a list of dictionaries containing the solutions. If there
       are no solutions, return an empty list (rather than a list containing
       an empty dictionary). Likewise, if there's only a single solution,
       return a list containing one dictionary with that solution.
    
    EXAMPLES::
    
        sage: x, y = var('x, y')
        sage: solve([x+y==6, x-y==4], x, y)
        [[x == 5, y == 1]]
        sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
        [[x == -1/2*I*sqrt(3) - 1/2, y == -sqrt(-1/2*I*sqrt(3) + 3/2)],
         [x == -1/2*I*sqrt(3) - 1/2, y == sqrt(-1/2*I*sqrt(3) + 3/2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == -sqrt(1/2*I*sqrt(3) + 3/2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == sqrt(1/2*I*sqrt(3) + 3/2)],
         [x == 0, y == -1],
         [x == 0, y == 1]]
        sage: solve([sqrt(x) + sqrt(y) == 5, x + y == 10], x, y)
        [[x == -5/2*I*sqrt(5) + 5, y == 5/2*I*sqrt(5) + 5], [x == 5/2*I*sqrt(5) + 5, y == -5/2*I*sqrt(5) + 5]]
        sage: solutions=solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y, solution_dict=True)
        sage: for solution in solutions: print solution[x].n(digits=3), ",", solution[y].n(digits=3)
        -0.500 - 0.866*I , -1.27 + 0.341*I
        -0.500 - 0.866*I , 1.27 - 0.341*I
        -0.500 + 0.866*I , -1.27 - 0.341*I
        -0.500 + 0.866*I , 1.27 + 0.341*I
        0.000 , -1.00
        0.000 , 1.00

    Whenever possible, answers will be symbolic, but with systems of 
    equations, at times approximations will be given, due to the 
    underlying algorithm in Maxima::

        sage: sols = solve([x^3==y,y^2==x],[x,y]); sols[-1], sols[0]
        ([x == 0, y == 0], [x == (0.309016994375 + 0.951056516295*I),  y == (-0.809016994375 - 0.587785252292*I)])
        sage: sols[0][0].rhs().pyobject().parent()
        Complex Double Field

    If ``f`` is only one equation or expression, we use the solve method
    for symbolic expressions, which defaults to exact answers only::

        sage: solve([y^6==y],y)
        [y == e^(2/5*I*pi), y == e^(4/5*I*pi), y == e^(-4/5*I*pi), y == e^(-2/5*I*pi), y == 1, y == 0]
        sage: solve( [y^6 == y], y)==solve( y^6 == y, y)
        True

    .. note::

        For more details about solving a single equations, see
        the documentation for its solve.

    ::

        sage: from sage.symbolic.expression import Expression
        sage: Expression.solve(x^2==1,x)
        [x == -1, x == 1]

    We must solve with respect to actual variables::

        sage: z = 5
        sage: solve([8*z + y == 3, -z +7*y == 0],y,z)
        Traceback (most recent call last):
        ...
        TypeError: 5 is not a valid variable.

    If we ask for dictionaries containing the solutions, we get them::
    
        sage: solve([x^2-1],x,solution_dict=True)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-4*x+4],x,solution_dict=True)
        [{x: 2}]
        sage: res = solve([x^2 == y, y == 4],x,y,solution_dict=True)
        sage: for soln in res: print "x: %s, y: %s"%(soln[x], soln[y])
        x: 2, y: 4
        x: -2, y: 4

    If there is a parameter in the answer, that will show up as 
    a new variable.  In the following example, ``r1`` is a real free
    variable (because of the ``r``)::

        sage: solve([x+y == 3, 2*x+2*y == 6],x,y)
        [[x == -r1 + 3, y == r1]]

    Especially with trigonometric functions, the dummy variable may
    be implicitly an integer (hence the ``z``)::

        sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y)
        [[x == 1/4*pi + pi*z68, y == -1/4*pi - pi*z68]]

    Expressions which are not equations are assumed to be set equal
    to zero, as with `x` in the following example::

        sage: solve([x, y == 2],x,y)
        [[x == 0, y == 2]]

    If ``True`` appears in the list of equations it is
    ignored, and if ``False`` appears in the list then no
    solutions are returned. E.g., note that the first
    ``3==3`` evaluates to ``True``, not to a
    symbolic equation.
    
    ::
    
        sage: solve([3==3, 1.00000000000000*x^3 == 0], x)
        [x == 0]
        sage: solve([1.00000000000000*x^3 == 0], x)
        [x == 0]
    
    Here, the first equation evaluates to ``False``, so
    there are no solutions::
    
        sage: solve([1==3, 1.00000000000000*x^3 == 0], x)
        []
    
    Completely symbolic solutions are supported::
    
        sage: var('s,j,b,m,g')
        (s, j, b, m, g)
        sage: sys = [ m*(1-s) - b*s*j, b*s*j-g*j ];
        sage: solve(sys,s,j)
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,(s,j))
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,[s,j])
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]

    Inequalities can be also solved::

        sage: solve(x^2>8,x)
        [[x < -2*sqrt(2)], [x > 2*sqrt(2)]]

    Use use_grobner if no solution is obtained from to_poly_solve::

       sage: x,y=var('x y'); c1(x,y)=(x-5)^2+y^2-16; c2(x,y)=(y-3)^2+x^2-9
       sage: solve([c1(x,y),c2(x,y)],[x,y])                               
       [[x == -9/68*sqrt(55) + 135/68, y == -15/68*sqrt(5)*sqrt(11) + 123/68], [x == 9/68*sqrt(55) + 135/68, y == 15/68*sqrt(5)*sqrt(11) + 123/68]]
        
    TESTS::

        sage: solve([sin(x)==x,y^2==x],x,y)
        [sin(x) == x, y^2 == x]
        sage: solve(0==1,x)
        Traceback (most recent call last):
        ...
        TypeError:  The first argument must be a symbolic expression or a list of symbolic expressions.

    Test if the empty list is returned, too, when (a list of)
    dictionaries (is) are requested (#8553)::

        sage: solve([0==1],x)
        []
        sage: solve([0==1],x,solution_dict=True)
        []
        sage: solve([x==1,x==-1],x)
        []
        sage: solve([x==1,x==-1],x,solution_dict=True)
        []
        sage: solve((x==1,x==-1),x,solution_dict=0)
        []

    Relaxed form, suggested by Mike Hansen (#8553)::

        sage: solve([x^2-1],x,solution_dict=-1)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-1],x,solution_dict=1)
        [{x: -1}, {x: 1}]
        sage: solve((x==1,x==-1),x,solution_dict=-1)
        []
        sage: solve((x==1,x==-1),x,solution_dict=1)
        []

    This inequality holds for any real ``x`` (trac #8078)::

        sage: solve(x^4+2>0,x)
        [x < +Infinity]

    """
    from sage.symbolic.expression import is_Expression
    if is_Expression(f): # f is a single expression
        ans = f.solve(*args,**kwds)
        return ans

    if not isinstance(f, (list, tuple)):
        raise TypeError("The first argument must be a symbolic expression or a list of symbolic expressions.")

    if len(f)==1 and is_Expression(f[0]):
        # f is a list with a single expression
        return f[0].solve(*args,**kwds)

    # f is a list of such expressions or equations
    from sage.symbolic.ring import is_SymbolicVariable

    if len(args)==0:
        raise TypeError, "Please input variables to solve for."
    if is_SymbolicVariable(args[0]):
        variables = args
    else:
        variables = tuple(args[0])
    
    for v in variables:
        if not is_SymbolicVariable(v):
            raise TypeError, "%s is not a valid variable."%v

    try:
        f = [s for s in f if s is not True]
    except TypeError:
        raise ValueError, "Unable to solve %s for %s"%(f, args)

    if any(s is False for s in f):
        return []

    from sage.calculus.calculus import maxima
    m = maxima(f)

    try:
        s = m.solve(variables)
    except: # if Maxima gave an error, try its to_poly_solve
        try:
            s = m.to_poly_solve(variables)
        except TypeError, mess: # if that gives an error, raise an error.
            if "Error executing code in Maxima" in str(mess):
                raise ValueError, "Sage is unable to determine whether the system %s can be solved for %s"%(f,args)
            else:
                raise
Ejemplo n.º 19
0
def solve(f, *args, **kwds):
    r"""
    Algebraically solve an equation or system of equations (over the
    complex numbers) for given variables. Inequalities and systems 
    of inequalities are also supported.    
    
    INPUT:
    
    -  ``f`` - equation or system of equations (given by a
       list or tuple)
    
    -  ``*args`` - variables to solve for.
    
    -  ``solution_dict`` - bool (default: False); if True or non-zero, 
       return a list of dictionaries containing the solutions. If there
       are no solutions, return an empty list (rather than a list containing
       an empty dictionary). Likewise, if there's only a single solution,
       return a list containing one dictionary with that solution.
    
    EXAMPLES::
    
        sage: x, y = var('x, y')
        sage: solve([x+y==6, x-y==4], x, y)
        [[x == 5, y == 1]]
        sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
        [[x == -1/2*I*sqrt(3) - 1/2, y == -1/2*sqrt(-I*sqrt(3) + 3)*sqrt(2)],
         [x == -1/2*I*sqrt(3) - 1/2, y == 1/2*sqrt(-I*sqrt(3) + 3)*sqrt(2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == -1/2*sqrt(I*sqrt(3) + 3)*sqrt(2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == 1/2*sqrt(I*sqrt(3) + 3)*sqrt(2)],
         [x == 0, y == -1],
         [x == 0, y == 1]]
        sage: solve([sqrt(x) + sqrt(y) == 5, x + y == 10], x, y)
        [[x == -5/2*I*sqrt(5) + 5, y == 5/2*I*sqrt(5) + 5], [x == 5/2*I*sqrt(5) + 5, y == -5/2*I*sqrt(5) + 5]]
        sage: solutions=solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y, solution_dict=True)
        sage: for solution in solutions: print solution[x].n(digits=3), ",", solution[y].n(digits=3)
        -0.500 - 0.866*I , -1.27 + 0.341*I
        -0.500 - 0.866*I , 1.27 - 0.341*I
        -0.500 + 0.866*I , -1.27 - 0.341*I
        -0.500 + 0.866*I , 1.27 + 0.341*I
        0.000 , -1.00
        0.000 , 1.00

    Whenever possible, answers will be symbolic, but with systems of 
    equations, at times approximations will be given, due to the 
    underlying algorithm in Maxima::

        sage: sols = solve([x^3==y,y^2==x],[x,y]); sols[-1], sols[0]
        ([x == 0, y == 0], [x == (0.309016994375 + 0.951056516295*I),  y == (-0.809016994375 - 0.587785252292*I)])
        sage: sols[0][0].rhs().pyobject().parent()
        Complex Double Field

    If ``f`` is only one equation or expression, we use the solve method
    for symbolic expressions, which defaults to exact answers only::

        sage: solve([y^6==y],y)
        [y == e^(2/5*I*pi), y == e^(4/5*I*pi), y == e^(-4/5*I*pi), y == e^(-2/5*I*pi), y == 1, y == 0]
        sage: solve( [y^6 == y], y)==solve( y^6 == y, y)
        True

    .. note::

        For more details about solving a single equations, see
        the documentation for its solve.

    ::

        sage: from sage.symbolic.expression import Expression
        sage: Expression.solve(x^2==1,x)
        [x == -1, x == 1]

    We must solve with respect to actual variables::

        sage: z = 5
        sage: solve([8*z + y == 3, -z +7*y == 0],y,z)
        Traceback (most recent call last):
        ...
        TypeError: 5 is not a valid variable.

    If we ask for dictionaries containing the solutions, we get them::
    
        sage: solve([x^2-1],x,solution_dict=True)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-4*x+4],x,solution_dict=True)
        [{x: 2}]
        sage: res = solve([x^2 == y, y == 4],x,y,solution_dict=True)
        sage: for soln in res: print "x: %s, y: %s"%(soln[x], soln[y])
        x: 2, y: 4
        x: -2, y: 4

    If there is a parameter in the answer, that will show up as 
    a new variable.  In the following example, ``r1`` is a real free
    variable (because of the ``r``)::

        sage: solve([x+y == 3, 2*x+2*y == 6],x,y)
        [[x == -r1 + 3, y == r1]]

    Especially with trigonometric functions, the dummy variable may
    be implicitly an integer (hence the ``z``)::

        sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y)
        [[x == 1/4*pi + pi*z68, y == -1/4*pi - pi*z68]]

    Expressions which are not equations are assumed to be set equal
    to zero, as with `x` in the following example::

        sage: solve([x, y == 2],x,y)
        [[x == 0, y == 2]]

    If ``True`` appears in the list of equations it is
    ignored, and if ``False`` appears in the list then no
    solutions are returned. E.g., note that the first
    ``3==3`` evaluates to ``True``, not to a
    symbolic equation.
    
    ::
    
        sage: solve([3==3, 1.00000000000000*x^3 == 0], x)
        [x == 0]
        sage: solve([1.00000000000000*x^3 == 0], x)
        [x == 0]
    
    Here, the first equation evaluates to ``False``, so
    there are no solutions::
    
        sage: solve([1==3, 1.00000000000000*x^3 == 0], x)
        []
    
    Completely symbolic solutions are supported::
    
        sage: var('s,j,b,m,g')
        (s, j, b, m, g)
        sage: sys = [ m*(1-s) - b*s*j, b*s*j-g*j ];
        sage: solve(sys,s,j)
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,(s,j))
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,[s,j])
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]

    Inequalities can be also solved::

        sage: solve(x^2>8,x)
        [[x < -2*sqrt(2)], [x > 2*sqrt(2)]]

    Use use_grobner if no solution is obtained from to_poly_solve::

       sage: x,y=var('x y'); c1(x,y)=(x-5)^2+y^2-16; c2(x,y)=(y-3)^2+x^2-9
       sage: solve([c1(x,y),c2(x,y)],[x,y])                               
       [[x == -9/68*sqrt(55) + 135/68, y == -15/68*sqrt(5)*sqrt(11) + 123/68], [x == 9/68*sqrt(55) + 135/68, y == 15/68*sqrt(5)*sqrt(11) + 123/68]]
        
    TESTS::

        sage: solve([sin(x)==x,y^2==x],x,y)
        [sin(x) == x, y^2 == x]
        sage: solve(0==1,x)
        Traceback (most recent call last):
        ...
        TypeError:  The first argument must be a symbolic expression or a list of symbolic expressions.

    Test if the empty list is returned, too, when (a list of)
    dictionaries (is) are requested (#8553)::

        sage: solve([0==1],x)
        []
        sage: solve([0==1],x,solution_dict=True)
        []
        sage: solve([x==1,x==-1],x)
        []
        sage: solve([x==1,x==-1],x,solution_dict=True)
        []
        sage: solve((x==1,x==-1),x,solution_dict=0)
        []

    Relaxed form, suggested by Mike Hansen (#8553)::

        sage: solve([x^2-1],x,solution_dict=-1)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-1],x,solution_dict=1)
        [{x: -1}, {x: 1}]
        sage: solve((x==1,x==-1),x,solution_dict=-1)
        []
        sage: solve((x==1,x==-1),x,solution_dict=1)
        []

    This inequality holds for any real ``x`` (trac #8078)::

        sage: solve(x^4+2>0,x)
        [x < +Infinity]

    """
    from sage.symbolic.expression import is_Expression
    if is_Expression(f):  # f is a single expression
        ans = f.solve(*args, **kwds)
        return ans

    if not isinstance(f, (list, tuple)):
        raise TypeError(
            "The first argument must be a symbolic expression or a list of symbolic expressions."
        )

    if len(f) == 1 and is_Expression(f[0]):
        # f is a list with a single expression
        return f[0].solve(*args, **kwds)

    # f is a list of such expressions or equations
    from sage.symbolic.ring import is_SymbolicVariable

    if len(args) == 0:
        raise TypeError, "Please input variables to solve for."
    if is_SymbolicVariable(args[0]):
        variables = args
    else:
        variables = tuple(args[0])

    for v in variables:
        if not is_SymbolicVariable(v):
            raise TypeError, "%s is not a valid variable." % v

    try:
        f = [s for s in f if s is not True]
    except TypeError:
        raise ValueError, "Unable to solve %s for %s" % (f, args)

    if any(s is False for s in f):
        return []

    from sage.calculus.calculus import maxima
    m = maxima(f)

    try:
        s = m.solve(variables)
    except:  # if Maxima gave an error, try its to_poly_solve
        try:
            s = m.to_poly_solve(variables)
        except TypeError, mess:  # if that gives an error, raise an error.
            if "Error executing code in Maxima" in str(mess):
                raise ValueError, "Sage is unable to determine whether the system %s can be solved for %s" % (
                    f, args)
            else:
                raise
Ejemplo n.º 20
0
def sage_to_max(expr):
    r"""
    Convert a symbolic ring expression to maxima
    
    EXAMPLES::

        sage: from sagemax import *
        ;;; Loading #P"/usr/local/sage/4.1.2/local/lib/ecl/maxima.fas"
        sage: from sage.calculus.calculus import _integrate
        sage: I=_integrate(cos(x),x)
        sage: sage_to_max(I)
        <ECL: (($INTEGRATE) ((%COS) SAGE-SYM-1) SAGE-SYM-1)>
        sage: meval(sage_to_max(I))
        <ECL: ((%SIN SIMP) SAGE-SYM-1)>
        sage: max_to_sage(meval(sage_to_max(I)))
        sin(x)
        
    This process has defined a mapping from the sage SR element x to maxima::
    
        sage: sym_sage_to_max[x]
        <ECL: SAGE-SYM-1>

    And this mapping exists in the other direction too (this is why EclObjects
    should be quickly hashable)::
    
        sage: sym_max_to_sage[sym_sage_to_max[x]]
        x

    Expressions that do not have a special meaning get translated relatively
    robustly. For instance, formal derivatives have not been implemented yet::
    
        sage: f=SFunction('f')
        sage: L=sage_to_max(derivative(f(x),x))
        sage: L
        <ECL: ((SAGE-OP-2) SAGE-SYM-1)>

    As you can see, the nature of the derivative is not translated at all.
    However, the reverse mapping unpacks that again::
    
        sage: max_to_sage(L)
        D[0](f)(x)
    """

    global op_sage_to_max, op_max_to_sage
    global sym_sage_to_max, sym_max_to_sage
    op = expr.operator()
    if op:
        if not (op in op_sage_to_max):
            op_max = maxop.next()
            op_sage_to_max[op] = op_max
            op_max_to_sage[op_max] = op
        return EclObject(
            ([op_sage_to_max[op]], [sage_to_max(o) for o in expr.operands()]))
    elif is_SymbolicVariable(expr):
        if not expr in sym_sage_to_max:
            sym_max = maxsym.next()
            sym_sage_to_max[expr] = sym_max
            sym_max_to_sage[sym_max] = expr
        return sym_sage_to_max[expr]
    else:
        return pyobject_to_max(expr.pyobject())
Ejemplo n.º 21
0
def sr_to_max(expr):
    r"""
    Convert a symbolic expression into a Maxima object.

    INPUT:

    - ``expr`` - symbolic expression

    OUTPUT: ECL object

    EXAMPLES::
        sage: from sage.interfaces.maxima_lib import sr_to_max
        sage: var('x')
        x
        sage: sr_to_max(x)
        <ECL: $X>
        sage: sr_to_max(cos(x))
        <ECL: ((%COS) $X)>
        sage: f = function('f',x)
        sage: sr_to_max(f.diff())
        <ECL: ((%DERIVATIVE) (($F) $X) $X 1)>
    """
    global sage_op_dict, max_op_dict
    global sage_sym_dict, max_sym_dict
    if isinstance(expr, list) or isinstance(expr, tuple):
        return EclObject(([mlist], [sr_to_max(e) for e in expr]))
    op = expr.operator()
    if op:
        # Stolen from sage.symbolic.expression_conversion
        # Should be defined in a function and then put in special_sage_to_max
        # For that, we should change the API of the functions there
        # (we need to have access to op, not only to expr.operands()
        if isinstance(op, FDerivativeOperator):
            from sage.symbolic.ring import is_SymbolicVariable
            args = expr.operands()
            if (not all(is_SymbolicVariable(v) for v in args)
                    or len(args) != len(set(args))):
                raise NotImplementedError, "arguments must be distinct variables"
            f = sr_to_max(op.function()(*args))
            params = op.parameter_set()
            deriv_max = []
            [
                deriv_max.extend(
                    [sr_to_max(args[i]),
                     EclObject(params.count(i))]) for i in set(params)
            ]
            l = [[mdiff], f]
            l.extend(deriv_max)
            return EclObject(l)
        elif (op in special_sage_to_max):
            return EclObject(special_sage_to_max[op](
                *[sr_to_max(o) for o in expr.operands()]))
        elif not (op in sage_op_dict):
            # Maxima does some simplifications automatically by default
            # so calling maxima(expr) can change the structure of expr
            #op_max=caar(maxima(expr).ecl())
            # This should be safe if we treated all special operators above
            op_max = maxima(op).ecl()
            sage_op_dict[op] = op_max
            max_op_dict[op_max] = op
        return EclObject(
            ([sage_op_dict[op]], [sr_to_max(o) for o in expr.operands()]))
    elif expr.is_symbol() or expr.is_constant():
        if not expr in sage_sym_dict:
            sym_max = maxima(expr).ecl()
            sage_sym_dict[expr] = sym_max
            max_sym_dict[sym_max] = expr
        return sage_sym_dict[expr]
    else:
        try:
            return pyobject_to_max(expr.pyobject())
        except TypeError:
            return maxima(expr).ecl()
Ejemplo n.º 22
0
def wronskian(*args):
    """
    Returns the Wronskian of the provided functions, differentiating with
    respect to the given variable. If no variable is provided,
    diff(f) is called for each function f.

    wronskian(f1,...,fn, x) returns the Wronskian of f1,...,fn, with
    derivatives taken with respect to x.

    wronskian(f1,...,fn) returns the Wronskian of f1,...,fn where
    k'th derivatives are computed by doing ``.derivative(k)`` on each
    function.

    The Wronskian of a list of functions is a determinant of derivatives.
    The nth row (starting from 0) is a list of the nth derivatives of the
    given functions.

    For two functions::

                              | f   g  |
                 W(f, g) = det|        | = f*g' - g*f'.
                              | f'  g' |

    EXAMPLES::

        sage: wronskian(e^x, x^2)
        -x^2*e^x + 2*x*e^x

        sage: x,y = var('x, y')
        sage: wronskian(x*y, log(x), x)
        -y*log(x) + y

    If your functions are in a list, you can use `*' to turn them into
    arguments to :func:`wronskian`::

        sage: wronskian(*[x^k for k in range(1, 5)])
        12*x^4

    If you want to use 'x' as one of the functions in the Wronskian,
    you can't put it last or it will be interpreted as the variable
    with respect to which we differentiate. There are several ways to
    get around this.

    Two-by-two Wronskian of sin(x) and e^x::

        sage: wronskian(sin(x), e^x, x)
        -cos(x)*e^x + e^x*sin(x)

    Or don't put x last::

        sage: wronskian(x, sin(x), e^x)
        (cos(x)*e^x + e^x*sin(x))*x - 2*e^x*sin(x)

    Example where one of the functions is constant::

        sage: wronskian(1, e^(-x), e^(2*x))
        -6*e^x

    NOTES:

    - http://en.wikipedia.org/wiki/Wronskian
    - http://planetmath.org/encyclopedia/WronskianDeterminant.html

    AUTHORS:

    - Dan Drake (2008-03-12)
    """
    if len(args) == 0:
        raise TypeError('wronskian() takes at least one argument (0 given)')
    elif len(args) == 1:
        # a 1x1 Wronskian is just its argument
        return args[0]
    else:
        if is_SymbolicVariable(args[-1]):
            # if last argument is a variable, peel it off and
            # differentiate the other args
            v = args[-1]
            fs = args[0:-1]
            row = lambda n: map(lambda f: diff(f, v, n), fs)
        else:
            # if the last argument isn't a variable, just run
            # .derivative on everything
            fs = args
            row = lambda n: map(lambda f: diff(f, n), fs)
        # NOTE: I rewrote the below as two lines to avoid a possible subtle
        # memory management problem on some platforms (only VMware as far
        # as we know?).  See trac #2990.
        # There may still be a real problem that this is just hiding for now.
        A = matrix(map(row, range(len(fs))))
        return A.determinant()
Ejemplo n.º 23
0
def solve(f, *args, **kwds):
    r"""
    Algebraically solve an equation or system of equations (over the
    complex numbers) for given variables. Inequalities and systems
    of inequalities are also supported.

    INPUT:

    -  ``f`` - equation or system of equations (given by a
       list or tuple)

    -  ``*args`` - variables to solve for.

    -  ``solution_dict`` - bool (default: False); if True or non-zero,
       return a list of dictionaries containing the solutions. If there
       are no solutions, return an empty list (rather than a list containing
       an empty dictionary). Likewise, if there's only a single solution,
       return a list containing one dictionary with that solution.

    There are a few optional keywords if you are trying to solve a single
    equation.  They may only be used in that context.

    -  ``multiplicities`` - bool (default: False); if True,
       return corresponding multiplicities.  This keyword is
       incompatible with ``to_poly_solve=True`` and does not make
       any sense when solving inequalities.

    -  ``explicit_solutions`` - bool (default: False); require that
       all roots be explicit rather than implicit. Not used
       when solving inequalities.

    -  ``to_poly_solve`` - bool (default: False) or string; use
       Maxima's ``to_poly_solver`` package to search for more possible
       solutions, but possibly encounter approximate solutions.
       This keyword is incompatible with ``multiplicities=True``
       and is not used when solving inequalities. Setting ``to_poly_solve``
       to 'force' (string) omits Maxima's solve command (useful when
       some solutions of trigonometric equations are lost).


    EXAMPLES::

        sage: x, y = var('x, y')
        sage: solve([x+y==6, x-y==4], x, y)
        [[x == 5, y == 1]]
        sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
        [[x == -1/2*I*sqrt(3) - 1/2, y == -sqrt(-1/2*I*sqrt(3) + 3/2)],
         [x == -1/2*I*sqrt(3) - 1/2, y == sqrt(-1/2*I*sqrt(3) + 3/2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == -sqrt(1/2*I*sqrt(3) + 3/2)],
         [x == 1/2*I*sqrt(3) - 1/2, y == sqrt(1/2*I*sqrt(3) + 3/2)],
         [x == 0, y == -1],
         [x == 0, y == 1]]
        sage: solve([sqrt(x) + sqrt(y) == 5, x + y == 10], x, y)
        [[x == -5/2*I*sqrt(5) + 5, y == 5/2*I*sqrt(5) + 5], [x == 5/2*I*sqrt(5) + 5, y == -5/2*I*sqrt(5) + 5]]
        sage: solutions=solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y, solution_dict=True)
        sage: for solution in solutions: print("{} , {}".format(solution[x].n(digits=3), solution[y].n(digits=3)))
        -0.500 - 0.866*I , -1.27 + 0.341*I
        -0.500 - 0.866*I , 1.27 - 0.341*I
        -0.500 + 0.866*I , -1.27 - 0.341*I
        -0.500 + 0.866*I , 1.27 + 0.341*I
        0.000 , -1.00
        0.000 , 1.00

    Whenever possible, answers will be symbolic, but with systems of
    equations, at times approximations will be given, due to the
    underlying algorithm in Maxima::

        sage: sols = solve([x^3==y,y^2==x],[x,y]); sols[-1], sols[0]
        ([x == 0, y == 0], [x == (0.3090169943749475 + 0.9510565162951535*I), y == (-0.8090169943749475 - 0.5877852522924731*I)])
        sage: sols[0][0].rhs().pyobject().parent()
        Complex Double Field

    If ``f`` is only one equation or expression, we use the solve method
    for symbolic expressions, which defaults to exact answers only::

        sage: solve([y^6==y],y)
        [y == 1/4*sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, y == -1/4*sqrt(5) + 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, y == -1/4*sqrt(5) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, y == 1/4*sqrt(5) - 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, y == 1, y == 0]
        sage: solve( [y^6 == y], y)==solve( y^6 == y, y)
        True

    Here we demonstrate very basic use of the optional keywords for
    a single expression to be solved::

        sage: ((x^2-1)^2).solve(x)
        [x == -1, x == 1]
        sage: ((x^2-1)^2).solve(x,multiplicities=True)
        ([x == -1, x == 1], [2, 2])
        sage: solve(sin(x)==x,x)
        [x == sin(x)]
        sage: solve(sin(x)==x,x,explicit_solutions=True)
        []
        sage: solve(abs(1-abs(1-x)) == 10, x)
        [abs(abs(x - 1) - 1) == 10]
        sage: solve(abs(1-abs(1-x)) == 10, x, to_poly_solve=True)
        [x == -10, x == 12]

    .. note::

        For more details about solving a single equation, see
        the documentation for the single-expression
        :meth:`~sage.symbolic.expression.Expression.solve`.

    ::

        sage: from sage.symbolic.expression import Expression
        sage: Expression.solve(x^2==1,x)
        [x == -1, x == 1]

    We must solve with respect to actual variables::

        sage: z = 5
        sage: solve([8*z + y == 3, -z +7*y == 0],y,z)
        Traceback (most recent call last):
        ...
        TypeError: 5 is not a valid variable.

    If we ask for dictionaries containing the solutions, we get them::

        sage: solve([x^2-1],x,solution_dict=True)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-4*x+4],x,solution_dict=True)
        [{x: 2}]
        sage: res = solve([x^2 == y, y == 4],x,y,solution_dict=True)
        sage: for soln in res: print("x: %s, y: %s" % (soln[x], soln[y]))
        x: 2, y: 4
        x: -2, y: 4

    If there is a parameter in the answer, that will show up as
    a new variable.  In the following example, ``r1`` is a real free
    variable (because of the ``r``)::

        sage: solve([x+y == 3, 2*x+2*y == 6],x,y)
        [[x == -r1 + 3, y == r1]]

    Especially with trigonometric functions, the dummy variable may
    be implicitly an integer (hence the ``z``)::

        sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y)
        [[x == 1/4*pi + pi*z79, y == -1/4*pi - pi*z79]]

    Expressions which are not equations are assumed to be set equal
    to zero, as with `x` in the following example::

        sage: solve([x, y == 2],x,y)
        [[x == 0, y == 2]]

    If ``True`` appears in the list of equations it is
    ignored, and if ``False`` appears in the list then no
    solutions are returned. E.g., note that the first
    ``3==3`` evaluates to ``True``, not to a
    symbolic equation.

    ::

        sage: solve([3==3, 1.00000000000000*x^3 == 0], x)
        [x == 0]
        sage: solve([1.00000000000000*x^3 == 0], x)
        [x == 0]

    Here, the first equation evaluates to ``False``, so
    there are no solutions::

        sage: solve([1==3, 1.00000000000000*x^3 == 0], x)
        []

    Completely symbolic solutions are supported::

        sage: var('s,j,b,m,g')
        (s, j, b, m, g)
        sage: sys = [ m*(1-s) - b*s*j, b*s*j-g*j ];
        sage: solve(sys,s,j)
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,(s,j))
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
        sage: solve(sys,[s,j])
        [[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]

    Inequalities can be also solved::

        sage: solve(x^2>8,x)
        [[x < -2*sqrt(2)], [x > 2*sqrt(2)]]

    We use ``use_grobner`` in Maxima if no solution is obtained from
    Maxima's ``to_poly_solve``::

       sage: x,y=var('x y'); c1(x,y)=(x-5)^2+y^2-16; c2(x,y)=(y-3)^2+x^2-9
       sage: solve([c1(x,y),c2(x,y)],[x,y])
       [[x == -9/68*sqrt(55) + 135/68, y == -15/68*sqrt(55) + 123/68], [x == 9/68*sqrt(55) + 135/68, y == 15/68*sqrt(55) + 123/68]]

    TESTS::

        sage: solve([sin(x)==x,y^2==x],x,y)
        [sin(x) == x, y^2 == x]
        sage: solve(0==1,x)
        Traceback (most recent call last):
        ...
        TypeError:  The first argument must be a symbolic expression or a list of symbolic expressions.

    Test if the empty list is returned, too, when (a list of)
    dictionaries (is) are requested (:trac:`8553`)::

        sage: solve([SR(0)==1],x)
        []
        sage: solve([SR(0)==1],x,solution_dict=True)
        []
        sage: solve([x==1,x==-1],x)
        []
        sage: solve([x==1,x==-1],x,solution_dict=True)
        []
        sage: solve((x==1,x==-1),x,solution_dict=0)
        []

    Relaxed form, suggested by Mike Hansen (:trac:`8553`)::

        sage: solve([x^2-1],x,solution_dict=-1)
        [{x: -1}, {x: 1}]
        sage: solve([x^2-1],x,solution_dict=1)
        [{x: -1}, {x: 1}]
        sage: solve((x==1,x==-1),x,solution_dict=-1)
        []
        sage: solve((x==1,x==-1),x,solution_dict=1)
        []

    This inequality holds for any real ``x`` (:trac:`8078`)::

        sage: solve(x^4+2>0,x)
        [x < +Infinity]

    Test for user friendly input handling :trac:`13645`::

        sage: poly.<a,b> = PolynomialRing(RR)
        sage: solve([a+b+a*b == 1], a)
        Traceback (most recent call last):
        ...
        TypeError: The first argument to solve() should be a symbolic expression or a list of symbolic expressions, cannot handle <... 'bool'>
        sage: solve([a, b], (1, a))
        Traceback (most recent call last):
        ...
        TypeError: 1 is not a valid variable.
        sage: solve([x == 1], (1, a))
        Traceback (most recent call last):
        ...
        TypeError: (1, a) are not valid variables.

    Test that the original version of a system in the French Sage book
    now works (:trac:`14306`)::

        sage: var('y,z')
        (y, z)
        sage: solve([x^2 * y * z == 18, x * y^3 * z == 24, x * y * z^4 == 6], x, y, z)
        [[x == 3, y == 2, z == 1], [x == (1.337215067... - 2.685489874...*I), y == (-1.700434271... + 1.052864325...*I), z == (0.9324722294... - 0.3612416661...*I)], ...]
    """
    from sage.symbolic.expression import is_Expression
    if is_Expression(f):  # f is a single expression
        ans = f.solve(*args, **kwds)
        return ans

    if not isinstance(f, (list, tuple)):
        raise TypeError(
            "The first argument must be a symbolic expression or a list of symbolic expressions."
        )

    if len(f) == 1:
        # f is a list with a single element
        if is_Expression(f[0]):
            # if its a symbolic expression call solve method of this expression
            return f[0].solve(*args, **kwds)
        # otherwise complain
        raise TypeError("The first argument to solve() should be a symbolic "
                        "expression or a list of symbolic expressions, "
                        "cannot handle %s" % repr(type(f[0])))

    # f is a list of such expressions or equations
    from sage.symbolic.ring import is_SymbolicVariable

    if len(args) == 0:
        raise TypeError("Please input variables to solve for.")
    if is_SymbolicVariable(args[0]):
        variables = args
    else:
        variables = tuple(args[0])

    for v in variables:
        if not is_SymbolicVariable(v):
            raise TypeError("%s is not a valid variable." % repr(v))

    try:
        f = [s for s in f if s is not True]
    except TypeError:
        raise ValueError("Unable to solve %s for %s" % (f, args))

    if any(s is False for s in f):
        return []

    from sage.calculus.calculus import maxima
    m = maxima(f)

    try:
        s = m.solve(variables)
    except Exception:  # if Maxima gave an error, try its to_poly_solve
        try:
            s = m.to_poly_solve(variables)
        except TypeError as mess:  # if that gives an error, raise an error.
            if "Error executing code in Maxima" in str(mess):
                raise ValueError(
                    "Sage is unable to determine whether the system %s can be solved for %s"
                    % (f, args))
            else:
                raise

    if len(
            s
    ) == 0:  # if Maxima's solve gave no solutions, try its to_poly_solve
        try:
            s = m.to_poly_solve(variables)
        except Exception:  # if that gives an error, stick with no solutions
            s = []

    if len(s) == 0:  # if to_poly_solve gave no solutions, try use_grobner
        try:
            s = m.to_poly_solve(variables, 'use_grobner=true')
        except Exception:  # if that gives an error, stick with no solutions
            s = []

    sol_list = string_to_list_of_solutions(repr(s))

    # Relaxed form suggested by Mike Hansen (#8553):
    if kwds.get('solution_dict', False):
        if len(sol_list
               ) == 0:  # fixes IndexError on empty solution list (#8553)
            return []
        if isinstance(sol_list[0], list):
            sol_dict = [
                dict([[eq.left(), eq.right()] for eq in solution])
                for solution in sol_list
            ]
        else:
            sol_dict = [{eq.left(): eq.right()} for eq in sol_list]

        return sol_dict
    else:
        return sol_list
Ejemplo n.º 24
0
def sr_to_max(expr):
    r"""
    Convert a symbolic expression into a Maxima object.

    INPUT:

    - ``expr`` - symbolic expression

    OUTPUT: ECL object

    EXAMPLES::

        sage: from sage.interfaces.maxima_lib import sr_to_max
        sage: var('x')
        x
        sage: sr_to_max(x)
        <ECL: $X>
        sage: sr_to_max(cos(x))
        <ECL: ((%COS) $X)>
        sage: f = function('f',x)
        sage: sr_to_max(f.diff())
        <ECL: ((%DERIVATIVE) (($F) $X) $X 1)>

    TESTS:

    We should be able to convert derivatives evaluated at a point,
    :trac:`12796`::

        sage: from sage.interfaces.maxima_lib import sr_to_max, max_to_sr
        sage: f = function('f')
        sage: f_prime = f(x).diff(x)
        sage: max_to_sr(sr_to_max(f_prime(x = 1)))
        D[0](f)(1)

    """
    global sage_op_dict, max_op_dict
    global sage_sym_dict, max_sym_dict
    if isinstance(expr,list) or isinstance(expr,tuple):
        return EclObject(([mlist],[sr_to_max(e) for e in expr]))
    op = expr.operator()
    if op:
        # Stolen from sage.symbolic.expression_conversion
        # Should be defined in a function and then put in special_sage_to_max
        # For that, we should change the API of the functions there
        # (we need to have access to op, not only to expr.operands()
        if isinstance(op, FDerivativeOperator):
            from sage.symbolic.ring import is_SymbolicVariable
            args = expr.operands()
            if (not all(is_SymbolicVariable(v) for v in args) or
                len(args) != len(set(args))):
                # An evaluated derivative of the form f'(1) is not a
                # symbolic variable, yet we would like to treat it
                # like one. So, we replace the argument `1` with a
                # temporary variable e.g. `t0` and then evaluate the
                # derivative f'(t0) symbolically at t0=1. See trac
                # #12796.
                temp_args=[var("t%s"%i) for i in range(len(args))]
                f =sr_to_max(op.function()(*temp_args))
                params = op.parameter_set()
                deriv_max = [[mdiff],f]
                for i in set(params):
                    deriv_max.extend([sr_to_max(temp_args[i]), EclObject(params.count(i))])
                at_eval=sr_to_max([temp_args[i]==args[i] for i in range(len(args))])
                return EclObject([[max_at],deriv_max,at_eval])

            f = sr_to_max(op.function()(*args))
            params = op.parameter_set()
            deriv_max = []
            [deriv_max.extend([sr_to_max(args[i]), EclObject(params.count(i))]) for i in set(params)]
            l = [[mdiff],f]
            l.extend(deriv_max)
            return EclObject(l)
        elif (op in special_sage_to_max):
            return EclObject(special_sage_to_max[op](*[sr_to_max(o) for o in expr.operands()]))
        elif not (op in sage_op_dict):
            # Maxima does some simplifications automatically by default
            # so calling maxima(expr) can change the structure of expr
            #op_max=caar(maxima(expr).ecl())
            # This should be safe if we treated all special operators above
            op_max=maxima(op).ecl()
            sage_op_dict[op]=op_max
            max_op_dict[op_max]=op
        return EclObject(([sage_op_dict[op]],
                     [sr_to_max(o) for o in expr.operands()]))
    elif expr.is_symbol() or expr.is_constant():
        if not expr in sage_sym_dict:
            sym_max=maxima(expr).ecl()
            sage_sym_dict[expr]=sym_max
            max_sym_dict[sym_max]=expr
        return sage_sym_dict[expr]
    else:
        try:
            return pyobject_to_max(expr.pyobject())
        except TypeError:
            return maxima(expr).ecl()
Ejemplo n.º 25
0
def sr_to_max(expr):
    r"""
    Convert a symbolic expression into a Maxima object.

    INPUT:

    - ``expr`` - symbolic expression

    OUTPUT: ECL object

    EXAMPLES::
        sage: from sage.interfaces.maxima_lib import sr_to_max
        sage: var('x')
        x
        sage: sr_to_max(x)
        <ECL: $X>
        sage: sr_to_max(cos(x))
        <ECL: ((%COS) $X)>
        sage: f = function('f',x)
        sage: sr_to_max(f.diff())
        <ECL: ((%DERIVATIVE) (($F) $X) $X 1)>
    """
    global sage_op_dict, max_op_dict
    global sage_sym_dict, max_sym_dict
    if isinstance(expr,list) or isinstance(expr,tuple):
        return EclObject(([mlist],[sr_to_max(e) for e in expr]))
    op = expr.operator()
    if op:
        # Stolen from sage.symbolic.expression_conversion
        # Should be defined in a function and then put in special_sage_to_max
        # For that, we should change the API of the functions there
        # (we need to have access to op, not only to expr.operands()
        if isinstance(op, FDerivativeOperator):
            from sage.symbolic.ring import is_SymbolicVariable
            args = expr.operands()
            if (not all(is_SymbolicVariable(v) for v in args) or
                len(args) != len(set(args))):
                raise NotImplementedError, "arguments must be distinct variables"
            f = sr_to_max(op.function()(*args))
            params = op.parameter_set()
            deriv_max = []
            [deriv_max.extend([sr_to_max(args[i]), EclObject(params.count(i))]) for i in set(params)]
            l = [[mdiff],f]
            l.extend(deriv_max)
            return EclObject(l)
        elif (op in special_sage_to_max):
            return EclObject(special_sage_to_max[op](*[sr_to_max(o) for o in expr.operands()]))
        elif not (op in sage_op_dict):
            # Maxima does some simplifications automatically by default
            # so calling maxima(expr) can change the structure of expr
            #op_max=caar(maxima(expr).ecl())
            # This should be safe if we treated all special operators above
            op_max=maxima(op).ecl()
            sage_op_dict[op]=op_max
            max_op_dict[op_max]=op
        return EclObject(([sage_op_dict[op]],
                     [sr_to_max(o) for o in expr.operands()]))
    elif expr.is_symbol() or expr.is_constant():
        if not expr in sage_sym_dict:
            sym_max=maxima(expr).ecl()
            sage_sym_dict[expr]=sym_max
            max_sym_dict[sym_max]=expr
        return sage_sym_dict[expr]
    else:
        try:
            return pyobject_to_max(expr.pyobject())
        except TypeError:
            return maxima(expr).ecl()