I have rewritten the karatsuba algorithm for
Polynomial_generic_dense_field. The code needs some cleaning, but it
is already usable at #10255

My primary personal motivation is that, for number fields as base
rings, karatsuba performs worse than the generic multiplication. For
this concrete problem is probably much better to create a custom class
(ticket #10591), but the patch at #10255 already introduces an
enhancement for several base rings that currently use
Polynomial_generic_dense_field code such as:

ZZ[I][x]: x200 faster
ZZ[I,sqrt(2)][x]: x30 faster
QuaternionAlgebra(1,1)[x]: x2 faster
SR[x]: x2 faster
PolynomialRing(MatrixSpace(QQ,2),'x'): x1.45 faster

Comparing the new code with the previous one:

- It has less function calls, less slicing of lists and less `if`
branches (this has a low impact).
- It does not perform plenty of unnecessary additions of python 0 +
ModuleElement (this has a very high impact over some base rings, like
QQ[I] and ZZ[I] due to slow coercion of python 0).
- User has ring-wise control over the karatsuba threshold to fall back
to the school method, this can speed up things in some cases. By
default the threshold 0, no school method at all, the same as the
previous implementation. But this is customizable using
PolynomialRing.set_karatsuba_thresold. This is quite ring and input
dependent and may introduce a performance penalty, so use this at your
own risk!
- The case of different sized inputs is treated differently. for
polynomials f and g of degree m-1 and n-1. The previous implementation
used as split point min(n,m)/2. I feel that it is inefficient in many
cases:

{{{
sage: K=ZZ[x]
sage: f=K.random_element(4000)
sage: g=K.random_element(2000)
sage: h=K.random_element(1500)
sage: %time _= f._mul_generic(g)
CPU times: user 0.90 s, sys: 0.00 s, total: 0.90 s
Wall time: 0.90 s
sage: %time _= f._mul_karatsuba(g)
CPU times: user 2.65 s, sys: 0.00 s, total: 2.66 s
Wall time: 2.66 s
sage: %time _= f._mul_karatsuba(h)
CPU times: user 3.41 s, sys: 0.00 s, total: 3.41 s
Wall time: 3.42 s
}}}

The new code, for f is of degree m-1 and g of degree n-1 with m<n,
consider g as:

g0 + x^m*g1 + x^(2*m)g2 + ... + x^(q*m)*gq

Compute the products f*gi recursively with karatsuba and reconstruct
f*g.
I took the idea from some documentation of an old implementation of
gmp. This is still not optimal in all cases, for instance, the pair of
degrees (6700,6000) is slightly slower than the pair of degrees
(6700,6700).

Does anyone knows any alternative that is easy to implement to
Karatsuba for different degree polynomials?

With the new code

{{{
sage: sage: K=ZZ[x]
sage: sage: f=K.random_element(4000)
sage: sage: g=K.random_element(2000)
sage: sage: h=K.random_element(1500)
sage: sage: %time _= f._mul_generic(g)
CPU times: user 0.90 s, sys: 0.00 s, total: 0.90 s
Wall time: 0.91 s
sage: sage: %time _= f._mul_karatsuba(g)
CPU times: user 0.24 s, sys: 0.00 s, total: 0.25 s
Wall time: 0.25 s
sage: sage: %time _= f._mul_karatsuba(h)
CPU times: user 0.26 s, sys: 0.00 s, total: 0.26 s
Wall time: 0.26 s
}}}

Do you think that it is a good idea to include this code in the sage
library?

Any comment and/or suggestion for improvement is welcomed.

Bests

Luis

-- 
To post to this group, send an email to sage-devel@googlegroups.com
To unsubscribe from this group, send an email to 
sage-devel+unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org

Reply via email to