Ticket #3749 (closed defect: fixed)
[with patch; with positive review] Request for a method "is_cyclic" for groups in SAGE
| Reported by: | ljpk | Owned by: | joyner |
|---|---|---|---|
| Priority: | minor | Milestone: | sage-3.3 |
| Component: | group theory | Keywords: | |
| Cc: | Work issues: | ||
| Report Upstream: | Reviewers: | ||
| Authors: | Merged in: | ||
| Dependencies: | Stopgaps: |
Description
It appears that there is no method is_cyclic for groups in SAGE; this is a command that MAGMA does have, and one which I think is fairly basic. It would be nice if this was included in a version of SAGE.
Attachments
Change History
comment:2 Changed 5 years ago by wdj
It's there:
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: G.is_cyclic() False sage:
comment:3 Changed 5 years ago by ljpk
It isn't there for AbelianGroup?:
F = AbelianGroup(3,[2]*3) F.is_cyclic()
gives
Traceback (click to the left for traceback) ... AttributeError: 'AbelianGroup_class' object has no attribute 'is_cyclic'
comment:4 Changed 5 years ago by wdj
I could easily create one (and I'd be happy to) but I am concerned with interfering with David Roe's rewrite of the AbelianGroup? class. One way to do it (which might break with the new class) is to just look at the invariants. The other way, which is probably unbreakable (though slower, especially for larger groups) is to convert to a permutation group (using the permutation_group method in the AbelianGroup? class) and then apply is_cyclic. I'd prefer hearing comments from others before going ahead with one of these.
comment:5 Changed 4 years ago by was
Don't worry about what David Roe is doing -- this ticket has been idle for nearly 6 months. And definitely *DON'T* convert to a permutation group -- that's crazy -- you should use the invariants.
comment:7 Changed 4 years ago by was
- Summary changed from Request for a method "is_cyclic" for groups in SAGE to [with patch; needs work] Request for a method "is_cyclic" for groups in SAGE
REFEREE REPORT:
This implementation is wrong and inefficient.
- Wrong -- the group Z/2 + Z/4 is cyclic.
sage: AbelianGroup([2,4]).is_cyclic() True
- Inefficient -- even if it were right, the actual way it is coded is inefficient, since once you find a duplicate you would be done. No need to iterate through the whole loop then check a flag at the end.
---
I just noticed that the function elementary_divisors on finite abelian groups isn't documented, in that it doesn't say what it does. Since it could be ambiguous I wish it were documented.
I think A.is_cyclic() should be true if and only if every element of the output of elementary_divisors is coprime. Given that factoring prime powers is fast, the following should be a reasonable is_cyclic function (and it's only 2 lines!):
sage: def is_cyclic(A):
v = [a.factor()[0][0] if a else 0 for a in A.elementary_divisors()]
return len(v) == len(set(v))
This works on finite groups:
sage: is_cyclic(AbelianGroup([3,5])) True sage: is_cyclic(AbelianGroup([2,4])) False sage: is_cyclic(AbelianGroup([2,2])) False sage: is_cyclic(AbelianGroup([6])) True sage: is_cyclic(AbelianGroup([15,1,21])) False
This fails on infinite groups since the function elementary_divisors itself has a bug on infinite groups!
sage: AbelianGroup([0,5]).elementary_divisors() ... ArithmeticError: Prime factorization of 0 not defined.
I think the above should return [0,5].
That said, it is disturbing that elementary_divisors isn't documented, and moreover the choice of definition is inconsistent with the one for matrices over ZZ (made by pari, actually):
sage: a = matrix(ZZ, 3, [0,0,0, 0,5,0, 0,0,3]) ; a [0 0 0] [0 5 0] [0 0 3] sage: a.elementary_divisors() [1, 15, 0] sage: AbelianGroup([5,3]).elementary_divisors() [3, 5]
So elementary_divisors for matrices gives invariants d_i where d_1 | d_2 | ..., With that choice of elementary divisors definition, the is_cyclic function would be easy:
def is_cyclic(A):
return len(A.elementary_divisors()) <= 1
I think the elementary_divisors function for abelian groups could be "cheesily" fixed for now by just defining things in terms of matrices:
sage: def elementary_divisors(A): ....: v = A.invariants() ....: return diagonal_matrix(ZZ,v).elementary_divisors() ....: sage: elementary_divisors(AbelianGroup([5,3])) [1, 15] sage: elementary_divisors(AbelianGroup([0,0,5,3])) [1, 15, 0, 0]
This obviously sucks because of the waste of memory (a matrix takes more), but is good because at least it is definitely *correct* and consistent, and I think correct and consistent is more important than speed. We can fix the speed later once this consistency is established and tested.
Summary:
- Change elementary_divisors to use matrices for consistency and correctness, and fix all corresponding doctests.
- Change is_cyclic to just be "len(self.elementary_divisors()) <= 1", and add much better doctests for is_cyclic, e.g, testing infinite groups and Z/2 x Z/3, etc.
comment:8 Changed 4 years ago by was
Robert Miller points that there is an easy algorithm for computing the elementary divisors d1, d2, d3, of a finite abelian group, where elementary divisors means d1 | d2 | d3 | ...
Just factor the numbers a_i that define the abelian group. Then the biggest d_i is the product of the maximum prime powers dividing some a_j. I.e., d_i is the product of pv, where v = max(ord_p(a_j) for all j). Then divide out all those pv's, and repeat to compute d_{i-1}.
Changed 4 years ago by wdj
-
attachment
trac_3749-is_cyclic2.patch
added
Apply other patch first. Based on 3.2.2.alpha1
comment:9 Changed 4 years ago by wdj
- Summary changed from [with patch; needs work] Request for a method "is_cyclic" for groups in SAGE to [with patch; needs review] Request for a method "is_cyclic" for groups in SAGE
Followed instructions almost to the letter. (I think the code for
def elementary_divisors...
given above needed a minor change.) Passes sage -t. I will report problems with sage -testall. (This takes a long time on my machine ubuntu 8.10 machine currently.) Hope it is okay to post the patch first.
comment:10 Changed 4 years ago by was
- Summary changed from [with patch; needs review] Request for a method "is_cyclic" for groups in SAGE to [with patch; needs work] Request for a method "is_cyclic" for groups in SAGE
- Is this statement that is in the docs still true? "Thus we see that the "invariants" are not the invariant factors but the "elementary divisors" (in the terminology of Rotman [R])."
- It doesn't make sense to include in the docs that paragraph about how to compute the elementary divisors, because we didn't implement that algorithm. It would make sense to include that paragraph as a comment and say -- when somebody wants to speed this code up, please implement this algorithm.
- Is this actually necessary:
665 if 1 in edivs: 666 edivs.remove(1)
Since I think that the only possible way 1 can be in evids is if evids = [1], in which case the group is trivial, hence cyclic.
comment:11 Changed 4 years ago by wdj
In reply to
Is this actually necessary: 665 if 1 in edivs: 666 edivs.remove(1)
As elementary_divisors is implemented:
sage: J = AbelianGroup([2,3]) sage: J.invariants() [2, 3] sage: J.elementary_divisors() [1, 6]
But we probably should have
sage: J = AbelianGroup([2,3]) sage: J.invariants() [2, 3] sage: J.elementary_divisors() [6]
since you want the elementary divisor of AbelianGroup?([2,3]) to be the same as that of AbelianGroup?([6]).
I'll try to fix this too.
Changed 4 years ago by wdj
-
attachment
trac_3749-is_cyclic3.patch
added
The others should be applied first. Based on 3.2.2.alpha1
comment:12 Changed 4 years ago by wdj
I think this last patch fixes things the way you suggested. Also, both abelian_groups.py and dual_abelian_groups.py pass sage -t now.
comment:13 Changed 4 years ago by wdj
- Summary changed from [with patch; needs work] Request for a method "is_cyclic" for groups in SAGE to [with patch; needs review] Request for a method "is_cyclic" for groups in SAGE
comment:14 Changed 4 years ago by cremona
- Summary changed from [with patch; needs review] Request for a method "is_cyclic" for groups in SAGE to [with patch; with positive review] Request for a method "is_cyclic" for groups in SAGE
Review: I have been avoiding reviewing this for ages since I hate the whole abelian groups code so much that every time I look at it I want to rewrite it from scratch, but am never going to have the time. But that is silly.
This code (after applying all three patches in succession to 3.2.3) gives correct answers now for both elementary_divisors() and is_cyclic(), as far as I can see. So it can pass.
comment:15 Changed 4 years ago by mabshoff
- Status changed from new to closed
- Resolution set to fixed
- Milestone changed from sage-3.4.1 to sage-3.3
Merged all three patches in Sage 3.3.alpha0

Please remember to assign a default milestone.
Cheers,
Michael