Creating the (Z/5Z)^2 group in Sage : Hell among groups, parent/elements, Cartesian Products ...

370 views
Skip to first unread message

Nathann Cohen

unread,
Nov 6, 2013, 12:41:28 PM11/6/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
Helloooooooooo everybody !

Today I needed to build a cyclic group Z/nZ (and products of them),
and to be able to add elements together.
I screamed for help, Aladin offered his, we tried a few things and
Hell followed.
I report those bugs, as I know next to nothing about groups and
categories, and I have no idea how to fix those myself.... Without
destroying something else :-P

1) I did not know at first how to create Z/nZ in Sage.
* I tried groups.<tab> and found "groups.permutation.Cyclic" but
its elements are permutations, not integers. Which is normal.
* I tried g=groups.presentation.Cyclic(5) and though I do not know
what "presentation" means it seems to be what I need. Thouuuugh g(2)
raises an exception, and I can't make a group element from an integer.
And... Well :

sage: g = groups.presentation.Cyclic(5)
sage: a=g.group_generators()[0]
sage: a*a
a^2
sage: a**80
a^80

* Aladin remembered the existence of IntegerModRing, equivalent to
Integers, both in the global namespace. They seem to do the job,
though none of them is exactly the most natural thing to try when you
want to build Z/nZ. And they are rings while I just want a group. But
they seem to do the job :

sage: G=Integers(5)
sage: G(1), G(6), G(3) + G(3)
(1, 1, 1)

Note : there is also an IntegerMod in the global namespace,
whose docstring reads : "Create an integer modulo n with the given
parent. This is mainly for internal use."

2) Using IntegerModRing, or Integers. Let's begin :

sage: groups.matrix.GL(3,2) in Groups
True
sage: Integers(5) in Groups
False

Then, I tried to create (Z/5Z)^2 from G=Integers(5). But how ?

a) G.cartesian_product()

sage: G2 = G.cartesian_product(G)
sage: G2((3,3))
(3, 3)
sage: G2((3,3))+G2((3,3))
TypeError: unsupported operand type(s) for +:
'CartesianProduct_with_category.element_class' and
'CartesianProduct_with_category.element_class'
sage: G2((3,3))*G2((3,4))
(9, 12)

12 is an unusual thing in Z/5Z. And anyway :

sage: G2((9,12)) == G2((4,2))
False

In particular, I don't get how computing a product LOST the
addition defined on the elements of my two groups/rings/whatever.

b) G.CartesianProduct() (yes, it has a .cartesian_product method
AND a CartesianProduct method)

sage: G.CartesianProduct(G)
TypeError: __init__() takes at least 3 arguments (2 given)
sage: G.CartesianProduct(G,G)
AttributeError: 'IntegerModRing_generic_with_category' object
has no attribute 'parent_class'

c) The global CartesianProduct function

sage: G2=CartesianProduct(G,G)
sage: G2((1,1))
[1, 1]
sage: G2((1,1))+G2((1,1))
TypeError: can only concatenate list (not "CombinatorialObject") to list
sage: G2((1,1))*G2((1,1))
TypeError: unsupported operand type(s) for *:
'CombinatorialObject' and 'CombinatorialObject'

Sooooooo that was my attempt at "creating Z/nZ in Sage". And I gave
up, but I still to do this for my next patch ^^;

Have fuuuuuuuuuuuuuuuuun everybody !!!

Nathann

Volker Braun

unread,
Nov 6, 2013, 12:56:07 PM11/6/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
Sounds like you want this:

sage: Z5xZ5 = AdditiveAbelianGroup([5, 5])
sage: x = Z5xZ5([1,3])
sage: x
(3, 1)
sage: x + x
(1, 2)
sage: 5*x
(0, 0)
sage: 5*x == 0
True

Note that a "presentation of a group" is actually a thing: http://en.wikipedia.org/wiki/Presentation_of_a_group

kcrisman

unread,
Nov 6, 2013, 1:44:53 PM11/6/13
to sage-...@googlegroups.com


On Wednesday, November 6, 2013 12:56:07 PM UTC-5, Volker Braun wrote:
Sounds like you want this:

sage: Z5xZ5 = AdditiveAbelianGroup([5, 5])
sage: x = Z5xZ5([1,3])
sage: x
(3, 1)
sage: x + x
(1, 2)
sage: 5*x
(0, 0)
sage: 5*x == 0
True

John H Palmieri

unread,
Nov 6, 2013, 3:10:54 PM11/6/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
Two questions:

- should AdditiveAbelianGroup be accessible through "groups.[TAB]"? Say as "groups.additive.AdditiveAbelianGroup"?

- Why in the world are AdditiveAbelianGroupWrapperElement and AdditiveAbelianGroupWrapper (not to mention UnwrappingMorphism) in the top-level name space? That is, why do we have the line

    from additive_abelian_wrapper import *

in sage.groups.additive_abelian.all? I wonder if we should have a meta-ticket about cleaning up top-level imports...

--
John

Vincent Delecroix

unread,
Nov 6, 2013, 3:31:11 PM11/6/13
to sage-...@googlegroups.com
2013/11/6, John H Palmieri <jhpalm...@gmail.com>:
> in sage.groups.additive_abelian.all? I wonder if we should have a
> meta-ticket about cleaning up top-level imports...

+1
But how do we do this ? It is fairly easy to list the names in the
global namespace but how do we select the ones which should stay and
the ones which should not ?

Vincent

Nathann Cohen

unread,
Nov 6, 2013, 4:13:19 PM11/6/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
Helloooooo !

> sage: Z5xZ5 = AdditiveAbelianGroup([5, 5])

Excellent ! Thaaaaaanks ! I can write my patch now ;-)

Nathann

Nathann Cohen

unread,
Nov 7, 2013, 7:49:14 AM11/7/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
Hello everybody !

I just created a ticket [1] that fixes several things in groups.<tab>
and adds this AdditiveAbelianGroup there. In particular, it does not
fix anything realted to the 3 cartesian products that can be used on
IntegerModRing, nor to the fact that it is not considered as a group
at all by Sage. I really don't know how this should be done :-/

Have fuuuuuuuuuuuuuuuun !

Nathann

[1] http://trac.sagemath.org/ticket/15368

Nathann Cohen

unread,
Nov 7, 2013, 8:11:50 AM11/7/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
And I don't know how to fix this either :

sage: G=AdditiveAbelianGroup([5])
sage: G(2)
TypeError: can't initialize vector from nonzero non-list

Nathann

Nathann Cohen

unread,
Nov 7, 2013, 8:32:47 AM11/7/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
> And I don't know how to fix this either :
>
> sage: G=AdditiveAbelianGroup([5])
> sage: G(2)
> TypeError: can't initialize vector from nonzero non-list

Fixed there : http://trac.sagemath.org/ticket/15369

Nathann

Nathann Cohen

unread,
Nov 7, 2013, 8:55:04 AM11/7/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
This, however, is beyond me. And I'm stuck again :-/

sage: G = AdditiveAbelianGroup([7,23]); G
Additive abelian group isomorphic to Z/161
sage: print G[:5]                        
[(0, 0), (3, 10), (6, 20), (2, 7), (5, 17)]
sage: G(0)
(0, 0)
sage: G(1)

TypeError: can't initialize vector from nonzero non-list
sage: G((0,0))
TypeError: length of v must be at most the number of rows of self
sage: G((0,1))
TypeError: length of v must be at most the number of rows of self

Nathann

Hugh Thomas

unread,
Nov 7, 2013, 12:56:13 PM11/7/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX

Hi!

Not obvious to me either, but documented (under AdditiveAbelianGroup)

sage: v=vector((1,1))
sage: G(v)
(1,1)

defines an element as a sum of multiples of the generators.  

cheers,

Hugh

Dima Pasechnik

unread,
Nov 7, 2013, 4:20:38 PM11/7/13
to sage-...@googlegroups.com
On 2013-11-07, Nathann Cohen <nathan...@gmail.com> wrote:
> This, however, is beyond me. And I'm stuck again :-/
>
> sage: G = AdditiveAbelianGroup([7,23]); G
> Additive abelian group isomorphic to Z/161
> sage: print G[:5]
> [(0, 0), (3, 10), (6, 20), (2, 7), (5, 17)]
> sage: G(0)
> (0, 0)
> sage: G(1)
> TypeError: can't initialize vector from nonzero non-list
> sage: G((0,0))
try G(vector(0,0)), etc.
This works...

Volker Braun

unread,
Nov 7, 2013, 5:27:30 PM11/7/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
On Thursday, November 7, 2013 5:55:04 AM UTC-8, Nathann Cohen wrote:
sage: G = AdditiveAbelianGroup([7,23]); G
Additive abelian group isomorphic to Z/161
sage: G(1)

TypeError: can't initialize vector from nonzero non-list

This expects input from Z/161, so a length-one list:

sage: G([160]) + G([1])
(0, 0)

If you insist on thinking of it as Z/7 + Z/23 then use linear combinations of generators:

sage: 7 * G.gen(0)
(0, 0)


Dima Pasechnik

unread,
Nov 7, 2013, 6:11:13 PM11/7/13
to sage-...@googlegroups.com
you can also do
sage: 7*G(vector([1,0]))
(0, 0)

which is perhaps more convenient to manipulate non-interactively, e.g.
you can write G(vector([3,4])) instead of 3*G.gen(0)+4*G.gen(1):

sage: G(vector([3,4]))==3*G.gen(0)+4*G.gen(1)
True

>
>

Nathann Cohen

unread,
Nov 8, 2013, 3:09:24 AM11/8/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
Yooooooo !


> This expects input from Z/161, so a length-one list:
>
> sage: G([160]) + G([1])
> (0, 0)

By the way, why would "G = AdditiveAbelianGroup([7,23])" 
1) expect input from Z/161
2) give its output as pairs 7x23 ?

As I explicitly asked it to be a 7x23 product I'd expect it to only deal with pairs, both as input AND output (that's just elementary consistency, isn't it ?)

Nathann

Nils Bruin

unread,
Nov 8, 2013, 3:58:51 AM11/8/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
On Friday, November 8, 2013 12:09:24 AM UTC-8, Nathann Cohen wrote:
By the way, why would "G = AdditiveAbelianGroup([7,23])" 
1) expect input from Z/161
2) give its output as pairs 7x23 ?

That must be an oversight (and hence a reportable bug). This is just too confusing:

sage: G1=AdditiveAbelianGroup([2,4]); G1
Additive abelian group isomorphic to Z/2 + Z/4
sage: G2=AdditiveAbelianGroup([4,2]); G2
Additive abelian group isomorphic to Z/2 + Z/4
sage: G2([1,0]).order()
2
sage: G2(vector([1,0])).order()
4

It is probably a matter of the implementer forgetting to support "list as input" and then the underlying structure (with internal basis) taking over to interpret the coefficient wrt. the internal basis.

Jean-Pierre Flori

unread,
Nov 8, 2013, 4:01:27 AM11/8/13
to sage-...@googlegroups.com
Just a random thought: Can't you use explicitly a CartesianProduct of AdditiveAbelianGroup if you don't want Sage to be too smart?

Travis Scrimshaw

unread,
Nov 8, 2013, 6:23:40 PM11/8/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
I think it would be better to make these UniqueRepresentations by sorting the list of integer inputs, that way things like

sage: G1 is G2
False
sage: G1 == G2
False

would make sense. Going to point 1, this would allow us to define natural coercions and allow people could use whichever format they wanted.

Best,
Travis

Travis Scrimshaw

unread,
Nov 8, 2013, 6:25:10 PM11/8/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
I think it would be better to make these UniqueRepresentations by sorting the list of integer inputs, that way things like

sage: G1 is G2
False
sage: G1 == G2
False

would make sense.

Sorry, I meant to say these would be True and the output from these comparisons would make sense.

Nils Bruin

unread,
Nov 8, 2013, 6:39:14 PM11/8/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX

Quoting from the documentation of AdditiveAbelianGroup:

    Construct a finitely-generated additive abelian group.

   INPUTS:

   * "invs" (list of integers): the invariants. These should all be
     greater than or equal to zero.

   * "remember_generators" (boolean): whether or not to fix a set of
     generators (corresponding to the given invariants, which need not
     be in Smith form).

I'd agree with you if remember_generators were "false", but it's "true" by default. So G1 and G2 should really be non-equal. It pretty clear "remember_generators" was partially implemented:
 - It does set the generators properly, so that G2.0, G2.1 etc. do the right thing
 - It prints elements represented wrt. the remembered set of generators
 - G2.0.lift() seems to do the right thing
but not fully:
 - the group prints in a funny way (it mentions some isomorphic group, but printing the group that was constructed would make a lot more sense)
 - the element construction from lists uses some internal basis
 - asking "list(G2.0)" gives the list of coefficients wrt. the internal basis (that's at least consistent with the previous one)
 - indexing on an element works wrt. the internal basis:
sage: (G2.0[0],G2.0[1])
(0, 1)
sage: G2.0
(1, 0)

The best thing is probably to just finish the job.

Rob Beezer

unread,
Nov 9, 2013, 1:01:12 AM11/9/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
On Wednesday, November 6, 2013 9:41:28 AM UTC-8, Nathann Cohen wrote:
I screamed for help, Aladin offered his, we tried a few things and
Hell followed.

Dear Nathann, et al,

I've been to hell and back.  The situation is as bad as it sounds.

#9773 builds on William's finitely-generated free-module-over-PID code to implement additive and multiplicative finitely generated groups in a unified and extendable way.  Mostly just a pretty face on top of free modules over ZZ.

The code should be solid.  Patch applies, with one obsolete hunk failing (just ignore it).  Passes the tests that are there.  It needs a big effort to be fully documented and then we'd want to decide if it is a useful replacement for what currently exists.  Mea culpa for not finishing the job.

KDC's group of multiplicative units mod n is a good demonstration of how to extend the abstract classes.  There is a cyclic group (maybe one fairly concrete and one more presentational).  Take it for a spin and see if it solves your original complaint.  Poke around in the (new) fg_abelian directory.

Rob

Nathann Cohen

unread,
Nov 12, 2013, 6:25:46 AM11/12/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert
Hellooooooooooooooooooooooo !!

> I've been to hell and back. The situation is as bad as it sounds.

O_O_O_O_O_O_O;;;;;;

> #9773 builds on William's finitely-generated free-module-over-PID code to
> implement additive and multiplicative finitely generated groups in a unified
> and extendable way. Mostly just a pretty face on top of free modules over
> ZZ.
>
> The code should be solid. Patch applies, with one obsolete hunk failing
> (just ignore it). Passes the tests that are there. It needs a big effort
> to be fully documented and then we'd want to decide if it is a useful
> replacement for what currently exists. Mea culpa for not finishing the job.
>
> KDC's group of multiplicative units mod n is a good demonstration of how to
> extend the abstract classes. There is a cyclic group (maybe one fairly
> concrete and one more presentational). Take it for a spin and see if it
> solves your original complaint. Poke around in the (new) fg_abelian
> directory.

HMmmmmm... Well, Volker more or less made me give up using
AdditiveAbelianGroup for Z/nZ and I now use IntegerModRing in this
case. Which (#15369 just got updated) is now available as
"groups.misc.AdditiveCyclic" for whoever is looking for it.

Nathann Cohen

unread,
Nov 12, 2013, 6:39:17 AM11/12/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert
Oops. This email was send too early. I wanted to add that the doctests I read in your patch make it look a bit like the current AdditiveAbelianGroup and IntegerModRing from outside, aaaaaand that I am not familiar enough with the current code and your patch's code to notice the internal differences... Though definitely the current IntegerModRing could work better with CartesianProduct :-P

Nathann

Nathann Cohen

unread,
Nov 12, 2013, 6:49:43 AM11/12/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert
A status of the "bugs" reported in the first message :

I did not know at first how to create Z/nZ in Sage : #15369 adds groups.misc.AdditiveCyclic which is equal to Integers (or IntegerModRing). So the void is filled, and Rob's implementation can replace it eventually.

- "Integers(5) in Groups" returns False. Not a bug according to Nicolas, because "Groups" implicitly says "Multiplicative Groups", and Integers(5) is not a multiplicative group. I personally think that this is terribly misleading, but well....

- AdditiveAbelianGroup([5]) (which represents Z/5Z) does not accept '2' as one of its elements, though '[2]' is one. Volker says it should not be changed and that accepting '2' as input would be a bad idea. So well, we should use groups.misc.AdditiveCyclic for these groups.

- "G2((3,3))*G2((3,4))" returns "(9, 12)" when G = Z/5Z x Z/5Z. That's because the elements (3,3) and (3,4) are not converted into elements of G during this computation, and Nicolas Thiery knows how to fix that. He told me, I tried 5 times and lost 1 hour, got mad, gave it up. But it can be done. Should be a one-line fix for whoever can find the right function, and I wasn't able to.

- "G.CartesianProduct" and "CartesianProduct" are supposedly the same function, and "should be removed" (Combinat-Style) if I got it right. I don't know when, nor who is suppoed to do it. I can't, I have no understanding of this code, and I try to keep my interactions with Combinat/Categories/Parent-Element code to a minimum.

sage: G2((3,3))+G2((3,3)) raises :
        TypeError: unsupported operand type(s) for +:
'CartesianProduct_with_category.element_class' and
'CartesianProduct_with_category.element_class'

Don't know where this bug comes from, Nicolas thought for a while that it was fixed by #10963, only apparently it isn't. So left to be fixed, too.

My personal problem is solved as I now know what I should use to build my two groups, and I added an alias in groups.<whatever> for whoever will have the same problem in the future.

Thank you for your help !!!

Nathann

Travis Scrimshaw

unread,
Nov 12, 2013, 12:38:48 PM11/12/13
to sage-...@googlegroups.com, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert
- "G.CartesianProduct" and "CartesianProduct" are supposedly the same function, and "should be removed" (Combinat-Style) if I got it right. I don't know when, nor who is suppoed to do it. I can't, I have no understanding of this code, and I try to keep my interactions with Combinat/Categories/Parent-Element code to a minimum.

   As I understand it, we want to move Cartesian products over to the category framework, but we will need #10963 in before we can really think about doing this. Although I'm not quite sure they are of the "should be removed" variety.

Best,
Travis

Nathann Cohen

unread,
Nov 12, 2013, 12:41:17 PM11/12/13
to Sage devel, Nicolas M. Thiery, Travis Scrimshaw, Florent Hivert
>    As I understand it, we want to move Cartesian products over to the
> category framework, but we will need #10963 in before we can really think
> about doing this. Although I'm not quite sure they are of the "should be
> removed" variety.

Oh O_o

Then I must have misunderstood something, sorry !

The point is that this object has a .CartesianProduct() and .cartesian_product() as methods, and that there is a global CartesianProduct function in the global namespace. Regardless of what they do, that is certainly too much :-P

(though having them work properly would be nice too)

Nathann

TB

unread,
Nov 13, 2013, 9:39:42 AM11/13/13
to sage-...@googlegroups.com
If we are in new features mood (which is much easier than actually
implementing them...):
Can we have a class for the *multiplicative* group of integers modulo n?
Currently it is inconvenient to use, and hard to discover, the
appropriate methods of Zmod, like:
- The unit_*() methods
- The multiplicative_*() methods
- and, the descriptively named
list_of_elements_of_multiplicative_group() method.

Currently we have G.multiplicative_generator() but not
G.unit_group_generator(), and G.unit_group_order() but not
G.multiplicative_group_order(). We can have UnitGroup.gens() and
UnitGroup.order(), or any other better name someone may suggest.

Regards,
TB

Nathann Cohen

unread,
Nov 13, 2013, 10:12:08 AM11/13/13
to Sage devel
Hellooooo !


> Can we have a class for the *multiplicative* group of integers modulo n?

There is one in Rob's patch #9773, file units_modm.py. All I know is that if/when we have one it should appear in groups.<something> :-)

Nathann

Nicolas M. Thiery

unread,
Nov 15, 2013, 1:05:20 PM11/15/13
to Nathann Cohen, Sage devel, Travis Scrimshaw, Florent Hivert, Aladin VIRMAUX
On Wed, Nov 06, 2013 at 06:41:28PM +0100, Nathann Cohen wrote:
> ...
> a) G.cartesian_product()
> b) G.CartesianProduct() (yes, it has a .cartesian_product method
> c) The global CartesianProduct function
>
> sage: G2=CartesianProduct(G,G)
> sage: G2((1,1))
> [1, 1]
> sage: G2((1,1))+G2((1,1))
> TypeError: can only concatenate list (not "CombinatorialObject") to list
> sage: G2((1,1))*G2((1,1))
> TypeError: unsupported operand type(s) for *:
> 'CombinatorialObject' and 'CombinatorialObject'

For the record, I created #15425 for this and further issues with
cartesian products.

Cheers,
Nicolas
--
Nicolas M. Thi�ry "Isil" <nth...@users.sf.net>
http://Nicolas.Thiery.name/
Reply all
Reply to author
Forward
0 new messages