#6043: [with patch, needs review] optimize the construction of Lagrange
interpolation polynomials
-------------------------+--------------------------------------------------
 Reporter:  mvngu        |       Owner:  tbd       
     Type:  enhancement  |      Status:  new       
 Priority:  major        |   Milestone:  sage-4.0.1
Component:  algebra      |    Keywords:            
-------------------------+--------------------------------------------------
Description changed by mvngu:

Old description:

> As the subject says.

New description:

 The method {{{lagrange_polynomial()}}} in
 {{{sage/rings/polynomial/polynomial_ring.py}}} for generating the
 {{{n}}}-th Lagrange interpolation polynomial currently is a
 straightforward implementation that uses the definition of Lagrange
 interpolation polynomial. This is inefficient if one wants to use more
 interpolating points to generate a better Lagrange interpolation
 polynomial. To generate a better interpolation polynomial, the method
 currently would generate it from scratch. The patch {{{trac_6043.patch}}}
 adds two options to the method {{{lagrange_polynomial()}}}:
  * {{{neville}}} --- (default: False) If True, then use a variant of
 Neville's method to recursively generate the n-th Lagrange interpolation
 polynomial. This adaptation of Neville's method is more memory efficient
 than the original Neville's method, since the former doesn't generate the
 full Neville table resulting from Neville's recursive procedure. Instead
 the adaptation only keeps track of the current and previous rows of the
 said table. If False, which it is by default, then fall back on the
 definition of Lagrange interpolation polynomial.
  * {{{previous_row}}} --- (default: None) Here "previous row" refers to
 the last row in the Neville table that was obtained from a previous
 computation of an n-th Lagrange interpolation polynomial using Neville's
 method. If the last row is provided, then use a memory efficient variant
 of Neville's method to recursively generate a better interpolation
 polynomial from the results of previous computation.
 The following are some timing statistics obtained using sage.math. When
 the results of previous computations are fed to {{{lagrange_polynomial}}}
 in order to produce better interpolation polynomials, we can gain an
 efficiency of up to 42%.
 {{{
 # BEFORE
 # without using precomputed values to generate successively better
 interpolation polynomials

 sage: R = PolynomialRing(QQ, 'x')
 sage: timeit("R.lagrange_polynomial([(0,1),(2,2)])");
 625 loops, best of 3: 571 µs per loop
 sage: # add two more points
 sage: timeit("R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)])");
 125 loops, best of 3: 2.29 ms per loop
 sage:
 sage: R = PolynomialRing(GF(2**3,'a'), 'x')
 sage: a = R.base_ring().gen()
 sage: timeit("R.lagrange_polynomial([(a^2+a,a),(a,1)])")
 625 loops, best of 3: 76.1 µs per loop
 sage: # add another point
 sage: timeit("R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)])")
 625 loops, best of 3: 229 µs per loop
 sage:
 sage: R = PolynomialRing(QQ, 'x')
 sage: points = [(random(), random()) for i in xrange(100)]
 sage: time R.lagrange_polynomial(points);
 CPU times: user 1.21 s, sys: 0.00 s, total: 1.21 s
 Wall time: 1.21 s
 sage: # add three more points
 sage: for i in xrange(3): points.append((random(), random()))
 ....:
 sage: time R.lagrange_polynomial(points);
 CPU times: user 1.28 s, sys: 0.01 s, total: 1.29 s
 Wall time: 1.29 s
 sage: # add another 100 points
 sage: for i in xrange(100): points.append((random(), random()))
 ....:
 sage: time R.lagrange_polynomial(points);
 CPU times: user 5.87 s, sys: 0.02 s, total: 5.89 s
 Wall time: 5.89 s


 # AFTER
 # using precomputed values to generate successively better interpolation
 polynomials

 sage: R = PolynomialRing(QQ, 'x')
 sage: timeit("R.lagrange_polynomial([(0,1),(2,2)], neville=True)");
 625 loops, best of 3: 332 µs per loop
 sage: p = R.lagrange_polynomial([(0,1),(2,2)], neville=True);
 sage: # add two more points
 sage: timeit("R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)],
 neville=True, previous_row=p)");
 625 loops, best of 3: 1.41 ms per loop
 sage:
 sage: R = PolynomialRing(GF(2**3,'a'), 'x')
 sage: a = R.base_ring().gen()
 sage: timeit("R.lagrange_polynomial([(a^2+a,a),(a,1)], neville=True)");
 625 loops, best of 3: 36.4 µs per loop
 sage: p = R.lagrange_polynomial([(a^2+a,a),(a,1)], neville=True);
 sage: # add another point
 sage: timeit("R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)],
 neville=True, previous_row=p)");
 625 loops, best of 3: 131 µs per loop
 sage:
 sage: R = PolynomialRing(QQ, 'x')
 sage: points = [(random(), random()) for i in xrange(100)]
 sage: time R.lagrange_polynomial(points, neville=True);
 CPU times: user 1.26 s, sys: 0.00 s, total: 1.26 s
 Wall time: 1.26 s
 sage: p = R.lagrange_polynomial(points, neville=True);
 sage: # add three more points
 sage: for i in xrange(3): points.append((random(), random()))
 ....:
 sage: time R.lagrange_polynomial(points, neville=True, previous_row=p);
 CPU times: user 0.09 s, sys: 0.00 s, total: 0.09 s
 Wall time: 0.08 s
 sage: p = R.lagrange_polynomial(points, neville=True, previous_row=p)
 sage: # add another 100 points
 sage: for i in xrange(100): points.append((random(), random()))
 ....:
 sage: time R.lagrange_polynomial(points, neville=True, previous_row=p);
 CPU times: user 4.62 s, sys: 0.00 s, total: 4.62 s
 Wall time: 4.62 s
 }}}

--

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/6043#comment:2>
Sage <http://sagemath.org/>
Sage - Open Source Mathematical Software: Building the Car Instead of 
Reinventing the Wheel

--~--~---------~--~----~------------~-------~--~----~
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