Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix comparison for divisors of curves (and FormalSum commutativity) #37972

Merged
merged 22 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions src/sage/schemes/generic/divisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,29 @@ def is_Divisor(x):
class Divisor_generic(FormalSum):
r"""
A Divisor.

TESTS::

sage: E = EllipticCurve([1, 2])
sage: P = E(-1, 0)
sage: Q = E(1, 2)
sage: Pd = E.divisor(P)
sage: Qd = E.divisor(Q)
sage: Pd + Qd == Qd + Pd
True
sage: Pd != Qd
True
sage: C = EllipticCurve([2, 1])
sage: R = C(1, 2)
sage: Rd = C.divisor(R)
sage: Qd == Rd
False
sage: Rd == Qd
False
sage: Qd == (2 * (Qd * 1/2))
True
sage: Qd == 1/2 * Qd
False
"""

def __init__(self, v, parent, check=True, reduce=True):
Expand Down Expand Up @@ -363,14 +386,15 @@ def _repr_(self):
"""
return repr_lincomb([(tuple(I.gens()), c) for c, I in self])

def support(self):
def support(self) -> list:
"""
Return the support of this divisor, which is the set of points that
occur in this divisor with nonzero coefficients.

EXAMPLES::

sage: x,y = AffineSpace(2, GF(5), names='xy').gens()
sage: A = AffineSpace(2, GF(5), names='xy')
sage: x, y = A.gens()
sage: C = Curve(y^2 - x^9 - x)
sage: pts = C.rational_points(); pts
[(0, 0), (2, 2), (2, 3), (3, 1), (3, 4)]
Expand Down
30 changes: 30 additions & 0 deletions src/sage/schemes/generic/divisor_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,36 @@ def _element_constructor_(self, x, check=True, reduce=True):
else:
return Divisor_generic([(self.base_ring()(1), x)], check=False, reduce=False, parent=self)

def _coerce_map_from_(self, other):
r"""
Return if there is a coercion map from ``other`` to ``self``.

There is a coercion from another divisor group if the
schemes are equal and there is a coercion map from
vincentmacri marked this conversation as resolved.
Show resolved Hide resolved
the base rings.

TESTS::

sage: C = EllipticCurve([2, 1])
sage: E = EllipticCurve([1, 2])
sage: C.divisor_group()._coerce_map_from_(E.divisor_group())
False
sage: E.divisor_group()._coerce_map_from_(C.divisor_group())
False
sage: E.divisor_group()._coerce_map_from_(E.divisor_group())
True
sage: C.divisor_group()._coerce_map_from_(C.divisor_group())
True
sage: D = 1/2 * E.divisor(E(1, 2))
sage: D.parent()._coerce_map_from_(E.divisor_group())
True
sage: E.divisor_group()._coerce_map_from_(D.parent())
False
"""
return (isinstance(other, DivisorGroup_generic)
and self.scheme().has_coerce_map_from(other.scheme())
and super()._coerce_map_from_(other))

def scheme(self):
r"""
Return the scheme supporting the divisors.
Expand Down
18 changes: 17 additions & 1 deletion src/sage/structure/formal_sum.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ def __init__(self, x, parent=None, check=True, reduce=True):
- ``reduce`` -- reduce (default: ``True``) if ``False``, do not
combine common terms

.. WARNING::

Setting ``reduce`` to ``False`` can cause issues when comparing
equal sums but with different orders and/or cancellations.

EXAMPLES::

sage: FormalSum([(1,2/3), (3,2/3), (-5, 7)])
Expand Down Expand Up @@ -230,8 +235,19 @@ def _richcmp_(self, other, op):
True
sage: a == 0 # 0 is coerced into a.parent()(0)
False

TESTS::

sage: a = FormalSum([(1, 3), (2, 5)])
sage: b = FormalSum([(2, 5), (1, 3)])
sage: a == b
True
sage: b == a
True
"""
return richcmp(self._data, other._data, op)
self_data = [(c, x) for (x, c) in sorted(self._data, key=str)]
other_data = [(c, x) for (x, c) in sorted(other._data, key=str)]
return richcmp(self_data, other_data, op)

def _neg_(self):
"""
Expand Down