#1173: implement numerical evaluation of erf at complex arguments
----------------------------------------------------------------------+-----
   Reporter:  was                                                     |         
 Owner:  was         
       Type:  enhancement                                             |         
Status:  needs_work  
   Priority:  major                                                   |      
Milestone:  sage-4.7.2  
  Component:  calculus                                                |       
Keywords:              
Work_issues:  add erf(sqrt(2)) and erf(45000).n(), formatting, speed  |       
Upstream:  N/A         
   Reviewer:  Burcin Erocal                                           |         
Author:  D. S. McNeil
     Merged:                                                          |   
Dependencies:  #11513      
----------------------------------------------------------------------+-----

Comment(by dsm):

 Now I remember why I found this so frustrating.  I rewrote the patch
 following -- plagiarizing is more like it! -- the pattern used in #11143,
 but the speed issue hasn't gone away.

 {{{

 # 4.7.1, OS X 10.6.8
 sage: timeit('erf(0.1)',number=1000)
 1000 loops, best of 3: 82.9 µs per loop
 sage: timeit('erf(10.0)',number=1000)
 1000 loops, best of 3: 72.8 µs per loop
 sage: timeit('erf(100.0)',number=1000)
 1000 loops, best of 3: 73.5 µs per loop

 # 4.7.2 before patch
 sage: timeit('erf(0.1)',number=1000)
 1000 loops, best of 3: 69.4 µs per loop
 sage: timeit('erf(10.0)',number=1000)
 1000 loops, best of 3: 62.6 µs per loop
 sage: timeit('erf(100.0)',number=1000)
 1000 loops, best of 3: 62 µs per loop

 # 4.7.2 after patch
 sage: timeit('erf(0.1)',number=1000)
 1000 loops, best of 3: 137 µs per loop
 sage: timeit('erf(10.0)',number=1000)
 1000 loops, best of 3: 116 µs per loop
 sage: timeit('erf(100.0)',number=1000)
 1000 loops, best of 3: 116 µs per loop

 sage: import mpmath
 sage: timeit('mpmath.erf(0.1)')
 625 loops, best of 3: 95 µs per loop
 sage: timeit('mpmath.erf(10.0)')
 625 loops, best of 3: 75.4 µs per loop
 sage: timeit('mpmath.erf(100.0)')
 625 loops, best of 3: 76.2 µs per loop

 }}}

 That is, there's about a factor of two penalty in speed for the standard
 case, but it's not because the underlying mpmath code is slow:

 {{{
 sage: timeit('mpmath.erf(0.1r)')
 625 loops, best of 3: 27.7 µs per loop
 sage: timeit('mpmath.erf(10.0r)')
 625 loops, best of 3: 9.85 µs per loop
 sage: timeit('mpmath.erf(100.0r)')
 625 loops, best of 3: 9.95 µs per loop
 }}}

 In fact, mpmath isn't that much slower than MPFR:

 {{{
 sage: z = RR(2); timeit('z.erf()')
 625 loops, best of 3: 20 µs per loop
 sage: z = 2.0r; timeit('mpmath.erf(z)')
 625 loops, best of 3: 57.9 µs per loop
 sage: timeit('erf(2.0)') # new code
 625 loops, best of 3: 181 µs per loop
 }}}

 So not much of the total time is spent actually doing any calculations:
 it's all overhead.  :-(  This affects #11143 as well:

 {{{
 sage: timeit('exp_integral_e1(2.0)')
 625 loops, best of 3: 165 µs per loop
 sage: z = exp_integral_e1(2); timeit('z.n()')
 625 loops, best of 3: 143 µs per loop
 sage: timeit('exponential_integral_1(2.0)')
 625 loops, best of 3: 44.7 µs per loop
 sage: timeit('mpmath.e1(2.0)')
 625 loops, best of 3: 123 µs per loop
 sage: timeit('mpmath.e1(2.0r)')
 625 loops, best of 3: 51 µs per loop

 }}}


 To wrap up:

 (1) Both this patch and #11143 suffer a significant slowdown relative to
 PARI, and have major overheads relative to calling mpmath.  Some of that's
 unavoidable given the symbolic path, but ISTM we should be able to do
 better.  Ideally there would be a reasonably efficient general special
 function implementation pattern, along the lines of what Benjamin used,
 that intermittent developers like me could be pointed to as a reference.

 (2) In the case of erf and erfc, mpfr offers a very fast evaluation for
 real numbers, fast enough that it might be worth using as the default in
 those cases (although Python-level branching is slow in my experience,
 maybe slow enough to wash away the benefits).  Once we settle on an
 approach for erf I'll do the same for erfc.

 (3) Should I move this out of other.py to special.py, where the
 complementary error_fcn function lives now?  It would seem a more natural
 location for it.  We also have some unfortunate naming (erf and error_fcn)
 it might be worth addressing.

 I don't have numbers for #11948 -- too many dependencies -- but it's
 probably considerably faster than this approach.  I figure it's probably
 worth getting the #11143 -style mpmath wrapper to be faster, though, even
 if we went #11948 instead for erf/erfc.

 [There are a few doctest failures:
 "devel/sage/doc/en/bordeaux_2008/l_series.rst", which I think is
 unrelated; a timeout in devel/sage/sage/modules/free_module.py, again
 probably unrelated.]

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/1173#comment:26>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sage-trac?hl=en.

Reply via email to