.. _gotchas: ==================== Gotchas and Pitfalls ==================== .. role:: input(strong) Introduction ============ SymPy runs under the `Python Programming Language `_, so there are some things that may behave differently than they do in other, independent computer algebra systems like Maple or Mathematica. These are some of the gotchas and pitfalls that you may encounter when using SymPy. See also the `FAQ `_, the :ref:`Tutorial`, the remainder of the SymPy Docs, and the `official Python Tutorial `_. If you are already familiar with C or Java, you might also want to look this `4 minute Python tutorial `_. Ignore ``#doctest: +SKIP`` in the examples. That has to do with internal testing of the examples. .. _equals-signs: Equals Signs (=) ================ Single Equals Sign ------------------ The equals sign (``=``) is the assignment operator, not an equality. If you want to do :math:`x=y`, use ``Eq(x,y)`` for equality. Alternatively, all expressions are assumed to equal zero, so you can just subtract one side and use ``x - y``. The proper use of the equals sign is to assign expressions to variables. For example: >>> from sympy.abc import x, y >>> a = x - y >>> print a x - y Double Equals Signs ------------------- Double equals signs (``==``) are used to test equality. However, this tests expressions exactly, not symbolically. For example: >>> (x + 1)**2 == x**2 + 2*x + 1 False >>> (x + 1)**2 == (x + 1)**2 True If you want to test for symbolic equality, one way is to subtract one expression from the other and run it through functions like :func:`expand`, :func:`simplify`, and :func:`trigsimp` and see if the equation reduces to 0. >>> from sympy import simplify, cos, sin, expand >>> simplify((x + 1)**2 - (x**2 + 2*x + 1)) 0 >>> simplify(sin(2*x) - 2*sin(x)*cos(x)) -2*cos(x)*sin(x) + sin(2*x) >>> expand(sin(2*x) - 2*sin(x)*cos(x), trig=True) 0 .. note:: See also `Why does SymPy say that two equal expressions are unequal? `_ in the FAQ. Variables ========= Variables Assignment does not Create a Relation Between Expressions ------------------------------------------------------------------- When you use ``=`` to do assignment, remember that in Python, as in most programming languages, the variable does not change if you change the value you assigned to it. The equations you are typing use the values present at the time of creation to "fill in" values, just like regular Python definitions. They are not altered by changes made afterwards. Consider the following: >>> from sympy import Symbol >>> a = Symbol('a') # Create a Symbol named a, that is also stored in the variable "a" >>> b = a + 1 # Create another object, b, that refers to 'a' >>> print b 1 + a >>> a = 4 # a now points to the literal integer 4, not Symbol('a') >>> print a 4 >>> b # But b is still pointing at Symbol('a') 1 + a Changing quantity :obj:`a` does not change :obj:`b`; you are not working with a set of simultaneous equations. It might be helpful to remember that the string that gets printed when you print a variable refering to a sympy object is the string that was given to it when it was created; that string does not have to be the same as the variable that you assign it to. >>> from sympy import var >>> r, t, d = var('rate time short_life') >>> d = r*t >>> print d rate*time >>> r=80 >>> t=2 >>> print d # We haven't changed d, only r and t rate*time >>> d=r*t >>> print d # Now d is using the current values of r and t 160 If you need variables that have dependence on each other, you can define functions. Use the ``def`` operator. Indent the body of the function. See the Python docs for more information on defining functions. >>> c, d = var('c d') >>> print c c >>> print d d >>> def ctimesd(): ... """ ... This function returns whatever c is times whatever d is. ... """ ... return c*d ... >>> ctimesd() c*d >>> c = 2 >>> print c 2 >>> ctimesd() 2*d If you define a circular relationship, you will get a :WARNING: document isn't included in any toctree :exc:`RuntimeError`. >>> def a(): ... return b() ... >>> def b(): ... return a() ... >>> a() Traceback (most recent call last): File "...", line ..., in ... compileflags, 1) in test.globs File "<...>", line 1, in a() File "<...>", line 2, in a return b() File "<...>", line 2, in b return a() File "<...>", line 2, in a return b() ... RuntimeError: maximum recursion depth exceeded .. note:: See also `Why doesn't changing one variable change another that depends on it? `_ in the FAQ. .. _symbols: Symbols ------- Symbols are variables, and like all other variables, they need to be assigned before you can use them. For example: >>> import sympy >>> z**2 # z is not defined yet #doctest: +SKIP Traceback (most recent call last): File "", line 1, in NameError: name 'z' is not defined >>> sympy.var('z') # This is the easiest way to define z as a standard symbol z >>> z**2 z**2 If you use :command:`isympy`, it runs the following commands for you, giving you some default Symbols and Functions. >>> from __future__ import division >>> from sympy import * >>> x, y, z = symbols('xyz') >>> k, m, n = symbols('kmn', integer=True) >>> f, g, h = map(Function, 'fgh') You can also import common symbol names from :mod:`sympy.abc`. >>> from sympy.abc import w >>> w w >>> import sympy >>> dir(sympy.abc) #doctest: +SKIP ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Symbol', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_greek', '_latin', 'a', 'alpha', 'b', 'beta', 'c', 'chi', 'd', 'delta', 'e', 'epsilon', 'eta', 'f', 'g', 'gamma', 'h', 'i', 'iota', 'j', 'k', 'kappa', 'l', 'm', 'mu', 'n', 'nu', 'o', 'omega', 'omicron', 'p', 'phi', 'pi', 'psi', 'q', 'r', 'rho', 's', 'sigma', 't', 'tau', 'theta', 'u', 'upsilon', 'v', 'w', 'x', 'xi', 'y', 'z', 'zeta'] If you want control over the assumptions of the variables, use :func:`Symbol` and :func:`symbols`. See :ref:`Keyword Arguments` below. Lastly, it is recomended that you not use :obj:`I`, :obj:`E`, :obj:`S`, :obj:`N`, :obj:`C`, or :obj:`O` for variable or symbol names, as those are used for the imaginary unit (:math:`i`), the base of the natural logarithm (:math:`e`), the :func:`sympify` function (see :ref:`Symbolic Expressions` below), evaluation (:func:`N` is equivalent to :ref:`evalf()` ), the class registry (for things like :func:`C.cos`, to prevent cyclic imports in some code), and the `big O `_ order symbol (as in :math:`O(n\log{n})`), respectively. You can use the mnemonic ``COSINE`` to remember what Symbols are defined by default in SymPy. Or better yet, always use lowercase letters for Symbol names. Python will not prevent you from overriding default SymPy names or functions, so be careful. >>> from sympy import * >>> cos(pi) # cos and pi are a built-in sympy names. -1 >>> pi = 3 # Notice that there is no warning for overriding pi. >>> cos(pi) cos(3) >>> def cos(x): # No warning for overriding built-in functions either. ... return 5*x ... >>> cos(pi) 15 To get a full list of all default names in SymPy do: >>> import sympy >>> dir(sympy) #doctest: +SKIP # A big list of all default sympy names and functions follows. # Ignore everything that starts and ends with __. If you have `iPython `_ installed and use :command:`isympy`, you can also press the TAB key to get a list of all built-in names and to autocomplete. Also, see `this page `_ for a trick for getting tab completion in the regular Python console. .. note:: See also `What is the best way to create symbols? `_ in the FAQ. .. _symbolic-expressions: Symbolic Expressions ==================== .. _python-vs-sympy-numbers: Python numbers vs. SymPy Numbers -------------------------------- SymPy uses its own classes for integers, rational numbers, and floating point numbers instead of the default Python :obj:`int` and :obj:`float` types because it allows for more control. But you have to be careful. If you type an expression that just has numbers in it, it will default to a Python expression. Use the :func:`sympify` function, or just :func:`S`, to ensure that something is a SymPy expression. >>> 6.2 # Python float. Notice the floating point accuracy problems. #doctest: +SKIP 6.2000000000000002 >>> type(6.2) >>> S(6.2) # SymPy Real has no such problems because of arbitrary precision. 6.20000000000000 >>> type(S(6.2)) If you include numbers in a sympy expression, they will be sympified automatically, but there is one gotcha you should be aware of. If you do ``/`` inside of a SymPy expression, Python will evaluate the two numbers into a float before SymPy has a chance to get to them. The solution is to :func:`sympify` one of the numbers, or use :mod:`Rational`. .. note:: A common mistake is copying an expression that is printed and reusing it. If the expression has a :mod:`Rational` (i.e., ``/``) in it, you will not get the same result. >>> x = Symbol('x') >>> print solve(x**2-2,x) [-2**(1/2), 2**(1/2)] >>> [-2**(1/2), 2**(1/2)] # If we just copy and paste, the expression is evaluated by Python #doctest: +SKIP [-1.41421356237, 1.41421356237] >>> # One solution is to just assign the expression to a variable >>> # if we need to use it again. >>> a = solve(x**2-2,x) >>> a [-2**(1/2), 2**(1/2)] >>> # The other solution is to put quotes around the expession and run it through S() (sympify) >>> S("[-2**(1/2), 2**(1/2)]") [-2**(1/2), 2**(1/2)] Also, if you do not use :command:`isympy`, you should do ``from __future__ import division`` to prevent the ``/`` sign from performing `integer division `_. >>> 1/2 # in regular python, this defaults to integer division, which truncates the fractional part #doctest: +SKIP 0 >>> from __future__ import division >>> from sympy import * >>> 1/2 # This uses regular division, but it still evaluates to a python float #doctest: +SKIP 0.5 >>> 1//2 # You can still achieve integer division with // 0 >>> # Either of these will produce the rational number one half: >>> S(1)/2 1/2 >>> Rational(1,2) 1/2 >>> var('x') x >>> x**(1/2) # Be careful with /, even in SymPy expressions #doctest: +SKIP x**0.5 >>> x**(S(1)/2) x**(1/2) >>> sqrt(x) # sqrt(x) does the exact same thing as x**(S(1)/2) x**(1/2) >>> sqrt(x) == x**(S(1)/2) True :mod:`Rational` only works for number/number and is only meant for rational numbers. If you want a fraction with symbols or expressions in it, just use ``/``. If you do number/expression or expression/number, then the number will automatically be converted in to a SymPy Number. You only need to be careful with number/number. >>> Rational(2, x) Traceback (most recent call last): File "...", line ..., in ... compileflags, 1) in test.globs File "<...>", line 1, in Rational(2, x) ... TypeError: int() argument must be a string or a number, not 'Symbol' >>> 2/x 2/x Mathematical Operators ---------------------- SymPy uses the same default operators as Python. Most of these, like ``*/+-``, are standard. Aside from integer division discussed in :ref:`Python numbers vs. SymPy Numbers ` above, you should also be aware that implied multiplication is not allowed. You need to use ``*`` whenever you wish to multiply something. Also, to raise something to a power, use ``**``, not ``^`` as many computer algebra systems use. Parentheses ``()`` change operator precedence as you would normally expect. In :command:`isympy`, with the :command:`ipython` shell:: >>> 2x Traceback (most recent call last): ... SyntaxError: invalid syntax >>> 2*x 2*x >>> x^2 # This is not power. Use ** instead. Traceback (most recent call last): File "", line 1, in TypeError: unsupported operand type(s) for ^: 'Symbol' and 'int' >>> x**2 x**2 >>> pprint(3 - x**(2*x)/(x + 1)) 2*x x 3 - ----- 1 + x Inverse Trig Functions ---------------------- SymPy uses different names for some functions than most computer algebra systems. In particular, the inverse trig functions use the python names of :func:`asin`, :func:`acos` and so on instead of the usual ``arcsin`` and ``arccos``. Use the methods described in :ref:`Symbols ` above to see the names of all SymPy functions. Special Symbols =============== The symbols ``[]``, ``{}``, ``=``, and ``()`` have special meanings in Python, and thus in SymPy. See the Python docs linked to above for more additional information. .. _lists: Lists ----- Square brackets ``[]`` denote a list. A list is a container that holds any number of different objects. A list can contain anything, including items of different types. Lists are mutable, which means that you can change the elements of a list after it has been created. You access the items of a list also using square brackets, placing them after the list or list variable. Items are numbered using the space before the item. .. note:: List indexes begin at 0. Example: >>> a = [x, 1] # A simple list of two items >>> a [x, 1] >>> a[0] # This is the first item x >>> a[0] = 2 # You can change values of lists after they have been created >>> print a [2, 1] >>> print solve(x**2+2*x-1,x) # Some functions return lists [-1 + 2**(1/2), -1 - 2**(1/2)] .. note:: See the Python docs for more information on lists and the square bracket notation for accessing elements of a list. Dictionaries ------------ Curly brackets ``{}`` denote a dictionary, or a dict for short. A dictionary is an unordered list of non-duplicate keys and values. The syntax is ``{key:value}``. You can access values of keys using square bracket notation. >>> d = {'a':1, 'b':2} # A dictionary. >>> d {'a': 1, 'b': 2} >>> d['a'] # How to access items in a dict 1 >>> roots((x-1)**2*(x-2),x) # some functions return dicts {1: 2, 2: 1} >>> # Some SymPy functions return dictionaries. For example, >>> # roots returns a dictionary of root:multiplicity items. >>> roots((x - 5)**2*(x + 3),x) {-3: 1, 5: 2} >>> # This means that the root -3 occurs once and the root 5 occurs twice. .. note:: See the python docs for more information on dictionaries. Tuples ------ Parentheses ``()``, aside from changing operator precedence and their use in function calls, (like ``cos(x)``), are also used for tuples. A ``tuple`` is identical to a :ref:`list `, except that it is not mutable. That means that you can not change their values after they have been created. In general, you will not need tuples in SymPy, but sometimes it can be more convenient to type parentheses instead of square brackets. >>> t = (1, 2, x) # Tuples are like lists >>> t (1, 2, x) >>> t[0] 1 >>> t[0] = 4 # Except you can not change them after they have been created Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment >>> (x,) # Single element tuples, unlike lists, must have a comma in them. (x,) >>> (x) # Not a tuple x >>> # integrate takes a tuple as the second argument if you want to integrate with limits. >>> integrate(x**2, (x, 0, 1)) 1/3 >>> integrate(x**2, [x, 0, 1]) # But a list works too. 1/3 .. note:: See the Python docs for more information on tuples. .. _keyword-arguments: Keyword Arguments ----------------- Aside from the usage described :ref:`above `, equals signs (``=``) are also used to give named arguments to functions. Any function that has ``key=value`` in its parameters list (see below on how to find this out), then ``key`` is set to ``value`` by default. You can change the value of the key by supplying your own value using the equals sign in the function call. Also, functions that have ``**`` followed by a name in the parameters list (usually ``**kwargs`` or ``**assumptions``) allow you to add any number of ``key=value`` pairs that you want, and they will all be evaluated according to the function. >>> # sqrt(x**2) doesn't auto simplify to x because x is assumed to be >>> # complex by default, and, for example, sqrt((-1)**2) == sqrt(1) == 1 != -1. >>> sqrt(x**2) (x**2)**(1/2) >>> x = Symbol('x', positive=True) # One example of keyword arguments is assumptions for Symbols >>> sqrt(x**2) # only == x if x >= 0 x >>> pprint(powsimp(x**n*x**m*y**n*y**m)) # powsimp has a default argument, combine='all' m + n (x*y) >>> # Setting combine to the default value is the same as not setting it. >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='all')) m + n (x*y) >>> # The non-default options are 'exp', which combines exponenents... >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='exp')) m + n m + n x *y >>> # ...and 'base', which combines bases. >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='base')) m n (x*y) *(x*y) .. note:: See the Python docs for more information on function parameters. Getting help from within SymPy ============================== help() ------ Although all docs are available at docs.sympy.org or on the `SymPy Wiki `_, you can also get info on functions from within the Python interpreter that runs SymPy. The easiest way to do this is to do ``help(function)``, or ``function?`` if you are using :command:`ipython`:: In [1]: help(powsimp) # help() works everywhere In [2]: # But in ipython, you can also use ?, which is better because it In [3]: # it gives you more information In [4]: powsimp? These will give you the function parameters and docstring for :func:`powsimp`. The output will look something like this: .. module:: sympy.simplify.simplify .. autofunction:: powsimp source() -------- Another useful option is the :func:`source` function. This will print the source code of a function, including any docstring that it may have. You can also do ``function??`` in :command:`ipython`. For example, from SymPy 0.6.5: >>> source(simplify) # simplify() is actually only 2 lines of code. #doctest: +SKIP In file: ./sympy/simplify/simplify.py def simplify(expr): """Naively simplifies the given expression. ... Simplification is not a well defined term and the exact strategies this function tries can change in the future versions of SymPy. If your algorithm relies on "simplification" (whatever it is), try to determine what you need exactly - is it powsimp()? radsimp()? together()?, logcombine()?, or something else? And use this particular function directly, because those are well defined and thus your algorithm will be robust. ... """ expr = Poly.cancel(powsimp(expr)) return powsimp(together(expr.expand()), combine='exp', deep=True)