.. include:: definitions.def Gotchas and pitfalls ==================== SymPy is being written in and runs under `Python `_, a general purpose programming language, so there are a few things that may be quite different from what can be experienced in other symbolic mathematics or computer algebra systems like Maple or Mathematica. These are some of the gotchas and pitfalls that you may encounter when using SymPy. ``1/3`` is not a rational number -------------------------------- Users of classical symbolic mathematics systems like Maple or Mathematica, are accustomed to typing ``1/3`` and get the rational number one over three. In SymPy this gives either ``0`` or a floating point number, depending on whether we use old or new division. This is considered most disturbing difference between SymPy and other mathematical systems. First, this strange behavior comes from the fact that Python is a general purpose programming language and for a very long time it didn't have support for rational numbers in the standard library. This changed in Python 2.6, where the :class:`Fraction` class was introduced, but it would be anyway unusual for Python to make ``/`` return a rational number. To construct a rational number in SymPy, one can use :class:`Rational` class:: >>> r = Rational(1, 3) >>> r 1/3 >>> type(r) >>> int(r) 0 >>> float(r) 0.333333333333 >>> r.evalf() 0.333333333333333 There are also other ways:: >>> Integer(1)/3 1/3 >>> S(1)/3 1/3 ``S`` is SymPy's registry of singletons. It implements the ``__call__`` method, which is a shorthand for :func:`sympify`. Using ``S`` is the most concise way to construct rational numbers. The last way is to pass a string with ``1/3`` to :func:`sympify`:: >>> sympify("1/3") 1/3 >>> type(_) :func:`sympify` implements a :mod:`tokenize`--based preparser that puts Python's numeric types in envelopes consisting of SymPy's numeric class constructors. You can also avoid this problem by not typing ``int/int`` when other terms are involved. For example, write ``2*x/3`` instead of ``2/3*x``. And you can type ``sqrt(x)`` instead of ``x**Rational(1, 2)``, as the two are equivalent. ``^`` is not exponentiation operator ------------------------------------ SymPy uses the same default arithmetic operators as Python. Most of these, like ``+``, ``-``, ``*`` and ``/``, are standard. There are, however, some differences when comparing SymPy to standalone mathematical systems. One of the differences is lack of implied multiplication, to which Mathematica users may be accustomed:: >>> var('x') >>> 2*x 2*x >>> 2x Traceback (most recent call last): ... SyntaxError: invalid syntax >>> 2 x Traceback (most recent call last): ... SyntaxError: invalid syntax More importantly, Python uses ``**`` to denote exponentiation, whereas other mathematical systems use ``^`` operator. Notable exceptions to this rule are Axiom and Maple, which allow both, though most users may not be aware of this. For example in Mathematica, ``**`` operator is used for non-commutative multiplication. So in Sympy the following expression is perfectly valid:: >>> (x + 1)**2 2 (x + 1) >>> type(_) but using ``^``:: >>> (x + 1)^2 Traceback (most recent call last): ... TypeError: unsupported operand type(s) for ^: 'Add' and 'int' gives use :exc:`TypeError`. For users' convenience, :func:`sympify` converts ``^`` to ``**`` by default in a string:: >>> sympify("(x + 1)^2") 2 (x + 1) >>> type(_) People who what pure Python behavior of :func:`sympify` can disable this automatic conversion by passing ``convert_xor=False`` to it. ``=`` is not comparison operator -------------------------------- The equals sign (``=``) is the assignment operator in Python, not equality operator. In other many mathematical systems, ``=`` is used for comparing values and/or for constructing equalities, but with SymPy you have to use ``==`` for the former and ``Eq(x, y)`` for the later. Note that instances of :class:`Eq` class, in boolean context, collapse to ``==``:: >>> var('x,y') >>> x == y False >>> Eq(x, y) x = y >>> bool(_) False Why you shouldn't write ``10**-1000`` ------------------------------------- Symbolic mathematics systems are expected to work with expressions of arbitrary size, limited only by the size of available memory. Python supports arbitrary precision integers by default, but allows only fixed precision floats. Thus you can write:: >>> 10**-10 1e-10 but:: >>> 10**-1000 0.0 is not what we expect. To overcome this, we have to make the base an instance of SymPy's floating point type:: >>> Float(10.0)**-1000 1.00000000000000e-1000 Note that we can't write simply ``Float(10)``, because SymPy automatically converts this to an instance of :class:`Integer` class and thus:: >>> type(Float(10)**-1000) Of course we could issue:: >>> (Float(10)**-1000).evalf() 1.00000000000000e-1000 but this it is neither readable, nor efficient. You can also pass the entire number as a string to :class:`Float`. If you do this, you must use the scientific notation syntax:: >>> Float("1e-1000") 1.00000000000000e-1000 Finally, we note that it is preferable to use exact (i.e., rational) numbers when the values of the numbers are exactly known. Many parts of SymPy work better when rational numbers are used instead of floating point numbers. This is because rational numbers do not suffer from some of the problems of floating point numbers, like rounding errors. This is especially the case for exponents:: >>> factor(x**2.0 - 1) x**2.0 - 1 >>> factor(x**2 - 1) (x - 1)*(x + 1) The first expression is not factored because the factorization only holds for the exponent of `2` *exactly*. This problem can also come up when using floating point coefficients:: >>> solve([2*x + y**2, y - x], [x, y]) [(-2, -2), (0, 0)] >>> solve([2.0*x + y**2, y - x], [x, y]) Traceback (most recent call last): ... DomainError: can't compute a Groebner basis over RR Here, the algorithm for solving systems of polynomial equations relies on computing a |groebner| basis (see the :ref:`groebner-bases` section below for more information on these). But the algorithm for computing this currently does not support floating point coefficients, so :func:`solve` fails in that case. How to deal with limited recursion depth ---------------------------------------- Very often algorithms in symbolic mathematics and computer algebra are highly recursive in nature. This can be a problem even for relatively small inputs in SymPy, because Python interpreters set a limit on the depth of recursion. Suppose we want to compute, manipulate and print the following function composition: .. math:: \underbrace{(f \circ f \circ \ldots \circ f)}_{1000}(x) Computing this isn't a problem:: >>> f = Function('f') >>> x = Symbol('x') >>> u = x >>> for i in xrange(1000): ... u = f(x) ... >>> type(u) f However, if we try to get the number of all subexpressions of ``u`` that contain ``f``, we get the following error:: >>> len(u.find(f)) Traceback (most recent call last): ... RuntimeError: maximum recursion depth exceeded while calling a Python object The same happens when we try to print ``u``:: >>> len([ c for c in str(u) if c == 'f' ]) Traceback (most recent call last): ... RuntimeError: maximum recursion depth exceeded while calling a Python object Python provides, at least partially, a solution to this problem by allowing the user to relax the limit on recursion depth:: >>> import sys >>> sys.setrecursionlimit(1050) >>> len(u.find(f)) 1000 To print ``u`` we have to relax the limit even more:: >>> len([ c for c in str(u) if c == 'f' ]) Traceback (most recent call last): ... RuntimeError: maximum recursion depth exceeded while calling a Python object >>> sys.setrecursionlimit(5500) >>> len([ c for c in str(u) if c == 'f' ]) 1000 This should be a warning about the fact that often it is possible to perform computations with highly nested expressions, but it is not possible to print those expressions without relaxing the recursion depth limit. SymPy never uses ``sys.setrecursionlimit`` automatically, so it's users responsibility to relax the limit whenever needed. Unless you are using a highly nested expression like the one above, you generally won't encounter this problem, as the default limit of 1000 is generally high enough for the most common expressions. Expression caching and its consequences --------------------------------------- To improve speed of computations, SymPy by default caches all intermediate subexpressions. The difference is easily visible when running tests: .. parsed-literal:: $ :input:`SYMPY_USE_CACHE=yes bin/test sympy/integrals/tests/test_risch.py` ============================= test process starts ============================== executable: /usr/bin/python2.6 (2.6.6-final-0) architecture: 64-bit ground types: gmpy sympy/integrals/tests/test_risch.py[20] .....ffff........... [OK] ======= tests finished: 16 passed, 4 expected to fail, in 28.18 seconds ======== $ :input:`SYMPY_USE_CACHE=no bin/test sympy/integrals/tests/test_risch.py` ============================= test process starts ============================== executable: /usr/bin/python2.6 (2.6.6-final-0) architecture: 64-bit ground types: gmpy sympy/integrals/tests/test_risch.py[20] .....ffff........... [OK] ======= tests finished: 16 passed, 4 expected to fail, in 64.82 seconds ======== (note the time needed to run the tests at the end of the each test run) and in interactive sessions: .. parsed-literal:: $ :input:`bin/isympy -q` IPython console for SymPy 0.7.1 (Python 2.7.1-64-bit) (ground types: gmpy) In [1]: f = (x-tan(x)) / tan(x)**2 + tan(x) In [2]: %time integrate(f, x); CPU times: user 0.46 s, sys: 0.00 s, total: 0.46 s Wall time: 0.49 s In [4]: %time integrate(f, x); CPU times: user 0.24 s, sys: 0.00 s, total: 0.24 s Wall time: 0.25 s $ :input:`bin/isympy -q -C` IPython console for SymPy 0.7.1 (Python 2.7.1-64-bit) (ground types: gmpy, cache: off) In [1]: f = (x-tan(x)) / tan(x)**2 + tan(x) In [2]: %time integrate(f, x); CPU times: user 1.82 s, sys: 0.00 s, total: 1.82 s Wall time: 1.84 s In [4]: %time integrate(f, x); CPU times: user 1.82 s, sys: 0.00 s, total: 1.82 s Wall time: 1.83 s (``-C`` is equivalent to setting ``SYMPY_USE_CACHE="no"``). The main consequence of caching is that SymPy can use a lot of resources in certain situations. One can use :func:`clear_cache` to reduce memory consumption: .. sourcecode:: ipython In [6]: from sympy.core.cache import clear_cache In [7]: clear_cache() In [8]: %time integrate(f, x); CPU times: user 0.46 s, sys: 0.00 s, total: 0.46 s Wall time: 0.47 s As caching influences computation times, any benchmarking must be performed with cache off. Otherwise those measurements will be either inaccurate or completely wrong (measuring how fast SymPy can retrieve data from cache, rather than actual computing times): .. sourcecode:: ipython $ bin/isympy -q IPython console for SymPy 0.7.1 (Python 2.7.1-64-bit) (ground types: gmpy) In [1]: %timeit sin(2*pi); 10000 loops, best of 3: 28.7 us per loop $ bin/isympy -q -C IPython console for SymPy 0.7.1 (Python 2.7.1-64-bit) (ground types: gmpy, cache: off) In [1]: %timeit sin(2*pi); 100 loops, best of 3: 2.75 ms per loop The difference between using and not using cache is two orders of magnitude. Naming convention of trigonometric inverses ------------------------------------------- SymPy uses different names than most computer algebra systems for some of the commonly used elementary functions. In particular, the inverse trigonometric and hyperbolic functions use Python's naming convention, so we have :func:`asin`, :func:`asinh`, :func:`acos` and so on, instead of :func:`arcsin`, :func:`arcsinh`, :func:`arccos`, etc. Container indices start at zero ------------------------------- It should be obvious for people using Python, even for beginners, that when indexing containers like ``list`` or ``tuple``, indexes start at zero, not one:: >>> L = symbols('x:5') >>> L (x₀, x₁, x₂, x₃, x₄) >>> L[0] x₀ >>> L[1] x₁ This is a common thing in general purpose programming languages. However, most symbolic mathematics systems, especially those which invent their own mathematical programming language, use `1`--based indexing, sometimes reserving the `0`--th index for special purpose (e.g. head of expressions in Mathematica).