On Tue, 14 Sept 2021 at 23:12, sandona...@gmail.com < sandona.dav...@gmail.com> wrote:
> Hello, > let's say I'd like to numerically evaluate a single sympy function over an > array using sympy as the module. Curiously, passing in regular Python's > float numbers makes the evaluation much faster then passing in Sympy's > Float instances. I tried several sympy functions, they tend to follow this > trend. > > Why does this happen? Considering that the following lambda function > always return Float instances, I thought that the input was sympified > inside a sympy function, thus making the actual python's float evaluation > slower due to casting... > > from sympy import * > import numpy as np > from mpmath import mpf > > func = sin(x) > f = np.frompyfunc(lambdify(x, func, "sympy"), 1, 1) > domain = np.linspace(0, 100, 1000) > domain_mpf = [mpf(str(t)) for t in domain] > domain_sympy = [Float(t) for t in domain] > > %timeit f(domain) > %timeit f(domain_mpf) > %timeit f(domain_sympy) > Running that here I get: ...: %timeit f(domain) ...: %timeit f(domain_mpf) ...: %timeit f(domain_sympy) 756 µs ± 58.1 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) 4.67 ms ± 130 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) 4.46 ms ± 64.6 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) However if I switch from timeit to time and run each in a separate process (close and reopen isympy in between each %time) I get: ...: %time ok = f(domain) CPU times: user 920 ms, sys: 4 ms, total: 924 ms Wall time: 921 ms ...: %time ok = f(domain_mpf) CPU times: user 824 ms, sys: 8 ms, total: 832 ms Wall time: 834 ms ...: %time ok = f(domain_sympy) CPU times: user 856 ms, sys: 16 ms, total: 872 ms Wall time: 877 ms So now f(domain) is slowest where %timeit suggested that it was fastest. Also the time measured by %time is 2-3 orders of magnitude greater than the result from %timeit. The reason that %time shows a much slower time than %timeit is because common operations in SymPy are cached. Since %timeit times things in a loop and records only the fastest runs it only ever really measures the warm-cache time. Conversely it never really tells you the time to compute something *once* which is in fact all that really matters in most situations. The 3 millisecond timing difference that you are asking about here is dwarfed by the actual 1 second time that it really takes to compute this result the first time. Most likely the time differences you see are just to do with exactly how efficient the cache lookups are for different types. It is possible to run timings with the cache disabled (env var: SYMPY_USE_CACHE=no). However then SymPy is often much slower and so those timings are also not necessarily representative of the timings seen with the cache enabled which is how SymPy is normally used. By all means investigate timeit results when micro-optimising but when you actually want to evaluate the actual real time that it takes to do something then you need to use a fresh process and time the result of running the operation precisely once. Yes, that will give noisy results compared to timeit but the results from timeit eliminate the "noise" to give a consistent but meaningless measure. Alternatively you can use %timeit but with SYMPY_USE_CACHE=no bearing in mind the caveat that in practice sympy is not normally used with that setting so it may also be unrepresentative for different reasons. -- Oscar -- You received this message because you are subscribed to the Google Groups "sympy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/CAHVvXxThamFOzU5%2BpeUyVOnBKKyuAqvQ%2BndkTj3w%3Dj935yj0yQ%40mail.gmail.com.