Here's my findings:
1) pari is faster with polynomial of degree 30-300. For higher degree, NTL wins
and wins big asymptotically -- degree 2000 random poly takes "forever" with pari
and 45 seconds with NTL.
2) pari seems to be a bit better when coefficients are larger but degree is
still low. For example, NTL is very fast for small degree (<10), but once we
start choosing larger coefficients (140 bits), pari becomes much more
competitive. However, this point seems fraught with special cases. I think the
point may be that pari integer arithmetic beats NTL integer arithmetic, but
naive testing with ntl.ZZ and pari('') are indicating otherwise.
3) My tests seem to indicate that NTL's performs better when there are small
factors, but it doesn't seem a decisive difference. This doesn't seem real
helpful for choosing an algorithm in general though. It could be a point to
keep in mind for more specialized uses of factoring when you might know more
about the poly in hand.
I'd be curious if there are any comments about this. I'm going to change the
criteria in ticket 1558 to make pari factor when degree is between 30 and 300
and otherwise let NTL factor.
--
Joel
John
--
John Cremona
Well, I know I'm using the default 2.9 build, and I know I see these timings:
sage: p=pari(1234157)
sage: r=ntl.ZZ(1234157)
sage: timeit p^300
10000 loops, best of 3: 33.8 µs per loop
sage: timeit r^300
10000 loops, best of 3: 21.7 µs per loop
I realize the exponentiation is a fairly narrow minded view of the whole of
integer arithmetic, but the difference there seems a little striking to both be
using gmp. However, I guess it really isn't fair since the pari is a gen
object, but a the NTL ZZ is known as an integer. So, here this might be more
fair to compare an ntl.ZZX with pari:
sage: s=ntl.ZZX([1234157])
sage: timeit s^300
10000 loops, best of 3: 94.6 µs per loop
I don't know, that seems bizarre to me!
--
Joel
>
> I get about 7us per loop on sage.math for Pari for the exponentiation.
> So perhaps this is all architecture dependent. This would not surprise
> me in the slightest.
>
> At any rate, I suspect the algorithms used for factorisation are
> implemented quite differently between NTL and Pari. Since both Pari
> and NTL use GMP mpn's for underlying integer arithmetic in SAGE, I
> think the algorithms being used for factorisation are much more
> relevant than the speed of basic arithmetic, which should be the same
> for both.
>
> The other point is that both Pari and NTL use finite field stuff to
> factor polynomials over the integers. So the speed of integer
> arithmetic is almost irrelevant.
>
> Having said all that, it is surprising that NTL is behind Pari for
> polynomial factorisation, given the amount of work Victor put into
> this. Can you try your example problems on sage.math?
On the other hand, Shoup's research is mostly about the asymptotics
for very large degree problems, so perhaps he didn't bother trying to
optimise the small polynomial case very much (?)
david
Yeah, in the end, I don't think I believe the speed increase for large
coefficients either. I think what I did observe was probably a result of
accidents with semi-random polynomials.
Here's a snippet from my patched branch:
Loading SAGE library. Current Mercurial branch is: uni-factoring
sage: R.<x>=ZZ[]
sage: f=x^2-1
sage: timeit f._factor_ntl() ######## NTL wins
10000 loops, best of 3: 159 µs per loop
sage: timeit f._factor_pari()
1000 loops, best of 3: 794 µs per loop
sage: f=R.random_element(6)
sage: timeit f._factor_ntl() ######### NTL wins
1000 loops, best of 3: 316 µs per loop
sage: timeit f._factor_pari()
1000 loops, best of 3: 533 µs per loop
I'm not seeing this NTL win on your chart. I'm wondering if this might be
because of data-conversion costs to pari. Of course, that data conversion is
a cost of the sage implementation so when making the cutoff choices for sage
we need to include the conversion costs.
--
Joel
The library and I think the conversion is done correctly. It's a bit of
convoluted path in the sage code to get in this specific case though so there
might be other silly issues.
> The other thing is, you are factoring a single random polynomial,
> which may be irreducible. Factoring generic polynomials may be much
> faster, since one only needs to know it is irreducible and then one
> need not do any factoring. I will prepare a graph comparing the time
> to factor generic polynomials, though I don't in general think that is
> such a great benchmark, unless one specifically wants to tune for that
> situation (which could be a nice idea if one had a certain flag that
> could be set to indicate that one expected the polynomials being
> factored to be vaguely generic).
My observation is that random polynomials are almost always irreducible. This
fact seems in startling contrast to the case for integers! For instance:
sage: R.<x>=ZZ[]
sage: R.random_element(6,-2^23,2^23).factor()
# virtually always 1 factor
I've actually been doing tests of 3 different cases (not all of which made it
to the mailing list).
1) product of a bunch of small factors
2) product of 2 medium factors
3) random (irreducible by comments above)
NTL seems to gain a bit relative to pari when there are non-trivial factors,
but it doesn't seem too significant. It's main influence in my cutoff points
has been to let NTL factor small polys out to degree 30 rather than degree
10. But both are so competitive for degree 10-20 that it's not that big of a
deal.
--
Joel
Conclusion: Magma completely totally devastates both PARI and NTL,
except for some
small cases? That's what the plots seem to say.
I now really wonder how Maple and Mathematica do in comparison.
William