def _eval_(self, n, m, theta, phi, **kwargs): r""" TESTS:: sage: x, y = var('x y') sage: spherical_harmonic(1, 2, x, y) 0 sage: spherical_harmonic(1, -2, x, y) 0 sage: spherical_harmonic(1/2, 2, x, y) spherical_harmonic(1/2, 2, x, y) sage: spherical_harmonic(3, 2, x, y) 15/4*sqrt(7/30)*cos(x)*e^(2*I*y)*sin(x)^2/sqrt(pi) sage: spherical_harmonic(3, 2, 1, 2) 15/4*sqrt(7/30)*cos(1)*e^(4*I)*sin(1)^2/sqrt(pi) sage: spherical_harmonic(3 + I, 2., 1, 2) -0.351154337307488 - 0.415562233975369*I """ from sage.structure.coerce import parent cc = get_coercion_model().canonical_coercion coerced = cc(phi, cc(theta, cc(n, m)[0])[0])[0] if is_inexact(coerced) and not isinstance(coerced, Expression): return self._evalf_(n, m, theta, phi, parent=parent(coerced)) elif n in ZZ and m in ZZ and n > -1: if abs(m) > n: return ZZ(0) return meval("spherical_harmonic({},{},{},{})".format( ZZ(n), ZZ(m), maxima(theta), maxima(phi))) return
def _eval_(self, *args): """ Returns a string which represents this function evaluated at *args* in Maxima. EXAMPLES:: sage: from sage.functions.special import MaximaFunction sage: f = MaximaFunction("jacobi_sn") sage: f(1,1) tanh(1) sage: f._eval_(1,1) tanh(1) Here arccoth doesn't have 1 in its domain, so we just hold the expression: sage: elliptic_e(arccoth(1), x^2*e) elliptic_e(arccoth(1), x^2*e) """ _init() try: s = maxima(self._maxima_init_evaled_(*args)) except TypeError: return None if self.name() in repr(s): return None else: return s.sage()
def _evalf_(self, *args, **kwds): """ Returns a numerical approximation of this function using Maxima. Currently, this is limited to 53 bits of precision. EXAMPLES:: sage: from sage.functions.special import MaximaFunction sage: f = MaximaFunction("jacobi_sn") sage: f(1/2,1/2) jacobi_sn(1/2, 1/2) sage: f(1/2,1/2).n() 0.470750473655657 TESTS:: sage: f(1/2,1/2).n(150) Traceback (most recent call last): ... NotImplementedError: jacobi_sn not implemented for precision > 53 """ parent = kwds['parent'] if hasattr(parent, 'prec') and parent.prec() > 53: raise NotImplementedError, "%s not implemented for precision > 53"%self.name() _init() return parent(maxima("%s, numer"%self._maxima_init_evaled_(*args)))
def _evalf_(self, *args, **kwds): """ Returns a numerical approximation of this function using Maxima. Currently, this is limited to 53 bits of precision. EXAMPLES:: sage: from sage.functions.special import MaximaFunction sage: f = MaximaFunction("jacobi_sn") sage: f(1/2,1/2) jacobi_sn(1/2, 1/2) sage: f(1/2,1/2).n() 0.470750473655657 TESTS:: sage: f(1/2,1/2).n(150) Traceback (most recent call last): ... NotImplementedError: jacobi_sn not implemented for precision > 53 """ parent = kwds['parent'] if hasattr(parent, 'prec') and parent.prec() > 53: raise NotImplementedError, "%s not implemented for precision > 53" % self.name( ) _init() return parent(maxima("%s, numer" % self._maxima_init_evaled_(*args)))
def assume(self): """ TEST:: sage: from sage.symbolic.assumptions import GenericDeclaration sage: decl = GenericDeclaration(x, 'even') sage: decl.assume() sage: cos(x*pi).simplify() 1 sage: decl2 = GenericDeclaration(x, 'odd') sage: decl2.assume() Traceback (most recent call last): ... ValueError: Assumption is inconsistent sage: decl.forget() """ from sage.calculus.calculus import maxima if self._context is None: # We get the list here because features may be added with time. valid_features = list(maxima("features")) if self._assumption not in [repr(x).strip() for x in list(valid_features)]: raise ValueError, "%s not a valid assumption, must be one of %s" % (self._assumption, valid_features) cur = maxima.get("context") self._context = maxima.newcontext('context' + maxima._next_var_name()) try: maxima.eval("declare(%s, %s)" % (repr(self._var), self._assumption)) # except TypeError, mess: # if 'inconsistent' in str(mess): # note Maxima doesn't tell you if declarations are redundant # raise ValueError, "Assumption is inconsistent" except RuntimeError, mess: if 'inconsistent' in str(mess): # note Maxima doesn't tell you if declarations are redundant raise ValueError, "Assumption is inconsistent" else: raise maxima.set("context", cur)
def _validate_feature(self): """ Check if this assumption is a known maxima feature, raise an error otherwise EXAMPLES:: sage: from sage.symbolic.assumptions import GenericDeclaration as GDecl sage: var('b') b sage: GDecl(b, 'bougie') b is bougie sage: _.assume() Traceback (most recent call last): ... ValueError: bougie not a valid assumption, must be one of ['analytic', ... 'symmetric'] """ from sage.calculus.calculus import maxima global _valid_feature_strings if self._assumption in _valid_feature_strings: return # We get the list here because features may be added with time. _valid_feature_strings.update( repr(x).strip() for x in list(maxima("features"))) if self._assumption in _valid_feature_strings: return raise ValueError("%s not a valid assumption, must be one of %s" % (self._assumption, sorted(_valid_feature_strings)))
def meval(x): """ Returns ``x`` evaluated in Maxima, then returned to Sage. This is used to evaluate several of these special functions. TEST:: sage: from sage.functions.special import airy_ai sage: airy_bi(1.0) 1.20742359495 """ return maxima(x).sage()
def meval(x): """ Return ``x`` evaluated in Maxima, then returned to Sage. This is used to evaluate several of these special functions. TEST:: sage: from sage.functions.special import spherical_bessel_J sage: spherical_bessel_J(2.,3.) # rel tol 1e-10 0.2986374970757335 """ return maxima(x).sage()
def _evalf_(self, *args, **kwds): """ Returns a numerical approximation of this function using Maxima. Currently, this is limited to 53 bits of precision. EXAMPLES:: sage: from sage.functions.special import MaximaFunction sage: f = MaximaFunction("jacobi_sn") sage: f(1/2, 1/2) jacobi_sn(1/2, 1/2) sage: f(1/2, 1/2).n() 0.470750473655657 sage: f(1/2, 1/2).n(20) 0.47075 sage: f(1, I).n() 0.848379519751901 - 0.0742924572771414*I TESTS:: sage: f(1/2, 1/2).n(150) Traceback (most recent call last): ... NotImplementedError: Maxima function jacobi_sn not implemented for Real Field with 150 bits of precision sage: f._evalf_(1/2, 1/2, parent=int) Traceback (most recent call last): ... NotImplementedError: Maxima function jacobi_sn not implemented for <type 'int'> sage: f._evalf_(1/2, 1/2, parent=complex) (0.4707504736556572+0j) sage: f._evalf_(1/2, 1/2, parent=RDF) 0.4707504736556572 sage: f._evalf_(1, I, parent=CDF) # abs tol 1e-16 0.8483795707591759 - 0.07429247342160791*I sage: f._evalf_(1, I, parent=RR) Traceback (most recent call last): ... TypeError: Unable to convert x (='0.848379570759176-0.0742924734216079*I') to real number. """ parent = kwds['parent'] # The result from maxima is a machine double, which corresponds # to RDF (or CDF). Therefore, before converting, we check that # we can actually coerce RDF into our parent. if parent is not float and parent is not complex: if not isinstance(parent, Parent) or not parent.has_coerce_map_from(RDF): raise NotImplementedError( "Maxima function %s not implemented for %r" % (self.name(), parent)) _init() return parent(maxima("%s, numer" % self._maxima_init_evaled_(*args)))
def _eval_(self, n, m, theta, phi, **kwargs): r""" TESTS:: sage: x, y = var('x y') sage: spherical_harmonic(1, 2, x, y) 0 sage: spherical_harmonic(1, -2, x, y) 0 sage: spherical_harmonic(1/2, 2, x, y) spherical_harmonic(1/2, 2, x, y) sage: spherical_harmonic(3, 2, x, y) 15/4*sqrt(7/30)*cos(x)*e^(2*I*y)*sin(x)^2/sqrt(pi) sage: spherical_harmonic(3, 2, 1, 2) 15/4*sqrt(7/30)*cos(1)*e^(4*I)*sin(1)^2/sqrt(pi) sage: spherical_harmonic(3 + I, 2., 1, 2) -0.351154337307488 - 0.415562233975369*I """ if n in ZZ and m in ZZ and n > -1: if abs(m) > n: return ZZ(0) return meval("spherical_harmonic({},{},{},{})".format( ZZ(n), ZZ(m), maxima(theta), maxima(phi)))
def _evalf_(self, *args, **kwds): """ Returns a numerical approximation of this function using Maxima. Currently, this is limited to 53 bits of precision. EXAMPLES:: sage: from sage.functions.special import MaximaFunction sage: f = MaximaFunction("jacobi_sn") sage: f(1/2, 1/2) jacobi_sn(1/2, 1/2) sage: f(1/2, 1/2).n() 0.470750473655657 sage: f(1/2, 1/2).n(20) 0.47075 sage: f(1, I).n() 0.848379519751901 - 0.0742924572771414*I TESTS:: sage: f(1/2, 1/2).n(150) Traceback (most recent call last): ... NotImplementedError: Maxima function jacobi_sn not implemented for Real Field with 150 bits of precision sage: f._evalf_(1/2, 1/2, parent=int) Traceback (most recent call last): ... NotImplementedError: Maxima function jacobi_sn not implemented for <type 'int'> sage: f._evalf_(1/2, 1/2, parent=complex) (0.4707504736556572+0j) sage: f._evalf_(1/2, 1/2, parent=RDF) 0.4707504736556572 sage: f._evalf_(1, I, parent=CDF) # abs tol 1e-16 0.8483795707591759 - 0.07429247342160791*I sage: f._evalf_(1, I, parent=RR) Traceback (most recent call last): ... TypeError: unable to convert '0.848379570759176-0.0742924734216079*I' to a real number """ parent = kwds['parent'] # The result from maxima is a machine double, which corresponds # to RDF (or CDF). Therefore, before converting, we check that # we can actually coerce RDF into our parent. if parent is not float and parent is not complex: if not isinstance(parent, Parent) or not parent.has_coerce_map_from(RDF): raise NotImplementedError("Maxima function %s not implemented for %r"%(self.name(), parent)) _init() return parent(maxima("%s, numer"%self._maxima_init_evaled_(*args)))
def _eval_(self, *args): """ Try to evaluate this function at ``*args``, return ``None`` if Maxima did not compute a numerical evaluation. EXAMPLES:: sage: from sage.functions.special import MaximaFunction sage: f = MaximaFunction("jacobi_sn") sage: f(1,1) tanh(1) sage: f._eval_(1,1) tanh(1) Here arccoth doesn't have 1 in its domain, so we just hold the expression: sage: elliptic_e(arccoth(1), x^2*e) elliptic_e(arccoth(1), x^2*e) Since Maxima works only with double precision, numerical results are in ``RDF``, no matter what the input precision is:: sage: R = RealField(300) sage: r = elliptic_eu(R(1/2), R(1/8)); r 0.4950737320232015 sage: parent(r) Real Double Field """ _init() try: s = maxima(self._maxima_init_evaled_(*args)) except TypeError: return None if self.name() in s.__repr__(): # Avoid infinite recursion return None else: return s.sage()
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 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 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