<jupyter_start><jupyter_text>**Important:** to view this notebook properly you will need to execute the cell above, which assumes you have an Internet connection.  It should already be selected, or place your cursor anywhere above to select.  Then press the "Run" button in the menu bar above (the right-pointing arrowhead), or press Shift-Enter on your keyboard. $\newcommand{\identity}{\mathrm{id}}\newcommand{\notdivide}{\nmid}\newcommand{\notsubset}{\not\subset}\newcommand{\lcm}{\operatorname{lcm}}\newcommand{\gf}{\operatorname{GF}}\newcommand{\inn}{\operatorname{Inn}}\newcommand{\aut}{\operatorname{Aut}}\newcommand{\Hom}{\operatorname{Hom}}\newcommand{\cis}{\operatorname{cis}}\newcommand{\chr}{\operatorname{char}}\newcommand{\Null}{\operatorname{Null}}\newcommand{\lt}{<}\newcommand{\gt}{>}\newcommand{\amp}{&}$ Section3.7Sage¶  Many of the groups discussed in this chapter are available for study in Sage.  It is important to understand that sets that form algebraic objects (groups in this chapter) are called “parents” in Sage, and elements of these objects are called, well, “elements.”  So every element belongs to a parent (in other words, is contained in some set).  We can ask about properties of parents (finite? order? abelian?), and we can ask about properties of individual elements (identity? inverse?).  In the following we will show you how to create some of these common groups and begin to explore their properties with Sage. SubsectionIntegers mod n<jupyter_code>Z8 = Integers(8)
Z8
Z8.list()
a = Z8.an_element(); a
a.parent()<jupyter_output><empty_output><jupyter_text>We would like to work with elements of Z8.  If you were to type a 6 into a compute cell right now, what would you mean?  The integer $6\text{,}$ the rational number $\frac{6}{1}\text{,}$ the real number $6.00000\text{,}$ or the complex number $6.00000+0.00000i\text{?}$  Or perhaps you really do want the integer $6$ mod $8\text{?}$  Sage really has no idea what you mean or want.  To make this clear, you can “coerce” 6 into Z8 with the syntax Z8(6).  Without this, Sage will treat a input number like 6 as an integer, the simplest possible interpretation in some sense.  Study the following carefully, where we first work with “normal” integers and then with integers mod 8.<jupyter_code>a = 6
a
a.parent()
b = 7
c = a + b; c
d = Z8(6)
d
d.parent()
e = Z8(7)
f = d+e; f
g = Z8(85); g
f == g<jupyter_output><empty_output><jupyter_text>Z8 is a bit unusual as a first example, since it has two operations defined, both addition and multiplication, with addition forming a group, and multiplication not forming a group.  Still, we can work with the additive portion, here forming the Cayley table for the addition.<jupyter_code>Z8.addition_table(names='elements')<jupyter_output><empty_output><jupyter_text>When $n$ is a prime number, the multipicative structure (excluding zero), will also form a group. The integers mod $n$ are very important, so Sage implements both addition and multiplication together.  Groups of symmetries are a better example of how Sage implements groups, since there is just one operation present.<jupyter_code><jupyter_output><empty_output><jupyter_text>SubsectionGroups of symmetries¶ The symmetries of some geometric shapes are already defined in Sage, albeit with different names.  They are implemented as “permutation groups” which we will begin to study carefully in Chapter 5. Sage uses integers to label vertices, starting the count at 1, instead of letters.  Elements by default are printed using “cycle notation” which we will see described carefully in Chapter 5.    Here is an example, with both the mathematics and Sage.  For the Sage part, we create the group of symmetries and then create the symmetry $\rho_2$ with coercion, followed by outputting the element in cycle notation.  Then we create just the bottom row of the notation we are using for permutations.\begin{equation*}\rho_2=\begin{pmatrix}A & B & C\\C & A & B\end{pmatrix}=\begin{pmatrix}1 & 2 & 3\\3 & 1 & 2\end{pmatrix}\end{equation*}<jupyter_code>triangle = SymmetricGroup(3)
rho2 = triangle([3,1,2])
rho2
[rho2(x) for x in triangle.domain()]<jupyter_output><empty_output><jupyter_text>The final list comprehension deserves comment.  The .domain() method gives a lait of the symbols used for the permutation group triangle and then rho2 is employed with syntax like it is a function (it is a function) to create the images that would occupy the bottom row. With a double list comprehension we can list all six elements of the group in the “bottom row” format.  A good exercise would be to pair up each element with its name as given in Figure 3.6.<jupyter_code>[[a(x) for x in triangle.domain()] for a in triangle]<jupyter_output><empty_output><jupyter_text>Different books, different authors, different software all have different ideas about the order in which to write multiplication of functions.  This textbook builds on the idea of composition of functions, so that $fg$ is the composition $(fg)(x)=f(g(x))$ and it is natural to apply $g$ first.  Sage takes the opposite view and since we write $fg\text{,}$ Sage will understand that we want to do $f$ first.  Neither approach is wrong, and neither is necessarily superior, they are just different and there are good arguments for either one.  When you consult other books that work with permutation groups, you want to first determine which approach it takes. (Be aware that this discussion of Sage function composition is limited to permutations only—“regular” functions in Sage compose in the order you might be familiar with from a calculus course.) The translation here between the text and Sage will be worthwhile practice.  Here we will reprise the discussion at the end of Section 3.1, but reverse the order on each product to compute Sage-style and exactly mirror what the text does.<jupyter_code>mu1 = triangle([1,3,2])
mu2 = triangle([3,2,1])
mu3 = triangle([2,1,3])
rho1 = triangle([2,3,1])
product = rho1*mu1
product == mu2
[product(x) for x in triangle.domain()]
rho1*mu1 == mu1*rho1
mu1*rho1 == mu3<jupyter_output><empty_output><jupyter_text>Now that we understand that Sage does multiplication in reverse, we can compute the Cayley table for this group.  Default behavior is to just name elements of a group as letters, a, b, c, \dots{} in the same order that the .list() command would produce the elements of the group.  But you can also print the elements in the table as themselves (that uses cycle notation here), or you can give the elements names.  We will use u as shorthand for $\mu$ and r as shorthand for $\rho\text{.}$<jupyter_code>triangle.cayley_table()
triangle.cayley_table(names='elements')
triangle.cayley_table(names=['id','u3','r1','r2','u1','u2'])<jupyter_output><empty_output><jupyter_text>You should verify that the table above is correct, just like Table 3.2 is correct.  Remember that the convention is to multiply a row label times a column label, in that order.  However, to do a check across the two tables, you will need to recall the difference in ordering between your textbook and Sage.<jupyter_code><jupyter_output><empty_output><jupyter_text>SubsectionQuaternions Sage implements the quaternions, but the elements are not matrices, but rather are permutations.  Despite appearances the structure is identical.  It should not matter which version you have in mind (matrices or permutations) if you build the Cayley table and use the default behavior of using letters to name the elements.  As permutations, or as letters, can you identify $-1\text{,}$ $I\text{,}$ $J$ and $K\text{?}$<jupyter_code>Q = QuaternionGroup()
[[a(x) for x in Q.domain()] for a in Q]
Q.cayley_table()<jupyter_output><empty_output><jupyter_text>It should be fairly obvious that a is the identity element of the group ($1$), either from its behavior in the table, or from its “bottom row” representation as the first element of the list above.  And if you prefer, you can ask Sage for a list of its outputs when viewed as a function.<jupyter_code>id = Q.identity()
[id(x) for x in Q.domain()]<jupyter_output><empty_output><jupyter_text>Now $-1$ should have the property that $-1\cdot -1= 1\text{.}$  We see that the identity element a is on the diagonal of the Cayley table only when we compute d*d.  We can verify this easily, borrowing the fourth “bottom row” element from the list above.  With this information, once we locate $I\text{,}$ we can easily compute $-I\text{,}$ and so on.<jupyter_code>minus_one = Q([3, 4, 1, 2, 7, 8, 5, 6])
minus_one*minus_one == Q.identity()<jupyter_output><empty_output><jupyter_text>See if you can pair up the letters with all eight elements of the quaternions.  Be a bit careful with your names, the symbol I is used by Sage for the imaginary number $i=\sqrt{-1}$ (which we will use below), but Sage will silently let you redefine it to be anything you like.  Same goes for using lower-case i in Sage.  So call your elements of the quaternions something like QI, QJ, QK to avoid confusion. As we begin to work with groups it is instructive to work with the actual elements.  But many properties of groups are totally independent of the order we use for multiplication, or the names or representations we use for the elements.  Here are facts about the quaternions we can compute without any knowledge of just how the elements are written or multiplied.<jupyter_code>Q.is_finite()
Q.order()
Q.is_abelian()<jupyter_output><empty_output><jupyter_text>SubsectionSubgroups The best techniques for creating subgroups will come in future chapters, but we can create some groups that are naturally subgroups of other groups. Elements of the quaternions were represented by certain permutations of the integers 1 through 8.  We can also build the group of all permutations of these eight integers.  It gets pretty big, so do not list it unless you want a lot of output!  (I dare you.)<jupyter_code>S8 = SymmetricGroup(8)
a = S8.random_element()
[a(x) for x in S8.domain()]     # random
S8.order()<jupyter_output><empty_output><jupyter_text>The quaternions, Q, is a subgroup of the full group of all permutations, the symmetric group $S_8$ or S8, and Sage regards this as a property of Q.<jupyter_code>Q.is_subgroup(S8)<jupyter_output><empty_output><jupyter_text>In Sage the complex numbers are known by the name CC.  We can create a list of the elements in the subgroup described in Example 3.16.  Then we can verify that this set is a subgroup by examining the Cayley table, using multiplication as the operation.<jupyter_code>H = [CC(1), CC(-1), CC(I), CC(-I)]
CC.multiplication_table(elements=H,
                        names=['1', '-1', 'i', '-i'])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08426861204638983, 'fraction_numerical': 0.012813318368873925, 'mean_word_length': 5.051499717034522, 'pattern_counts': {'":': 0, '<': 66, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '424803', 'license': 'Apache-2.0', 'n_tokens_mistral': 3071, 'n_tokens_neox': 2938, 'n_words': 1462, 'path': 'aata/groups-sage.ipynb', 'repo_name': 'johnperry-math/cocalc-examples', 'size': '10692'}