Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Fix hash for unreduced fraction field elements.
Browse files Browse the repository at this point in the history
  • Loading branch information
robertwb committed Apr 30, 2014
1 parent 8be52e6 commit f7266ca
Showing 1 changed file with 60 additions and 6 deletions.
66 changes: 60 additions & 6 deletions src/sage/rings/fraction_field_element.pyx
Expand Up @@ -97,6 +97,7 @@ cdef class FractionFieldElement(FieldElement):
"""
cdef object __numerator
cdef object __denominator
cdef bint _is_reduced

def __init__(self, parent, numerator, denominator=1,
coerce=True, reduce=True):
Expand Down Expand Up @@ -163,7 +164,7 @@ cdef class FractionFieldElement(FieldElement):
nden = codomain.coerce(self.__denominator._im_gens_(codomain, im_gens))
return codomain.coerce(nnum/nden)

def reduce(self):
cpdef reduce(self):
"""
Divides out the gcd of the numerator and denominator.
Expand All @@ -179,6 +180,8 @@ cdef class FractionFieldElement(FieldElement):
sage: f.reduce(); f
x + 1.0
"""
if self._is_reduced:
return
try:
g = self.__numerator.gcd(self.__denominator)
if not g.is_unit():
Expand All @@ -195,13 +198,30 @@ cdef class FractionFieldElement(FieldElement):
pass
self.__numerator = num
self.__denominator = den
self._is_reduced = True
except AttributeError:
raise ArithmeticError, "unable to reduce because lack of gcd or quo_rem algorithm"
except TypeError:
raise ArithmeticError, "unable to reduce because gcd algorithm doesn't work on input"
except NotImplementedError:
raise ArithmeticError("unable to reduce because gcd algorithm not implemented on input")

cpdef normalize(self):
"""
Returns a normalized representation of self.
In particular, for any a == b, after normalization they will have the
same numerator and denominator.
EXAMPLES::
sage: R.<x> = Frac(ZZ['x'])
sage: s = (2*x + 2) / (4*x)
sage: s.normalize(); s
(x + 1)/(2*x)
"""
self.reduce()

def __copy__(self):
"""
Make a copy of ``self``.
Expand Down Expand Up @@ -346,17 +366,31 @@ cdef class FractionFieldElement(FieldElement):
1
sage: hash(R(1)/R(2))==hash(1/2)
True
Ensure normalization is done before hashing the numerator and
denominator, fixing trac #16268::
sage: Ku.<u> = FractionField(PolynomialRing(QQ,'u'))
sage: a = 27*u^2+81*u+243
sage: b = 27*u-81
sage: c = u^2 + 3*u + 9
sage: d = u-3
sage: s = a/b
sage: t = c/d
sage: s==t
True
sage: len(Set([s,t]))
1
"""
# This is same algorithm as used for members of QQ
#cdef long n, d
self.normalize()
n = hash(self.__numerator)
d = hash(self.__denominator)
if d == 1:
return n
n = n ^ d
if n == -1:
return -2
return n
else:
return n ^ d

def __call__(self, *x, **kwds):
"""
Expand Down Expand Up @@ -973,7 +1007,7 @@ cdef class FractionFieldElement(FieldElement):
(self._parent, self.__numerator, self.__denominator))


class FractionFieldElement_1poly_field(FractionFieldElement):
cdef class FractionFieldElement_1poly_field(FractionFieldElement):
"""
A fraction field element where the parent is the fraction field of a
univariate polynomial ring.
Expand Down Expand Up @@ -1016,6 +1050,26 @@ class FractionFieldElement_1poly_field(FractionFieldElement):
L.sort()
return L

cpdef normalize(self):
"""
Returns a normalized representation of self.
In particular, for any a == b, after normalization they will have the
same numerator and denominator.
EXAMPLES::
sage: R.<x> = QQ[]
sage: s = (1 + x) / (2*x); s
(x + 1)/(2*x)
sage: s.normalize(); s
(1/2*x + 1/2)/x
"""
self.reduce()
leading = self.__denominator.leading_coefficient()
if leading != 1:
self.__numerator /= leading
self.__denominator /= leading

def make_element(parent, numerator, denominator):
"""
Expand Down

0 comments on commit f7266ca

Please sign in to comment.