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
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
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."
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
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.")
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)
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
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)
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)
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)
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)
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)
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)
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)
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
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()
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
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
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
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())
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()
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()
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
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()
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()