There is already a bug report from 2023 for this one at https://github.com/sagemath/sage/issues/35238.
julian On Tuesday, April 22, 2025 at 11:47:32 PM UTC+3 vdelecroix wrote: > A simple way to fix the OP is to set FractionFieldElement.__hash__ to > return 0 always. > > Though, if we want to keep x == y implies hash(x) == hash(y) through > injective coercions then we are in trouble because of fraction fields. > One could introduce a framework for canonical representatives of > fraction field elements... but it looks like a can of worms. > > Vincent > > On Tue, 22 Apr 2025 at 19:06, Nils Bruin <[email protected]> wrote: > > > > Good find! Indeed, the fraction field of ZZ[x,y] is equally broken. It's > just less pronounced because there are fewer units: > > > > sage: K.<x,y>=ZZ[] > > sage: (-x)/(-y) > > (-x)/(-y) > > sage: (-x)/(-y) == x/y > > True > > sage: hash((x)/(y)) > > -8752216344059172460 > > sage: hash((-x)/(-y)) > > -8752216196772797820 > > > > That hash is bad in other ways too: n^d is symmetric and generally looks > quite likely to generate hash collisions (although that depends a bit on > how garbled the hashes of the numerator and denominator are) > > > > On Tuesday, 22 April 2025 at 01:35:31 UTC-7 [email protected] wrote: > >> > >> I would think that the method `__hash__` of FractionFieldElement in > fraction_field_element.pyx is broken, since > >> > >> sage: f1 = x/y > >> sage: f2 = (2*x)/(2*y) > >> sage: f1 == f2 > >> True > >> sage: hash(f1) > >> -284264079394034550 > >> sage: hash(f2) > >> -284264773958195866 > >> > >> In `__hash__`, we do the following: > >> > >> if self._parent.is_exact(): > >> ... > >> self.reduce() > >> # Same algorithm as for elements of QQ > >> n = hash(self._numerator) > >> d = hash(self._denominator) > >> if d == 1: > >> return n > >> else: > >> return n ^ d > >> > >> The problem is that `self.reduce()` doesn't have any effect: it divides > out the gcd of numerator and denominator, which is 1, since QQ is a field. > (Over ZZ it is 2, which is the reason why it works) > >> > >> I don't know how to fix this properly. Can we define a sensible hash > generically for FractionFieldElement at all? > >> > >> Partially, this might also be my fault from > https://github.com/sagemath/sage/pull/38924 > >> > >> There are other tickets that thought about this, e.g., > https://github.com/sagemath/sage/issues/16268 > >> > >> :-( > >> > >> Martin > >> > >> On Wednesday, 16 April 2025 at 17:48:47 UTC+2 Nils Bruin wrote: > >>> > >>> On Wednesday, 16 April 2025 at 04:55:39 UTC-7 Peter Mueller wrote: > >>> > >>> The following code > >>> > >>> K.<x, y> = QQ[] > >>> K = K.fraction_field() > >>> print(len({x/y, (2*x)/(2*y)})) > >>> > >>> gives the answer 2, even though the two elements of course are the > same! Is this a bug or a feature for a reason I cannot guess? Same on the > SageMath Cell. > >>> > >>> > >>> I don't think it's a feature but it might be that you're hitting > general code that can't do much more than it does. In that case we should > probably have a specialization that deals with that particular situation. > >>> > >>> In your case, we can just force the denominator to be monic. It can > make for less nice representations because it might cause fractional > coefficients in the numerator and denominator: > >>> > >>> > f.numerator()/(c:=f.denominator().leading_coefficient())/(f.denominator()/c) > >>> > >>> For this standardization, we need that there's a monomial ordering > (which would generally be met) and that the leading coefficient is a unit > (true over a field). It's the last one that is generally problematic. In > ZZ["x,y"].fraction_field(), you'd already need a different approach and > over domains with more complicated unit groups and/or without unique > factorization, normalizing the denominator is going to be very expensive. > Note that it doesn't affect the ability to compute in the field of > fractions: equality testing is still easy. It's just the normal form that's > hard (and which is necessary to get to a well-defined hash). > >>> > >>> Funniliy enough: > >>> > >>> K.<x, y> = ZZ[] > >>> > >>> K = K.fraction_field() > >>> print(len({x/y, (2*x)/(2*y)})) > >>> > >>> so it seems that the extra work was already done in that case. And > that's also the representation in which you'll avoid denominators in the > denominator! So probably it's better to switch to that representation. If > you need polynomials you can use > >>> > >>> QQ['x,y'](f) > >>> > >>> when the denominator has degree 0. > >>> > > -- > > You received this message because you are subscribed to the Google > Groups "sage-support" group. > > To unsubscribe from this group and stop receiving emails from it, send > an email to [email protected]. > > To view this discussion visit > https://groups.google.com/d/msgid/sage-support/43c4110d-3238-4039-b47f-4c593e453338n%40googlegroups.com > . > -- You received this message because you are subscribed to the Google Groups "sage-support" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/sage-support/fb644b78-1bce-41c8-9495-1b047452988en%40googlegroups.com.
