`PermutationGroup`

represents a group of permutations.

- Redberry can handle permutation groups with degree in the range of a few thousand, hence working with groups with more than $10^{1000}$ elements.

`PermutationGroup`

can be specified by its generating set:

def gen1 = [[1, 4, 5]].p def gen2 = [[2, 3]].p def group = Group(gen1, gen2) //print all group elements group.each { println it }

> +[] > +[[2, 3]] > +[[1, 5, 4]] > +[[1, 5, 4], [2, 3]] > +[[1, 4, 5]] > +[[1, 4, 5], [2, 3]]

- One can construct a special kinds of
`PermutationGroup`

: symmetric or alternating by using`SymmetricGroup(degree)`

and`AlternatingGroup(degree)`

respectively:

def sym69 = SymmetricGroup(69) println sym69.order()

> 17112245242814131137246833888127283909227054489352036939364804092325 7279754140647424000000000000000

def alt54 = AlternatingGroup(54) println alt54.order()

> 115421848669620690236046371341513790541639282285903970566144000000000000

`PermutationGroup`

provides a number of common methods for working wih permutation groups: membership testing, coset enumeration, searching for centralizers, stabilizers, etc. One can find many examples in below subsections.

Let us consider some common features of `PermutationGroup`

by a particular examples. Consider the following permutation group:

//first generator in cycle notation def perm1 = [[1,28,5,3,13,25,8,4,17,11,29,7,2,21,23,10,6], [9,16,22,30,18,15,20,19,14]].p //second generator in cycle notation def perm2 = [[1, 4, 27], [2, 5, 3]].p //create group def group = Group(perm1, perm2)

- Print group order (i.e. number of all elements):

println group.order()

> 28810681675776000

- Get orbit of some point:

println group.orbit(20)

> [9, 16, 22, 30, 18, 15, 20, 19, 14]

- Get a pointwise stabilizer (i.e. subgroup that fixes specified points)

def pStabilizer = group.pointwiseStabilizer(3, 25, 27) println pStabilizer

> Group( +[[9, 16, 22, 30, 18, 15, 20, 19, 14]], +[[1, 17, 11, 21, 23, 28, 5, 29, 7, 2, 13, 8, 4, 10, 6]], +[[1, 29, 2, 17, 7, 6, 23, 8, 21, 13, 11], [4, 10, 28]])

println pStabilizer.order()

> 5884534656000

- Check membership (i.e. whether some permutation belongs to
`PermutationGroup`

)

def p = [[1, 28, 2, 8, 27, 10, 11], [21, 29, 23]].p println group.membershipTest(p)

> true

def n = [[7, 19, 5, 17, 3, 4, 21, 25]].p println group.membershipTest(n)

> false

- Calculate a setwise stabiliser (i.e. a subgroup that fixes a set as a whole):

def sStabilizer = group.setwiseStabilizer(3, 27, 25) println sStabilizer

> Group( +[[9, 16, 22, 30, 18, 15, 20, 19, 14]], +[[1, 17, 11, 21, 23, 28, 5, 29, 7, 2, 13, 8, 4, 10, 6]], +[[1, 29, 2, 17, 7, 6, 23, 8, 21, 13, 11], [4, 10, 28]], +[[1, 4], [25, 27]], +[[1, 4], [3, 25]] )

println sStabilizer.order()

> 35307207936000

- Calculate derived subgroup (i.e. a commutator subgroup of group with itself):

def dSubgroup = group.derivedSubgroup() println dSubgroup.order()

> 3201186852864000

- Define some other group and check whether it is a subgroup of group:

def oth = Group([[1, 17, 12, 19], [23, 25]].p, [[4, 14, 26]].p) println group.containsSubgroup(oth)

> false

- Calculate union of groups:

def union = group.union(oth) assert union.containsSubgroup(group) assert union.containsSubgroup(oth) println union.order()

> 4420880996869850977271808000000

- Calculate intersection of groups:

def intersection = union.intersection(group) assert intersection == group

- Calculate coset representatives:

println sStabilizer.leftCosetRepresentatives(pStabilizer)

> [+[], +[[1, 4], [25, 27]], +[[1, 4], [3, 25]], +[[3, 25, 27]], +[[3, 27, 25]], +[[1, 4], [3, 27]]]

- Calculate centralizer of subgroup:

println group.centralizerOf(sStabilizer)

> Group( +[[9, 14, 19, 20, 15, 18, 30, 22, 16]] )

The following table lists relevant features of `PermutationGroup`

:

`.center()` |
center of group. |

`.centralizerOf(perm)` |
centralizer of permutation `perm` . |

`.centralizerOf(group)` . |
centralizer of subgroup `group` . |

`.commutator(oth)` |
commutator with `oth` group. |

`.conjugate(perm)` |
conjugation of group with specified permutation `perm` ( i.e. $p^{-1} G p$, where $p$ is `perm` and $G$ is a group). |

`.containsSubgroup(oth)` |
returns whether group contains subgroup `oth` . |

`.degree()` |
natural degree of group, i.e. largest moved point plus one. |

`.derivedSubgroup()` |
derived subgroup, i.e. commutator subgroup of group with itself. |

`. directProduct(oth)` |
direct product of group `oth` group. This product is organized as follows: the initial segment of each permutation is equal to permutation taken from group, while the rest is taken from permutation of `oth` . |

`. equals(oth)` |
returns whether group is equal to `oth` in mathematical sense. |

`.generators()` |
a list of group generators. |

`. base` |
base of group. |

`. getBSGS()` |
low level representation of base and strong generating set. |

`. intersection(oth)` |
intersection of group with `oth` . |

`. isAbelian()` |
returns whether group is abelian. |

`. isAlternating()` |
returns whether group is alternating. |

`. isRegular()` |
returns whether group is regular (i.e. transitive and its order equals to degree). |

`. isSymmetric()` |
returns whether group is symmetric. |

`. isTransitive()` |
returns whether group is transitive. |

`. isTransitive(from, to)` |
returns whether group acts transitively on the the range `from` (inclusive) to `to` (exclusive). |

`. isTrivial()` |
returns whether group is trivial (contains only identity element). |

`. leftCosetRepresentatives(subgroup)` |
array of left coset representatives of a `subgroup` . |

`. leftTransversalOf(subgroup, perm)` |
a unique left coset representative of `perm` . |

`. mapping(from, to)` |
iterator over permutations that maps `from` points on `to` . |

`. membershipTest(perm)` |
returns whether `perm` |

`. normalClosureOf(subgroup)` |
normal closure of specified `subgroup` . |

`. orbit(points)` |
orbit of `points` . |

`.order()` |
group order (i.e. number of all elements). |

`. pointwiseStabilizer(set)` |
pointwise stabilizer of specified `set` of points. |

`. randomElement()` |
uniformly distributed random element from group. |

`. rightCosetRepresentatives(subgroup)` |
array of right coset representatives of a `subgroup` . |

`. setwiseStabilizer(set)` |
pointwise stabilizer of specified `set` of points. |

`. union(oth)` |
union of group and specified group (or set of generators), i.e. group which is generated by union of generators of group and `oth` . |

One can take an orbit of some point using method `.orbit(point)`

:

def perm1 = [[0, 7, 4, 2, 10], [8, 5, 9]].p def perm2 = [[0, 3, 6], [1, 4, 2]].p def group = Group(perm1, perm2) println group.orbit(2)

> [0, 7, 3, 4, 6, 2, 10, 1]

println group.orbit(5)

> [5, 9, 8]In order to take a list of all orbits one can do

def orbits = group.orbits() println orbits

> [[0, 7, 3, 4, 6, 2, 10, 1], [5, 9, 8]]Given a list of all orbits, one can take an orbit of specified point by using array

`positionsInOrbits`

: an `orbits`

:
def poss = group.positionsInOrbits println poss

> [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0]

//orbit of 2 println orbits[poss[2]]

> [0, 7, 3, 4, 6, 2, 10, 1]

//orbit of 5 println orbits[poss[5]]

> [5, 9, 8]

//check for (int i = 0; i < group.degree(); ++i) assert group.orbit(i) == orbits[poss[i]]

The implementation of most `PermutationGroup`

methods relies on base and strong generating set (BSGS). The algorithms such as used in calculation of groups intersections, centralizers etc. uses backtracking techniques.

Consider for example the stabilizers chain of Rubik group:

def rot1 = [[0, 2, 7, 5], [1, 4, 6, 3], [8, 47, 14, 11], [9, 46, 15, 12], [10, 45, 16, 13]].p def rot2 = [[5, 14, 34, 25], [6, 21, 33, 18], [7, 29, 32, 10], [11, 13, 28, 26], [12, 20, 27, 19]].p def rot3 = [[0, 11, 32, 40], [3, 19, 35, 43], [5, 26, 37, 45], [8, 10, 25, 23], [9, 18, 24, 17]].p def rot4 = [[0, 23, 39, 16], [1, 17, 38, 22], [2, 8, 37, 31], [40, 42, 47, 45], [41, 44, 46, 43]].p def rot5 = [[2, 42, 34, 13], [4, 44, 36, 20], [7, 47, 39, 28], [14, 16, 31, 29], [15, 22, 30, 21]].p def rot6 = [[23, 26, 29, 42], [24, 27, 30, 41], [25, 28, 31, 40], [32, 34, 39, 37], [33, 36, 38, 35]].p def RubikGroup = Group(rot1, rot2, rot3, rot4, rot5, rot6) //order of Rubik group println RubikGroup.order()

> 43252003274489856000Get base of group:

//get base of group def base = RubikGroup.base println base

> [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24,4, 30,17,3,1]Let's print order of each stabilizer in stabilizers chain:

//print stabilizers chain for (int i = 0; i < base.length; ++i) { //partial base def pBase = base[0..i] as int[] print('stab of ' + pBase + ' -> ') print(RubikGroup.pointwiseStabilizer(pBase).order()) println '' }

> stab of [0] -> 1802166803103744000 > stab of [0,5] -> 85817466814464000 > stab of [0,5,6] -> 3575727783936000 > stab of [0,5,6,7] -> 198651543552000 > stab of [0,5,6,7,10] -> 198651543552000 > stab of [0,5,6,7,10,11] -> 198651543552000 > stab of [0,5,6,7,10,11,12] -> 198651543552000 > stab of [0,5,6,7,10,11,12,13] -> 198651543552000 > stab of [0,5,6,7,10,11,12,13,14] -> 198651543552000 > stab of [0,5,6,7,10,11,12,13,14,18] -> 9029615616000 > stab of [0,5,6,7,10,11,12,13,14,18,19] -> 9029615616000 > stab of [0,5,6,7,10,11,12,13,14,18,19,20] -> 451480780800 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21] -> 451480780800 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25] -> 30098718720 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26] -> 30098718720 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27] -> 1672151040 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28] -> 139345920 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29] -> 139345920 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32] -> 139345920 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33] -> 139345920 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34] -> 139345920 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2] -> 15482880 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23] -> 2580480 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22] -> 161280 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24] -> 11520 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24,4] -> 960 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24,4,30] -> 96 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24,4,30,17] -> 12 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24,4,30,17,3] -> 2 > stab of [0,5,6,7,10,11,12,13,14,18,19,20,21,25,26,27,28,29,32,33,34,2,23,22,24,4,30,17,3,1] -> 1

The algorithms used in Redberry are described in:

- Derek F. Holt, Bettina Eick, Eamonn A. O'Brien,
*Handbook Of Computational Group Theory*, Chapman and Hall/CRC, 2005

The details on the internal implementation can be found in API.

- Related guides: Permutations and permutation groups
- Related reference material: Permutation
- JavaDocs:
- Overview: Permutations package
`PermutationGroup`

: PermutationGroup- Schreier-Sims and related algorithms: AlgorithmsBase
- Backtracking algorithms: AlgorithmsBacktrack

- Source code:
`PermutationGroup`

: PermutationGroup.java- Schreier-Sims and related algorithms: AlgorithmsBase.java
- Backtracking algorithms: AlgorithmsBacktrack.java