Skip to content

Commit

Permalink
Trac #23402: faster hash of number field elements
Browse files Browse the repository at this point in the history
Hashing of nf element go through `self.polynomial()` which is damn slow!

The attached branch provides a quick hash version (that is more robust
than the one for polynomial). A x10 speed up is seen on the following
example (425 ms vs 40ms)
{{{
sage: K.<b> = NumberField(x^3 - 2)
sage: l = [i * b + j * b^2 for i in range(100) for j in range(100)]
sage: l.sort()
sage: %time s = set(l[i+1] - l[i] for i in range(len(l)-1))
}}}

URL: https://trac.sagemath.org/23402
Reported by: vdelecroix
Ticket author(s): Vincent Delecroix
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager authored and vbraun committed Sep 3, 2017
2 parents 37f0944 + 8d8a2ea commit 97ac782
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 27 deletions.
8 changes: 4 additions & 4 deletions src/sage/groups/matrix_gps/finitely_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,10 +1270,10 @@ def invariants_of_degree(self, deg, chi=None, R=None):
sage: chi = G.character(G.character_table()[1])
sage: R.<x,y,z> = K[]
sage: G.invariants_of_degree(2, R=R, chi=chi)
[x^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*y^2 + (2*izeta3^3 +
3*izeta3^2 + 8*izeta3 + 3)*z^2,
x*y + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*x*z + (-2*izeta3^3 -
3*izeta3^2 - 8*izeta3 - 4)*y*z]
[x*y + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*x*z +
(-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*y*z,
x^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*y^2 +
(2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*z^2]
::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2020,9 +2020,10 @@ def simple_fixed_point_set(self, extended=True):
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
sage: el.simple_fixed_point_set()
{(-lam + 3/2)*e - 1/2*lam + 1, 1/2*e + 1/2*lam, (-lam + 3/2)*e + 1/2*lam - 1, 1/2*e - 1/2*lam}
{(-lam + 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e - 1/2*lam + 1, 1/2*e - 1/2*lam, 1/2*e + 1/2*lam}
sage: el.simple_fixed_point_set(extended=False)
{1/2*e + 1/2*lam, 1/2*e - 1/2*lam}
{1/2*e - 1/2*lam, 1/2*e + 1/2*lam}
"""
if self.parent().n() == infinity:
from warnings import warn
Expand Down Expand Up @@ -2507,7 +2508,7 @@ def is_hecke_symmetric(self):
sage: el.is_hecke_symmetric()
False
sage: (el.simple_fixed_point_set(), el.inverse().simple_fixed_point_set())
({1/2*e, (-1/2*lam + 1/2)*e}, {(1/2*lam - 1/2)*e, -1/2*e})
({1/2*e, (-1/2*lam + 1/2)*e}, {-1/2*e, (1/2*lam - 1/2)*e})
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
sage: el.is_hecke_symmetric()
Expand All @@ -2519,7 +2520,7 @@ def is_hecke_symmetric(self):
sage: el.is_hecke_symmetric()
True
sage: el.simple_fixed_point_set()
{(lam - 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e + 1/2*lam - 1, (lam - 3/2)*e - 1/2*lam + 1, (-lam + 3/2)*e - 1/2*lam + 1}
{(lam - 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e - 1/2*lam + 1, (lam - 3/2)*e - 1/2*lam + 1, (-lam + 3/2)*e + 1/2*lam - 1}
sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set()
True
"""
Expand Down
2 changes: 1 addition & 1 deletion src/sage/modular/modform_hecketriangle/readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@
sage: el.is_hecke_symmetric()
False
sage: (el.simple_fixed_point_set(), el.inverse().simple_fixed_point_set())
({1/2*e, (-1/2*lam + 1/2)*e}, {(1/2*lam - 1/2)*e, -1/2*e})
({1/2*e, (-1/2*lam + 1/2)*e}, {-1/2*e, (1/2*lam - 1/2)*e})
sage: el = G.V(2)*G.V(3)
sage: el.is_hecke_symmetric()
True
Expand Down
50 changes: 46 additions & 4 deletions src/sage/rings/number_field/number_field_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ from sage.libs.gmp.mpq cimport *
from sage.libs.mpfi cimport mpfi_t, mpfi_init, mpfi_set, mpfi_clear, mpfi_div_z, mpfi_init2, mpfi_get_prec, mpfi_set_prec
from sage.libs.mpfr cimport mpfr_equal_p, mpfr_less_p, mpfr_greater_p, mpfr_greaterequal_p, mpfr_floor, mpfr_get_z, MPFR_RNDN
from sage.libs.ntl.error import NTLError
from sage.libs.gmp.pylong cimport mpz_pythonhash

from cpython.object cimport Py_EQ, Py_NE, Py_LT, Py_GT, Py_LE, Py_GE
from sage.structure.richcmp cimport rich_to_bool

Expand Down Expand Up @@ -2854,16 +2856,56 @@ cdef class NumberFieldElement(FieldElement):

def __hash__(self):
"""
Return hash of this number field element, which is just the
hash of the underlying polynomial.
Return hash of this number field element.
It respects the hash values of rational numbers.
EXAMPLES::
sage: K.<b> = NumberField(x^3 - 2)
sage: hash(b^2 + 1) == hash((b^2 + 1).polynomial()) # indirect doctest
sage: hash(b^2 + 1) # random
175247765440
sage: hash(K(13)) == hash(13)
True
sage: hash(K(-2/3)) == hash(-2/3)
True
No collisions (even on low bits)::
sage: from itertools import product
sage: elts = []
sage: for (i,j,k) in product((-1,0,1,2,3), repeat=3):
....: x = i + j*b + k*b^2
....: elts.append(x)
....: if gcd([2,i,j,k]) == 1:
....: elts.append(x / 2)
....: if gcd([3,i,j,k]) == 1:
....: elts.append(x / 3)
sage: len(set(map(hash, elts))) == len(elts)
True
sage: len(set(hash(x)%(2^18) for x in elts)) == len(elts)
True
"""
return hash(self.polynomial())
cdef Py_hash_t h
cdef int i
cdef mpz_t z

mpz_init(z)
ZZX_getitem_as_mpz(z, &self.__numerator, 0)
h = mpz_pythonhash(z)

for i from 1 <= i <= ZZX_deg(self.__numerator):
ZZX_getitem_as_mpz(z, &self.__numerator, i)
# magic number below is floor(2^63 / (2+sqrt(2)))
h ^= mpz_pythonhash(z) + (<Py_hash_t> 2701463124188384701) + (h << 16) + (h >> 2)

ZZ_to_mpz(z, &self.__denominator)
# magic number below is floor((1+sqrt(5)) * 2^63)
h += (mpz_pythonhash(z) - 1) * (<Py_hash_t> 7461864723258187525)

mpz_clear(z)

return h

cpdef list _coefficients(self):
"""
Expand Down
9 changes: 6 additions & 3 deletions src/sage/schemes/curves/curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,12 @@ def singular_points(self, F=None):
+ 67/3*x^2*y*z^2 + 117/4*y^5 + 9*x^5 + 6*x^3*z^2 + 393/4*x*y^4\
+ 145*x^2*y^3 + 115*x^3*y^2 + 49*x^4*y], P)
sage: C.singular_points(K)
[(1/2*b^5 + 1/2*b^3 - 1/2*b - 1 : 1 : 0), (-2/3*b^4 + 1/3 : 0 : 1),
(2/3*b^4 - 1/3 : 0 : 1), (b^6 : -b^6 : 1), (-b^6 : b^6 : 1),
(-1/2*b^5 - 1/2*b^3 + 1/2*b - 1 : 1 : 0)]
[(b^6 : -b^6 : 1),
(-b^6 : b^6 : 1),
(1/2*b^5 + 1/2*b^3 - 1/2*b - 1 : 1 : 0),
(-1/2*b^5 - 1/2*b^3 + 1/2*b - 1 : 1 : 0),
(2/3*b^4 - 1/3 : 0 : 1),
(-2/3*b^4 + 1/3 : 0 : 1)]
"""
if F is None:
if not self.base_ring() in Fields():
Expand Down
32 changes: 21 additions & 11 deletions src/sage/schemes/projective/projective_morphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -3384,12 +3384,13 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety', return_s
sage: H = Hom(P,P)
sage: f = H([x^2+z^2, y^2+x^2, z^2+y^2])
sage: f.periodic_points(1)
[(-2*s^5 + 4*s^4 - 5*s^3 + 3*s^2 - 4*s : -2*s^5 + 5*s^4 - 7*s^3 + 6*s^2 - 7*s + 3 : 1),
(-s^5 + 3*s^4 - 4*s^3 + 4*s^2 - 4*s + 2 : -s^5 + 2*s^4 - 2*s^3 + s^2 - s : 1),
(2*s^5 - 6*s^4 + 9*s^3 - 8*s^2 + 7*s - 4 : 2*s^5 - 5*s^4 + 7*s^3 - 5*s^2 + 6*s - 2 : 1),
(s^5 - 2*s^4 + 2*s^3 + s : s^5 - 3*s^4 + 4*s^3 - 3*s^2 + 2*s - 1 : 1),
(s^5 - 2*s^4 + 3*s^3 - 3*s^2 + 3*s - 1 : -s^5 + 3*s^4 - 5*s^3 + 4*s^2 - 4*s + 2 : 1), (1 : 1 : 1),
(-s^5 + 3*s^4 - 5*s^3 + 4*s^2 - 3*s + 1 : s^5 - 2*s^4 + 3*s^3 - 3*s^2 + 4*s - 1 : 1)]
[(-s^5 + 3*s^4 - 5*s^3 + 4*s^2 - 3*s + 1 : s^5 - 2*s^4 + 3*s^3 - 3*s^2 + 4*s - 1 : 1),
(-2*s^5 + 4*s^4 - 5*s^3 + 3*s^2 - 4*s : -2*s^5 + 5*s^4 - 7*s^3 + 6*s^2 - 7*s + 3 : 1),
(-s^5 + 3*s^4 - 4*s^3 + 4*s^2 - 4*s + 2 : -s^5 + 2*s^4 - 2*s^3 + s^2 - s : 1),
(s^5 - 2*s^4 + 3*s^3 - 3*s^2 + 3*s - 1 : -s^5 + 3*s^4 - 5*s^3 + 4*s^2 - 4*s + 2 : 1),
(2*s^5 - 6*s^4 + 9*s^3 - 8*s^2 + 7*s - 4 : 2*s^5 - 5*s^4 + 7*s^3 - 5*s^2 + 6*s - 2 : 1),
(1 : 1 : 1),
(s^5 - 2*s^4 + 2*s^3 + s : s^5 - 3*s^4 + 4*s^3 - 3*s^2 + 2*s - 1 : 1)]
::
Expand Down Expand Up @@ -4788,9 +4789,18 @@ def all_rational_preimages(self, points):
sage: H = End(P)
sage: f = H([16*x^2 - 29*y^2, 16*y^2])
sage: f.all_rational_preimages([P(16*w^2 - 29,16)])
[(w^2 + w - 25/16 : 1), (-w - 1/2 : 1), (w^2 - 29/16 : 1), (-w : 1), (w + 1/2 : 1), (w^2 - 21/16 : 1),
(w : 1), (-w^2 + 21/16 : 1), (-w^2 - w + 25/16 : 1), (w^2 + w - 33/16 : 1), (-w^2 + 29/16 : 1),
(-w^2 - w + 33/16 : 1)]
[(-w^2 + 21/16 : 1),
(w : 1),
(w + 1/2 : 1),
(w^2 + w - 33/16 : 1),
(-w^2 - w + 25/16 : 1),
(w^2 - 21/16 : 1),
(-w^2 - w + 33/16 : 1),
(-w : 1),
(-w - 1/2 : 1),
(-w^2 + 29/16 : 1),
(w^2 - 29/16 : 1),
(w^2 + w - 25/16 : 1)]
::
Expand Down Expand Up @@ -5085,12 +5095,12 @@ def connected_rational_component(self, P, n=0):
sage: f.connected_rational_component(P)
[(w : 1),
(w^2 - 29/16 : 1),
(w^2 + w - 25/16 : 1),
(-w^2 - w + 25/16 : 1),
(w^2 + w - 25/16 : 1),
(-w : 1),
(-w^2 + 29/16 : 1),
(w + 1/2 : 1),
(-w - 1/2 : 1),
(-w^2 + 29/16 : 1),
(-w^2 + 21/16 : 1),
(w^2 - 21/16 : 1),
(w^2 + w - 33/16 : 1),
Expand Down

0 comments on commit 97ac782

Please sign in to comment.