Skip to content

Commit

Permalink
Tests, new utility functions, triviality testing.
Browse files Browse the repository at this point in the history
Started writing tests for the new functions (currently, there are
tests for .center() and .centralizer().

Wrote some new utility functions to help in the test process.

Wrote a method to test whether a permutation group is trivial.
  • Loading branch information
Aleksandar Makelov committed Aug 20, 2012
1 parent dba132c commit 16ca149
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 8 deletions.
32 changes: 32 additions & 0 deletions sympy/combinatorics/perm_groups.py
Expand Up @@ -433,6 +433,7 @@ def __new__(cls, *args, **kw_args):
obj._is_primitive = None
obj._is_nilpotent = None
obj._is_solvable = None
obj._is_trivial = None
obj._transitivity_degree = None
obj._max_div = None
size = len(args[0][0].array_form)
Expand Down Expand Up @@ -752,6 +753,7 @@ def baseswap(self, base, strong_gens, pos, randomized=False,\
if gen not in strong_gens_new:
strong_gens_new.append(gen)
return base_new, strong_gens_new

@property
def basic_orbits(self):
"""
Expand Down Expand Up @@ -929,6 +931,8 @@ def centralizer(self, other):
"""
if hasattr(other, 'generators'):
if other.is_trivial or self.is_trivial:
return self
degree = self.degree
identity = _new_from_array_form(range(degree))
orbits = other.orbits()
Expand Down Expand Up @@ -1806,6 +1810,34 @@ def is_transitive(self):
self._is_transitive = ans
return ans

@property
def is_trivial(self):
"""
Test if the group is the trivial group.
This is true if and only if all the generators are the identity.
Examples
========
>>> from sympy.combinatorics.perm_groups import PermutationGroup
>>> from sympy.combinatorics.permutations import Permutation
>>> id = Permutation(range(5))
>>> G = PermutationGroup([id, id, id])
>>> G.is_trivial
True
"""
if self._is_trivial is None:
gens = self.generators
degree = self.degree
identity = _new_from_array_form(range(degree))
res = [identity for gen in gens] == gens
self._is_trivial = res
return res
else:
return self._is_trivial

def lower_central_series(self):
r"""
Return the lower central series for the group.
Expand Down
2 changes: 1 addition & 1 deletion sympy/combinatorics/tests/test_named_groups.py
Expand Up @@ -7,7 +7,7 @@ def test_SymmetricGroup():
elements = list(G.generate())
assert (G.generators[0]).size == 5
assert len(elements) == 120
assert G.is_solvable() == False
assert G.is_solvable == False
assert G.is_abelian == False
assert G.is_transitive == True
H = SymmetricGroup(1)
Expand Down
58 changes: 51 additions & 7 deletions sympy/combinatorics/tests/test_perm_groups.py
@@ -1,12 +1,13 @@
from sympy.combinatorics.perm_groups import PermutationGroup
from sympy.combinatorics.group_constructs import DirectProduct
from sympy.combinatorics.named_groups import SymmetricGroup, CyclicGroup,\
DihedralGroup, AlternatingGroup
DihedralGroup, AlternatingGroup, AbelianGroup
from sympy.combinatorics.permutations import Permutation, perm_af_muln, cyclic
from sympy.utilities.pytest import raises, skip, XFAIL
from sympy.combinatorics.generators import rubik_cube_generators
import random
from sympy.combinatorics.util import _verify_bsgs
from sympy.combinatorics.util import _verify_bsgs, _naive_list_centralizer,\
_cmp_perm_lists


def test_new():
Expand All @@ -30,18 +31,15 @@ def test_generate():
assert list(g) == [Permutation([0, 1]), Permutation([1, 0])]
g = PermutationGroup([a]).generate(method='dimino')
assert list(g) == [Permutation([0, 1]), Permutation([1, 0])]

a = Permutation([2, 0, 1])
b = Permutation([2, 1, 0])
G = PermutationGroup([a, b])
g = G.generate()
v1 = [p.array_form for p in list(g)]
v1.sort()
assert v1 == [[0,1,2], [0,2,1], [1,0,2], [1,2,0], [2,0,1], [2,1,0]]

v2 = list(G.generate(method='dimino', af=True))
assert v1 == sorted(v2)

a = Permutation([2, 0, 1, 3, 4, 5])
b = Permutation([2, 1, 3, 4, 5, 0])
g = PermutationGroup([a, b]).generate(af=True)
Expand Down Expand Up @@ -77,6 +75,52 @@ def test_stabilizer():
G2 = G.stabilizer(2)
assert G2.order() == 181440

def test_center():
# the center of the dihedral group D_n is of order 2 for even n
for i in (4, 6, 10):
D = DihedralGroup(i)
assert (D.center()).order() == 2
# the center of the dihedral group D_n is of order 1 for odd n>2
for i in (3, 5, 7):
D = DihedralGroup(i)
assert (D.center()).order() == 1
# the center of an abelian group is the group itself
for i in (2, 3, 5):
for j in (1, 5, 7):
for k in (1, 1, 11):
G = AbelianGroup(i, j, k)
assert G.center() == G
# the center of a nonabelian simple group is trivial
for i in(1, 5, 9):
A = AlternatingGroup(i)
assert (A.center()).order() == 1
# brute-force verifications
D = DihedralGroup(5)
A = AlternatingGroup(3)
C = CyclicGroup(4)
G = D*A*C
center_list_naive = _naive_list_centralizer(G, G)
center_list = list((G.center()).generate())
assert _cmp_perm_lists(center_list_naive, center_list)

def test_centralizer():
# the centralizer of the trivial group is the entire group
S = SymmetricGroup(2)
assert S.centralizer(Permutation(range(2))) == S
A = AlternatingGroup(5)
assert A.centralizer(Permutation(range(5))) == A
# a centralizer in the trivial group is the trivial group itself
triv = PermutationGroup([Permutation([0,1,2,3])])
D = DihedralGroup(4)
assert triv.centralizer(D) == triv
# brute-force verifications
S = SymmetricGroup(6)
g = Permutation([2, 3, 4, 5, 0, 1])
centralizer = S.centralizer(g)
centralizer_list = list(centralizer.generate())
centralizer_list_naive = _naive_list_centralizer(S, g)
assert _cmp_perm_lists(centralizer_list, centralizer_list_naive)

def test_coset_repr():
a = Permutation([0, 2, 1])
b = Permutation([1, 0, 2])
Expand Down Expand Up @@ -195,11 +239,11 @@ def test_is_solvable():
a = Permutation([1,2,0])
b = Permutation([1,0,2])
G = PermutationGroup([a, b])
assert G.is_solvable()
assert G.is_solvable
a = Permutation([1,2,3,4,0])
b = Permutation([1,0,2,3,4])
G = PermutationGroup([a, b])
assert not G.is_solvable()
assert not G.is_solvable

def test_rubik1():
gens = rubik_cube_generators()
Expand Down
80 changes: 80 additions & 0 deletions sympy/combinatorics/util.py
Expand Up @@ -106,6 +106,32 @@ def _check_cycles_alt_sym(perm):
return True
return False

def _cmp_perm_lists(first, second):
"""
Compare two lists of permutations as sets.
This is used for testing purposes. Since the array form of a
permutation is currently a list, Permutation is not hashable
and cannot be put into a set.
Examples
========
>>> from sympy.combinatorics.permutations import Permutation
>>> from sympy.combinatorics.util import _cmp_perm_lists
>>> a = Permutation([0, 2, 3, 4, 1])
>>> b = Permutation([1, 2, 0, 4, 3])
>>> c = Permutation([3, 4, 0, 1, 2])
>>> ls1 = [a, b, c]
>>> ls2 = [b, c, a]
>>> _cmp_perm_lists(ls1, ls2)
True
"""
first.sort(key = lambda x: x.array_form)
second.sort(key = lambda x: x.array_form)
return first == second

def _distribute_gens_by_base(base, gens):
"""
Distribute the group elements ``gens`` by membership in basic stabilizers.
Expand Down Expand Up @@ -236,6 +262,43 @@ def _handle_precomputed_bsgs(base, strong_gens, transversals=None,\
basic_orbits[i] = transversals[i].keys()
return transversals, basic_orbits, strong_gens_distr

def _naive_list_centralizer(self, other):
from sympy.combinatorics.perm_groups import PermutationGroup
"""
Return a list of elements for the centralizer of a subgroup/set/element.
This is a brute-force implementation that goes over all elements of the group
and checks for membership in the centralizer. It is used to
test ``.centralizer()`` from ``sympy.combinatorics.perm_groups``.
Examples
========
>>> from sympy.combinatorics.util import _naive_list_centralizer
>>> from sympy.combinatorics.named_groups import DihedralGroup
>>> D = DihedralGroup(4)
>>> _naive_list_centralizer(D, D)
[Permutation([0, 1, 2, 3]), Permutation([2, 3, 0, 1])]
See Also
========
sympy.combinatorics.perm_groups.centralizer
"""
if hasattr(other, 'generators'):
elements = list(self.generate())
gens = other.generators
commutes_with_gens = lambda x: [x*gen for gen in gens] == [gen*x for gen in gens]
centralizer_list = []
for element in elements:
if commutes_with_gens(element):
centralizer_list.append(element)
return centralizer_list
elif hasattr(other, 'getitem'):
return _naive_list_centralizer(self, PermutationGroup(other))
elif hasattr(other, 'array_form'):
return _naive_list_centralizer(self, PermutationGroup([other]))

def _orbits_transversals_from_bsgs(base, strong_gens_distr,\
transversals_only=False):
"""
Expand Down Expand Up @@ -520,3 +583,20 @@ def _verify_bsgs(group, base, gens):
if current_stabilizer.order() != 1:
return False
return True

def _verify_centralizer(group, arg, centr=None):
"""
Verify the centralizer of a group/set/element inside another group.
This is used for testing ``.centralizer()`` from ``sympy.combinatorics.perm_groups``
Examples
========
"""
if centr is None:
centr = group.centralizer(arg)
centr_list = list(centr.generate())
centr_list_naive = _naive_list_centralizer(group, arg)
return _cmp_perm_lists(centr_list, centr_list_naive)

0 comments on commit 16ca149

Please sign in to comment.