Repository: sagemath/sage

Issue:
AbelianGroupElement does not always reduce exponent vectors when needed
In SageMath 9.8:
```
sage: A = AdditiveAbelianGroup([3])
sage: A([6]) == A([0])
True
sage: A([6]).vector()
(0)
sage: M = AbelianGroup([3])
sage: M([6]) == M([0])  # output should be True
False
sage: M([6]).exponents()
(6,)
```
The last output contradicts the documentation of the `exponents()` method, which says
```
   OUTPUT:

   A tuple of integers for an abelian group element. The integer can
   be arbitrary if the corresponding generator has infinite order. If
   the generator is of finite order, the integer is in the range from
   0 (inclusive) to the order (exclusive).
```
The `exponents()` method should be fixed (so that it reduces the exponents modulo the respective orders) and `_richcmp_()` should use this method.  (Alternatively, `_richcmp_()` and possibly other methods could do the reduction modulo the orders, but this is probably be more fragile.)


Discussion:

Resolving patch:
diff --git a/src/sage/groups/abelian_gps/element_base.py b/src/sage/groups/abelian_gps/element_base.py
--- a/src/sage/groups/abelian_gps/element_base.py
+++ b/src/sage/groups/abelian_gps/element_base.py
@@ -64,15 +64,25 @@ def __init__(self, parent, exponents):
             sage: A,B,C = Fd.gens()
             sage: A*B^-1 in Fd
             True
+
+        Check that :issue:`35216` is fixed::
+
+            sage: M = AbelianGroup([3])
+            sage: M([5]) == M([2])
+            True
+            sage: M([3]).is_trivial()
+            True
         """
         MultiplicativeGroupElement.__init__(self, parent)
         n = parent.ngens()
         if exponents == 1:
-            self._exponents = tuple( ZZ.zero() for i in range(n) )
+            self._exponents = tuple(ZZ.zero() for i in range(n))
         else:
-            self._exponents = tuple( ZZ(e) for e in exponents )
-            if len(self._exponents) != n:
-                raise IndexError('argument length (= %s) must be %s.'%(len(exponents), n))
+            if len(exponents) != n:
+                raise IndexError('argument length (= %s) must be %s'
+                                 % (len(exponents), n))
+            self._exponents = tuple(ZZ(e % o if o else e) for e, o in
+                                    zip(exponents, parent.gens_orders()))
 
     def __hash__(self):
         r"""
@@ -256,9 +266,8 @@ def _div_(left, right):
         """
         G = left.parent()
         assert G is right.parent()
-        exponents = [ (x-y)%order if order!=0 else x-y
-                      for x, y, order in
-                      zip(left._exponents, right._exponents, G.gens_orders()) ]
+        exponents = [x - y for x, y in
+                     zip(left._exponents, right._exponents)]
         return G.element_class(G, exponents)
 
     def _mul_(left, right):
@@ -275,9 +284,8 @@ def _mul_(left, right):
         """
         G = left.parent()
         assert G is right.parent()
-        exponents = [ (x+y)%order if order!=0 else x+y
-                      for x, y, order in
-                      zip(left._exponents, right._exponents, G.gens_orders()) ]
+        exponents = [x + y for x, y in
+                     zip(left._exponents, right._exponents)]
         return G.element_class(G, exponents)
 
     def __pow__(self, n):
@@ -294,8 +302,7 @@ def __pow__(self, n):
         if n != m:
             raise TypeError('argument n (= '+str(n)+') must be an integer.')
         G = self.parent()
-        exponents = [ (m*e) % order if order!=0 else m*e
-                      for e,order in zip(self._exponents, G.gens_orders()) ]
+        exponents = [m * e for e in self._exponents]
         return G.element_class(G, exponents)
 
     def __invert__(self):
@@ -319,8 +326,7 @@ def __invert__(self):
             (-1, 4)
         """
         G = self.parent()
-        exponents = [(-e) % order if order != 0 else -e
-                     for e, order in zip(self._exponents, G.gens_orders())]
+        exponents = [-e for e in self._exponents]
         return G.element_class(G, exponents)
 
     def is_trivial(self):


Test patch: