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

Fixed a bug in AbelianGroup.Subgroup.gens_orders(), which returns the reduced order of the subgroup #36986

Merged
merged 8 commits into from
Jan 22, 2024
42 changes: 24 additions & 18 deletions src/sage/groups/abelian_gps/abelian_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ def _normalize(n, gens_orders=None, names="f"):
names = tuple(names)
return (gens_orders, names)


def AbelianGroup(n, gens_orders=None, names="f"):
r"""
Create the multiplicative abelian group in `n` generators
Expand Down Expand Up @@ -444,6 +445,7 @@ def AbelianGroup(n, gens_orders=None, names="f"):
M = AbelianGroup_class(gens_orders, names)
return M


def is_AbelianGroup(x):
"""
Return True if ``x`` is an Abelian group.
Expand Down Expand Up @@ -514,7 +516,7 @@ class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase):
"""
Element = AbelianGroupElement

def __init__(self, generator_orders, names, category=None):
def __init__(self, generator_orders, names, gens_orders=None, category=None):
"""
The Python constructor

Expand All @@ -535,8 +537,8 @@ def __init__(self, generator_orders, names, category=None):
"""
assert isinstance(names, (str, tuple))
assert isinstance(generator_orders, tuple)
assert all(isinstance(order,Integer) for order in generator_orders)
self._gens_orders = generator_orders
assert all(isinstance(order, Integer) for order in generator_orders)
self._gens_orders = generator_orders if gens_orders is None else gens_orders
n = len(generator_orders)
names = normalize_names(n, names)
self._assign_names(names)
Expand Down Expand Up @@ -943,7 +945,7 @@ def gens(self):
sage: [g.order() for g in F.gens()]
[+Infinity, +Infinity, +Infinity, 3, 2]
"""
return tuple( self.gen(i) for i in range(self.ngens()) )
return tuple(self.gen(i) for i in range(self.ngens()))

def gens_orders(self):
"""
Expand Down Expand Up @@ -976,13 +978,15 @@ def gens_orders(self):
sage: Z2xZ3 is Z6
False

TESTS::

amanmoon marked this conversation as resolved.
Show resolved Hide resolved
TESTS::
sage: G, (g0, g1) = AbelianGroup(2, [48, 0]).objgens()
amanmoon marked this conversation as resolved.
Show resolved Hide resolved
sage: G0 = G.subgroup([g0])
sage: len(G0.gens()) == len(G0.gens_orders())
True
sage: F = AbelianGroup(3, [2], names='abc')
sage: list(map(type, F.gens_orders()))
[<class 'sage.rings.integer.Integer'>,
<class 'sage.rings.integer.Integer'>,
<class 'sage.rings.integer.Integer'>]
[<class 'sage.rings.integer.Integer'>, <class 'sage.rings.integer.Integer'>, <class 'sage.rings.integer.Integer'>]
amanmoon marked this conversation as resolved.
Show resolved Hide resolved
"""
return self._gens_orders

Expand Down Expand Up @@ -1175,7 +1179,7 @@ def random_element(self):
order = g.order()
if order is infinity:
order = 42 # infinite order; randomly chosen maximum
result *= g**(randint(0,order))
result *= g**(randint(0, order))
amanmoon marked this conversation as resolved.
Show resolved Hide resolved
return result

def _repr_(self):
Expand Down Expand Up @@ -1553,8 +1557,8 @@ def subgroup_reduced(self, elts, verbose=False):
rel_lattice = X.span([X.gen(i) * self.gens_orders()[i] for i in range(d)])
isect = elt_lattice.intersection(rel_lattice)
mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)
D,U,V = mat.smith_form()
new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i,i]) for i in range(U.ncols())]
D, U, V = mat.smith_form()
new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i, i]) for i in range(U.ncols())]
return self.subgroup([self([x[0][i] % self.gens_orders()[i]
for i in range(d)]) for x in new_basis if x[1] != 1])

Expand Down Expand Up @@ -1627,7 +1631,7 @@ def __init__(self, ambient, gens, names="f", category=None):
Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a^3, b}
sage: F.subgroup([c])
Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 generated by {c}
sage: F.subgroup([a, c])
sage: S = F.subgroup([a, c]); S
amanmoon marked this conversation as resolved.
Show resolved Hide resolved
Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x Z generated by {a, c}
sage: F.subgroup([a, b*c])
Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b*c}
Expand Down Expand Up @@ -1657,7 +1661,7 @@ def __init__(self, ambient, gens, names="f", category=None):
sage: B = A.subgroup([a^3, b, c, d, e^2]); B
Multiplicative Abelian subgroup isomorphic to C4 x C5 x C5 x C7 generated by {b, c, d, e^2}
sage: B.gens_orders()
(4, 5, 5, 7)
(5, 5, 7, 4)
sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names="abcd")
sage: a,b,c,d = A.gens()
sage: B = A.subgroup([a^3,b,c,d])
Expand All @@ -1682,7 +1686,7 @@ def __init__(self, ambient, gens, names="f", category=None):
Multiplicative Abelian subgroup isomorphic to C2 x C3 x Z
generated by {a, b^2, c}
sage: F.gens_orders()
(2, 3, 0)
(3, 2, 0)
sage: F.gens()
(a, b^2, c)
sage: F.order()
Expand All @@ -1708,16 +1712,19 @@ def __init__(self, ambient, gens, names="f", category=None):
H = libgap(ambient).Subgroup(H_gens)

invs = H.TorsionSubgroup().AbelianInvariants().sage()
gens_orders = [order_sage for g in H.GeneratorsOfGroup() if (order_sage := g.Order().sage()) is not infinity]
amanmoon marked this conversation as resolved.
Show resolved Hide resolved

rank = len([1 for g in H.GeneratorsOfGroup()
if g.Order().sage() is infinity])
invs += [0] * rank

gens_orders += [0] * rank
amanmoon marked this conversation as resolved.
Show resolved Hide resolved
self._abinvs = invs
invs = tuple(ZZ(i) for i in invs)
gens_orders = tuple(ZZ(i) for i in gens_orders)
amanmoon marked this conversation as resolved.
Show resolved Hide resolved

if category is None:
category = Groups().Commutative().Subobjects()
AbelianGroup_class.__init__(self, invs, names, category=category)
AbelianGroup_class.__init__(self, invs, names, category=category, gens_orders=gens_orders)

def __contains__(self, x):
"""
Expand Down Expand Up @@ -1770,8 +1777,7 @@ def __contains__(self, x):
ZZ, len(self._gens), len(amb_inv),
[g.list() for g in self._gens]
)
return (vector(ZZ, x.list())
in inv_basis.stack(gens_basis).row_module())
return (vector(ZZ, x.list()) in inv_basis.stack(gens_basis).row_module())
amanmoon marked this conversation as resolved.
Show resolved Hide resolved
return False

def ambient_group(self):
Expand Down
Loading