add read me
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,825 @@
|
||||
from sympy.combinatorics.fp_groups import FpGroup
|
||||
from sympy.combinatorics.coset_table import (CosetTable,
|
||||
coset_enumeration_r, coset_enumeration_c)
|
||||
from sympy.combinatorics.coset_table import modified_coset_enumeration_r
|
||||
from sympy.combinatorics.free_groups import free_group
|
||||
|
||||
from sympy.testing.pytest import slow
|
||||
|
||||
"""
|
||||
References
|
||||
==========
|
||||
|
||||
[1] Holt, D., Eick, B., O'Brien, E.
|
||||
"Handbook of Computational Group Theory"
|
||||
|
||||
[2] John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson
|
||||
Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490.
|
||||
"Implementation and Analysis of the Todd-Coxeter Algorithm"
|
||||
|
||||
"""
|
||||
|
||||
def test_scan_1():
|
||||
# Example 5.1 from [1]
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y])
|
||||
c = CosetTable(f, [x])
|
||||
|
||||
c.scan_and_fill(0, x)
|
||||
assert c.table == [[0, 0, None, None]]
|
||||
assert c.p == [0]
|
||||
assert c.n == 1
|
||||
assert c.omega == [0]
|
||||
|
||||
c.scan_and_fill(0, x**3)
|
||||
assert c.table == [[0, 0, None, None]]
|
||||
assert c.p == [0]
|
||||
assert c.n == 1
|
||||
assert c.omega == [0]
|
||||
|
||||
c.scan_and_fill(0, y**3)
|
||||
assert c.table == [[0, 0, 1, 2], [None, None, 2, 0], [None, None, 0, 1]]
|
||||
assert c.p == [0, 1, 2]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
c.scan_and_fill(0, x**-1*y**-1*x*y)
|
||||
assert c.table == [[0, 0, 1, 2], [None, None, 2, 0], [2, 2, 0, 1]]
|
||||
assert c.p == [0, 1, 2]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
c.scan_and_fill(1, x**3)
|
||||
assert c.table == [[0, 0, 1, 2], [3, 4, 2, 0], [2, 2, 0, 1], \
|
||||
[4, 1, None, None], [1, 3, None, None]]
|
||||
assert c.p == [0, 1, 2, 3, 4]
|
||||
assert c.n == 5
|
||||
assert c.omega == [0, 1, 2, 3, 4]
|
||||
|
||||
c.scan_and_fill(1, y**3)
|
||||
assert c.table == [[0, 0, 1, 2], [3, 4, 2, 0], [2, 2, 0, 1], \
|
||||
[4, 1, None, None], [1, 3, None, None]]
|
||||
assert c.p == [0, 1, 2, 3, 4]
|
||||
assert c.n == 5
|
||||
assert c.omega == [0, 1, 2, 3, 4]
|
||||
|
||||
c.scan_and_fill(1, x**-1*y**-1*x*y)
|
||||
assert c.table == [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1], \
|
||||
[None, 1, None, None], [1, 3, None, None]]
|
||||
assert c.p == [0, 1, 2, 1, 1]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
# Example 5.2 from [1]
|
||||
f = FpGroup(F, [x**2, y**3, (x*y)**3])
|
||||
c = CosetTable(f, [x*y])
|
||||
|
||||
c.scan_and_fill(0, x*y)
|
||||
assert c.table == [[1, None, None, 1], [None, 0, 0, None]]
|
||||
assert c.p == [0, 1]
|
||||
assert c.n == 2
|
||||
assert c.omega == [0, 1]
|
||||
|
||||
c.scan_and_fill(0, x**2)
|
||||
assert c.table == [[1, 1, None, 1], [0, 0, 0, None]]
|
||||
assert c.p == [0, 1]
|
||||
assert c.n == 2
|
||||
assert c.omega == [0, 1]
|
||||
|
||||
c.scan_and_fill(0, y**3)
|
||||
assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]]
|
||||
assert c.p == [0, 1, 2]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
c.scan_and_fill(0, (x*y)**3)
|
||||
assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]]
|
||||
assert c.p == [0, 1, 2]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
c.scan_and_fill(1, x**2)
|
||||
assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]]
|
||||
assert c.p == [0, 1, 2]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
c.scan_and_fill(1, y**3)
|
||||
assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]]
|
||||
assert c.p == [0, 1, 2]
|
||||
assert c.n == 3
|
||||
assert c.omega == [0, 1, 2]
|
||||
|
||||
c.scan_and_fill(1, (x*y)**3)
|
||||
assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [3, 4, 1, 0], [None, 2, 4, None], [2, None, None, 3]]
|
||||
assert c.p == [0, 1, 2, 3, 4]
|
||||
assert c.n == 5
|
||||
assert c.omega == [0, 1, 2, 3, 4]
|
||||
|
||||
c.scan_and_fill(2, x**2)
|
||||
assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [3, 3, 1, 0], [2, 2, 3, 3], [2, None, None, 3]]
|
||||
assert c.p == [0, 1, 2, 3, 3]
|
||||
assert c.n == 4
|
||||
assert c.omega == [0, 1, 2, 3]
|
||||
|
||||
|
||||
@slow
|
||||
def test_coset_enumeration():
|
||||
# this test function contains the combined tests for the two strategies
|
||||
# i.e. HLT and Felsch strategies.
|
||||
|
||||
# Example 5.1 from [1]
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y])
|
||||
C_r = coset_enumeration_r(f, [x])
|
||||
C_r.compress(); C_r.standardize()
|
||||
C_c = coset_enumeration_c(f, [x])
|
||||
C_c.compress(); C_c.standardize()
|
||||
table1 = [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1]]
|
||||
assert C_r.table == table1
|
||||
assert C_c.table == table1
|
||||
|
||||
# E1 from [2] Pg. 474
|
||||
F, r, s, t = free_group("r, s, t")
|
||||
E1 = FpGroup(F, [t**-1*r*t*r**-2, r**-1*s*r*s**-2, s**-1*t*s*t**-2])
|
||||
C_r = coset_enumeration_r(E1, [])
|
||||
C_r.compress()
|
||||
C_c = coset_enumeration_c(E1, [])
|
||||
C_c.compress()
|
||||
table2 = [[0, 0, 0, 0, 0, 0]]
|
||||
assert C_r.table == table2
|
||||
# test for issue #11449
|
||||
assert C_c.table == table2
|
||||
|
||||
# Cox group from [2] Pg. 474
|
||||
F, a, b = free_group("a, b")
|
||||
Cox = FpGroup(F, [a**6, b**6, (a*b)**2, (a**2*b**2)**2, (a**3*b**3)**5])
|
||||
C_r = coset_enumeration_r(Cox, [a])
|
||||
C_r.compress(); C_r.standardize()
|
||||
C_c = coset_enumeration_c(Cox, [a])
|
||||
C_c.compress(); C_c.standardize()
|
||||
table3 = [[0, 0, 1, 2],
|
||||
[2, 3, 4, 0],
|
||||
[5, 1, 0, 6],
|
||||
[1, 7, 8, 9],
|
||||
[9, 10, 11, 1],
|
||||
[12, 2, 9, 13],
|
||||
[14, 9, 2, 11],
|
||||
[3, 12, 15, 16],
|
||||
[16, 17, 18, 3],
|
||||
[6, 4, 3, 5],
|
||||
[4, 19, 20, 21],
|
||||
[21, 22, 6, 4],
|
||||
[7, 5, 23, 24],
|
||||
[25, 23, 5, 18],
|
||||
[19, 6, 22, 26],
|
||||
[24, 27, 28, 7],
|
||||
[29, 8, 7, 30],
|
||||
[8, 31, 32, 33],
|
||||
[33, 34, 13, 8],
|
||||
[10, 14, 35, 35],
|
||||
[35, 36, 37, 10],
|
||||
[30, 11, 10, 29],
|
||||
[11, 38, 39, 14],
|
||||
[13, 39, 38, 12],
|
||||
[40, 15, 12, 41],
|
||||
[42, 13, 34, 43],
|
||||
[44, 35, 14, 45],
|
||||
[15, 46, 47, 34],
|
||||
[34, 48, 49, 15],
|
||||
[50, 16, 21, 51],
|
||||
[52, 21, 16, 49],
|
||||
[17, 50, 53, 54],
|
||||
[54, 55, 56, 17],
|
||||
[41, 18, 17, 40],
|
||||
[18, 28, 27, 25],
|
||||
[26, 20, 19, 19],
|
||||
[20, 57, 58, 59],
|
||||
[59, 60, 51, 20],
|
||||
[22, 52, 61, 23],
|
||||
[23, 62, 63, 22],
|
||||
[64, 24, 33, 65],
|
||||
[48, 33, 24, 61],
|
||||
[62, 25, 54, 66],
|
||||
[67, 54, 25, 68],
|
||||
[57, 26, 59, 69],
|
||||
[70, 59, 26, 63],
|
||||
[27, 64, 71, 72],
|
||||
[72, 73, 68, 27],
|
||||
[28, 41, 74, 75],
|
||||
[75, 76, 30, 28],
|
||||
[31, 29, 77, 78],
|
||||
[79, 77, 29, 37],
|
||||
[38, 30, 76, 80],
|
||||
[78, 81, 82, 31],
|
||||
[43, 32, 31, 42],
|
||||
[32, 83, 84, 85],
|
||||
[85, 86, 65, 32],
|
||||
[36, 44, 87, 88],
|
||||
[88, 89, 90, 36],
|
||||
[45, 37, 36, 44],
|
||||
[37, 82, 81, 79],
|
||||
[80, 74, 41, 38],
|
||||
[39, 42, 91, 92],
|
||||
[92, 93, 45, 39],
|
||||
[46, 40, 94, 95],
|
||||
[96, 94, 40, 56],
|
||||
[97, 91, 42, 82],
|
||||
[83, 43, 98, 99],
|
||||
[100, 98, 43, 47],
|
||||
[101, 87, 44, 90],
|
||||
[82, 45, 93, 97],
|
||||
[95, 102, 103, 46],
|
||||
[104, 47, 46, 105],
|
||||
[47, 106, 107, 100],
|
||||
[61, 108, 109, 48],
|
||||
[105, 49, 48, 104],
|
||||
[49, 110, 111, 52],
|
||||
[51, 111, 110, 50],
|
||||
[112, 53, 50, 113],
|
||||
[114, 51, 60, 115],
|
||||
[116, 61, 52, 117],
|
||||
[53, 118, 119, 60],
|
||||
[60, 70, 66, 53],
|
||||
[55, 67, 120, 121],
|
||||
[121, 122, 123, 55],
|
||||
[113, 56, 55, 112],
|
||||
[56, 103, 102, 96],
|
||||
[69, 124, 125, 57],
|
||||
[115, 58, 57, 114],
|
||||
[58, 126, 127, 128],
|
||||
[128, 128, 69, 58],
|
||||
[66, 129, 130, 62],
|
||||
[117, 63, 62, 116],
|
||||
[63, 125, 124, 70],
|
||||
[65, 109, 108, 64],
|
||||
[131, 71, 64, 132],
|
||||
[133, 65, 86, 134],
|
||||
[135, 66, 70, 136],
|
||||
[68, 130, 129, 67],
|
||||
[137, 120, 67, 138],
|
||||
[132, 68, 73, 131],
|
||||
[139, 69, 128, 140],
|
||||
[71, 141, 142, 86],
|
||||
[86, 143, 144, 71],
|
||||
[145, 72, 75, 146],
|
||||
[147, 75, 72, 144],
|
||||
[73, 145, 148, 120],
|
||||
[120, 149, 150, 73],
|
||||
[74, 151, 152, 94],
|
||||
[94, 153, 146, 74],
|
||||
[76, 147, 154, 77],
|
||||
[77, 155, 156, 76],
|
||||
[157, 78, 85, 158],
|
||||
[143, 85, 78, 154],
|
||||
[155, 79, 88, 159],
|
||||
[160, 88, 79, 161],
|
||||
[151, 80, 92, 162],
|
||||
[163, 92, 80, 156],
|
||||
[81, 157, 164, 165],
|
||||
[165, 166, 161, 81],
|
||||
[99, 107, 106, 83],
|
||||
[134, 84, 83, 133],
|
||||
[84, 167, 168, 169],
|
||||
[169, 170, 158, 84],
|
||||
[87, 171, 172, 93],
|
||||
[93, 163, 159, 87],
|
||||
[89, 160, 173, 174],
|
||||
[174, 175, 176, 89],
|
||||
[90, 90, 89, 101],
|
||||
[91, 177, 178, 98],
|
||||
[98, 179, 162, 91],
|
||||
[180, 95, 100, 181],
|
||||
[179, 100, 95, 152],
|
||||
[153, 96, 121, 148],
|
||||
[182, 121, 96, 183],
|
||||
[177, 97, 165, 184],
|
||||
[185, 165, 97, 172],
|
||||
[186, 99, 169, 187],
|
||||
[188, 169, 99, 178],
|
||||
[171, 101, 174, 189],
|
||||
[190, 174, 101, 176],
|
||||
[102, 180, 191, 192],
|
||||
[192, 193, 183, 102],
|
||||
[103, 113, 194, 195],
|
||||
[195, 196, 105, 103],
|
||||
[106, 104, 197, 198],
|
||||
[199, 197, 104, 109],
|
||||
[110, 105, 196, 200],
|
||||
[198, 201, 133, 106],
|
||||
[107, 186, 202, 203],
|
||||
[203, 204, 181, 107],
|
||||
[108, 116, 205, 206],
|
||||
[206, 207, 132, 108],
|
||||
[109, 133, 201, 199],
|
||||
[200, 194, 113, 110],
|
||||
[111, 114, 208, 209],
|
||||
[209, 210, 117, 111],
|
||||
[118, 112, 211, 212],
|
||||
[213, 211, 112, 123],
|
||||
[214, 208, 114, 125],
|
||||
[126, 115, 215, 216],
|
||||
[217, 215, 115, 119],
|
||||
[218, 205, 116, 130],
|
||||
[125, 117, 210, 214],
|
||||
[212, 219, 220, 118],
|
||||
[136, 119, 118, 135],
|
||||
[119, 221, 222, 217],
|
||||
[122, 182, 223, 224],
|
||||
[224, 225, 226, 122],
|
||||
[138, 123, 122, 137],
|
||||
[123, 220, 219, 213],
|
||||
[124, 139, 227, 228],
|
||||
[228, 229, 136, 124],
|
||||
[216, 222, 221, 126],
|
||||
[140, 127, 126, 139],
|
||||
[127, 230, 231, 232],
|
||||
[232, 233, 140, 127],
|
||||
[129, 135, 234, 235],
|
||||
[235, 236, 138, 129],
|
||||
[130, 132, 207, 218],
|
||||
[141, 131, 237, 238],
|
||||
[239, 237, 131, 150],
|
||||
[167, 134, 240, 241],
|
||||
[242, 240, 134, 142],
|
||||
[243, 234, 135, 220],
|
||||
[221, 136, 229, 244],
|
||||
[149, 137, 245, 246],
|
||||
[247, 245, 137, 226],
|
||||
[220, 138, 236, 243],
|
||||
[244, 227, 139, 221],
|
||||
[230, 140, 233, 248],
|
||||
[238, 249, 250, 141],
|
||||
[251, 142, 141, 252],
|
||||
[142, 253, 254, 242],
|
||||
[154, 255, 256, 143],
|
||||
[252, 144, 143, 251],
|
||||
[144, 257, 258, 147],
|
||||
[146, 258, 257, 145],
|
||||
[259, 148, 145, 260],
|
||||
[261, 146, 153, 262],
|
||||
[263, 154, 147, 264],
|
||||
[148, 265, 266, 153],
|
||||
[246, 267, 268, 149],
|
||||
[260, 150, 149, 259],
|
||||
[150, 250, 249, 239],
|
||||
[162, 269, 270, 151],
|
||||
[262, 152, 151, 261],
|
||||
[152, 271, 272, 179],
|
||||
[159, 273, 274, 155],
|
||||
[264, 156, 155, 263],
|
||||
[156, 270, 269, 163],
|
||||
[158, 256, 255, 157],
|
||||
[275, 164, 157, 276],
|
||||
[277, 158, 170, 278],
|
||||
[279, 159, 163, 280],
|
||||
[161, 274, 273, 160],
|
||||
[281, 173, 160, 282],
|
||||
[276, 161, 166, 275],
|
||||
[283, 162, 179, 284],
|
||||
[164, 285, 286, 170],
|
||||
[170, 188, 184, 164],
|
||||
[166, 185, 189, 173],
|
||||
[173, 287, 288, 166],
|
||||
[241, 254, 253, 167],
|
||||
[278, 168, 167, 277],
|
||||
[168, 289, 290, 291],
|
||||
[291, 292, 187, 168],
|
||||
[189, 293, 294, 171],
|
||||
[280, 172, 171, 279],
|
||||
[172, 295, 296, 185],
|
||||
[175, 190, 297, 297],
|
||||
[297, 298, 299, 175],
|
||||
[282, 176, 175, 281],
|
||||
[176, 294, 293, 190],
|
||||
[184, 296, 295, 177],
|
||||
[284, 178, 177, 283],
|
||||
[178, 300, 301, 188],
|
||||
[181, 272, 271, 180],
|
||||
[302, 191, 180, 303],
|
||||
[304, 181, 204, 305],
|
||||
[183, 266, 265, 182],
|
||||
[306, 223, 182, 307],
|
||||
[303, 183, 193, 302],
|
||||
[308, 184, 188, 309],
|
||||
[310, 189, 185, 311],
|
||||
[187, 301, 300, 186],
|
||||
[305, 202, 186, 304],
|
||||
[312, 187, 292, 313],
|
||||
[314, 297, 190, 315],
|
||||
[191, 316, 317, 204],
|
||||
[204, 318, 319, 191],
|
||||
[320, 192, 195, 321],
|
||||
[322, 195, 192, 319],
|
||||
[193, 320, 323, 223],
|
||||
[223, 324, 325, 193],
|
||||
[194, 326, 327, 211],
|
||||
[211, 328, 321, 194],
|
||||
[196, 322, 329, 197],
|
||||
[197, 330, 331, 196],
|
||||
[332, 198, 203, 333],
|
||||
[318, 203, 198, 329],
|
||||
[330, 199, 206, 334],
|
||||
[335, 206, 199, 336],
|
||||
[326, 200, 209, 337],
|
||||
[338, 209, 200, 331],
|
||||
[201, 332, 339, 240],
|
||||
[240, 340, 336, 201],
|
||||
[202, 341, 342, 292],
|
||||
[292, 343, 333, 202],
|
||||
[205, 344, 345, 210],
|
||||
[210, 338, 334, 205],
|
||||
[207, 335, 346, 237],
|
||||
[237, 347, 348, 207],
|
||||
[208, 349, 350, 215],
|
||||
[215, 351, 337, 208],
|
||||
[352, 212, 217, 353],
|
||||
[351, 217, 212, 327],
|
||||
[328, 213, 224, 323],
|
||||
[354, 224, 213, 355],
|
||||
[349, 214, 228, 356],
|
||||
[357, 228, 214, 345],
|
||||
[358, 216, 232, 359],
|
||||
[360, 232, 216, 350],
|
||||
[344, 218, 235, 361],
|
||||
[362, 235, 218, 348],
|
||||
[219, 352, 363, 364],
|
||||
[364, 365, 355, 219],
|
||||
[222, 358, 366, 367],
|
||||
[367, 368, 353, 222],
|
||||
[225, 354, 369, 370],
|
||||
[370, 371, 372, 225],
|
||||
[307, 226, 225, 306],
|
||||
[226, 268, 267, 247],
|
||||
[227, 373, 374, 233],
|
||||
[233, 360, 356, 227],
|
||||
[229, 357, 361, 234],
|
||||
[234, 375, 376, 229],
|
||||
[248, 231, 230, 230],
|
||||
[231, 377, 378, 379],
|
||||
[379, 380, 359, 231],
|
||||
[236, 362, 381, 245],
|
||||
[245, 382, 383, 236],
|
||||
[384, 238, 242, 385],
|
||||
[340, 242, 238, 346],
|
||||
[347, 239, 246, 381],
|
||||
[386, 246, 239, 387],
|
||||
[388, 241, 291, 389],
|
||||
[343, 291, 241, 339],
|
||||
[375, 243, 364, 390],
|
||||
[391, 364, 243, 383],
|
||||
[373, 244, 367, 392],
|
||||
[393, 367, 244, 376],
|
||||
[382, 247, 370, 394],
|
||||
[395, 370, 247, 396],
|
||||
[377, 248, 379, 397],
|
||||
[398, 379, 248, 374],
|
||||
[249, 384, 399, 400],
|
||||
[400, 401, 387, 249],
|
||||
[250, 260, 402, 403],
|
||||
[403, 404, 252, 250],
|
||||
[253, 251, 405, 406],
|
||||
[407, 405, 251, 256],
|
||||
[257, 252, 404, 408],
|
||||
[406, 409, 277, 253],
|
||||
[254, 388, 410, 411],
|
||||
[411, 412, 385, 254],
|
||||
[255, 263, 413, 414],
|
||||
[414, 415, 276, 255],
|
||||
[256, 277, 409, 407],
|
||||
[408, 402, 260, 257],
|
||||
[258, 261, 416, 417],
|
||||
[417, 418, 264, 258],
|
||||
[265, 259, 419, 420],
|
||||
[421, 419, 259, 268],
|
||||
[422, 416, 261, 270],
|
||||
[271, 262, 423, 424],
|
||||
[425, 423, 262, 266],
|
||||
[426, 413, 263, 274],
|
||||
[270, 264, 418, 422],
|
||||
[420, 427, 307, 265],
|
||||
[266, 303, 428, 425],
|
||||
[267, 386, 429, 430],
|
||||
[430, 431, 396, 267],
|
||||
[268, 307, 427, 421],
|
||||
[269, 283, 432, 433],
|
||||
[433, 434, 280, 269],
|
||||
[424, 428, 303, 271],
|
||||
[272, 304, 435, 436],
|
||||
[436, 437, 284, 272],
|
||||
[273, 279, 438, 439],
|
||||
[439, 440, 282, 273],
|
||||
[274, 276, 415, 426],
|
||||
[285, 275, 441, 442],
|
||||
[443, 441, 275, 288],
|
||||
[289, 278, 444, 445],
|
||||
[446, 444, 278, 286],
|
||||
[447, 438, 279, 294],
|
||||
[295, 280, 434, 448],
|
||||
[287, 281, 449, 450],
|
||||
[451, 449, 281, 299],
|
||||
[294, 282, 440, 447],
|
||||
[448, 432, 283, 295],
|
||||
[300, 284, 437, 452],
|
||||
[442, 453, 454, 285],
|
||||
[309, 286, 285, 308],
|
||||
[286, 455, 456, 446],
|
||||
[450, 457, 458, 287],
|
||||
[311, 288, 287, 310],
|
||||
[288, 454, 453, 443],
|
||||
[445, 456, 455, 289],
|
||||
[313, 290, 289, 312],
|
||||
[290, 459, 460, 461],
|
||||
[461, 462, 389, 290],
|
||||
[293, 310, 463, 464],
|
||||
[464, 465, 315, 293],
|
||||
[296, 308, 466, 467],
|
||||
[467, 468, 311, 296],
|
||||
[298, 314, 469, 470],
|
||||
[470, 471, 472, 298],
|
||||
[315, 299, 298, 314],
|
||||
[299, 458, 457, 451],
|
||||
[452, 435, 304, 300],
|
||||
[301, 312, 473, 474],
|
||||
[474, 475, 309, 301],
|
||||
[316, 302, 476, 477],
|
||||
[478, 476, 302, 325],
|
||||
[341, 305, 479, 480],
|
||||
[481, 479, 305, 317],
|
||||
[324, 306, 482, 483],
|
||||
[484, 482, 306, 372],
|
||||
[485, 466, 308, 454],
|
||||
[455, 309, 475, 486],
|
||||
[487, 463, 310, 458],
|
||||
[454, 311, 468, 485],
|
||||
[486, 473, 312, 455],
|
||||
[459, 313, 488, 489],
|
||||
[490, 488, 313, 342],
|
||||
[491, 469, 314, 472],
|
||||
[458, 315, 465, 487],
|
||||
[477, 492, 485, 316],
|
||||
[463, 317, 316, 468],
|
||||
[317, 487, 493, 481],
|
||||
[329, 447, 464, 318],
|
||||
[468, 319, 318, 463],
|
||||
[319, 467, 448, 322],
|
||||
[321, 448, 467, 320],
|
||||
[475, 323, 320, 466],
|
||||
[432, 321, 328, 437],
|
||||
[438, 329, 322, 434],
|
||||
[323, 474, 452, 328],
|
||||
[483, 494, 486, 324],
|
||||
[466, 325, 324, 475],
|
||||
[325, 485, 492, 478],
|
||||
[337, 422, 433, 326],
|
||||
[437, 327, 326, 432],
|
||||
[327, 436, 424, 351],
|
||||
[334, 426, 439, 330],
|
||||
[434, 331, 330, 438],
|
||||
[331, 433, 422, 338],
|
||||
[333, 464, 447, 332],
|
||||
[449, 339, 332, 440],
|
||||
[465, 333, 343, 469],
|
||||
[413, 334, 338, 418],
|
||||
[336, 439, 426, 335],
|
||||
[441, 346, 335, 415],
|
||||
[440, 336, 340, 449],
|
||||
[416, 337, 351, 423],
|
||||
[339, 451, 470, 343],
|
||||
[346, 443, 450, 340],
|
||||
[480, 493, 487, 341],
|
||||
[469, 342, 341, 465],
|
||||
[342, 491, 495, 490],
|
||||
[361, 407, 414, 344],
|
||||
[418, 345, 344, 413],
|
||||
[345, 417, 408, 357],
|
||||
[381, 446, 442, 347],
|
||||
[415, 348, 347, 441],
|
||||
[348, 414, 407, 362],
|
||||
[356, 408, 417, 349],
|
||||
[423, 350, 349, 416],
|
||||
[350, 425, 420, 360],
|
||||
[353, 424, 436, 352],
|
||||
[479, 363, 352, 435],
|
||||
[428, 353, 368, 476],
|
||||
[355, 452, 474, 354],
|
||||
[488, 369, 354, 473],
|
||||
[435, 355, 365, 479],
|
||||
[402, 356, 360, 419],
|
||||
[405, 361, 357, 404],
|
||||
[359, 420, 425, 358],
|
||||
[476, 366, 358, 428],
|
||||
[427, 359, 380, 482],
|
||||
[444, 381, 362, 409],
|
||||
[363, 481, 477, 368],
|
||||
[368, 393, 390, 363],
|
||||
[365, 391, 394, 369],
|
||||
[369, 490, 480, 365],
|
||||
[366, 478, 483, 380],
|
||||
[380, 398, 392, 366],
|
||||
[371, 395, 496, 497],
|
||||
[497, 498, 489, 371],
|
||||
[473, 372, 371, 488],
|
||||
[372, 486, 494, 484],
|
||||
[392, 400, 403, 373],
|
||||
[419, 374, 373, 402],
|
||||
[374, 421, 430, 398],
|
||||
[390, 411, 406, 375],
|
||||
[404, 376, 375, 405],
|
||||
[376, 403, 400, 393],
|
||||
[397, 430, 421, 377],
|
||||
[482, 378, 377, 427],
|
||||
[378, 484, 497, 499],
|
||||
[499, 499, 397, 378],
|
||||
[394, 461, 445, 382],
|
||||
[409, 383, 382, 444],
|
||||
[383, 406, 411, 391],
|
||||
[385, 450, 443, 384],
|
||||
[492, 399, 384, 453],
|
||||
[457, 385, 412, 493],
|
||||
[387, 442, 446, 386],
|
||||
[494, 429, 386, 456],
|
||||
[453, 387, 401, 492],
|
||||
[389, 470, 451, 388],
|
||||
[493, 410, 388, 457],
|
||||
[471, 389, 462, 495],
|
||||
[412, 390, 393, 399],
|
||||
[462, 394, 391, 410],
|
||||
[401, 392, 398, 429],
|
||||
[396, 445, 461, 395],
|
||||
[498, 496, 395, 460],
|
||||
[456, 396, 431, 494],
|
||||
[431, 397, 499, 496],
|
||||
[399, 477, 481, 412],
|
||||
[429, 483, 478, 401],
|
||||
[410, 480, 490, 462],
|
||||
[496, 497, 484, 431],
|
||||
[489, 495, 491, 459],
|
||||
[495, 460, 459, 471],
|
||||
[460, 489, 498, 498],
|
||||
[472, 472, 471, 491]]
|
||||
|
||||
assert C_r.table == table3
|
||||
assert C_c.table == table3
|
||||
|
||||
# Group denoted by B2,4 from [2] Pg. 474
|
||||
F, a, b = free_group("a, b")
|
||||
B_2_4 = FpGroup(F, [a**4, b**4, (a*b)**4, (a**-1*b)**4, (a**2*b)**4, \
|
||||
(a*b**2)**4, (a**2*b**2)**4, (a**-1*b*a*b)**4, (a*b**-1*a*b)**4])
|
||||
C_r = coset_enumeration_r(B_2_4, [a])
|
||||
C_c = coset_enumeration_c(B_2_4, [a])
|
||||
index_r = 0
|
||||
for i in range(len(C_r.p)):
|
||||
if C_r.p[i] == i:
|
||||
index_r += 1
|
||||
assert index_r == 1024
|
||||
|
||||
index_c = 0
|
||||
for i in range(len(C_c.p)):
|
||||
if C_c.p[i] == i:
|
||||
index_c += 1
|
||||
assert index_c == 1024
|
||||
|
||||
# trivial Macdonald group G(2,2) from [2] Pg. 480
|
||||
M = FpGroup(F, [b**-1*a**-1*b*a*b**-1*a*b*a**-2, a**-1*b**-1*a*b*a**-1*b*a*b**-2])
|
||||
C_r = coset_enumeration_r(M, [a])
|
||||
C_r.compress(); C_r.standardize()
|
||||
C_c = coset_enumeration_c(M, [a])
|
||||
C_c.compress(); C_c.standardize()
|
||||
table4 = [[0, 0, 0, 0]]
|
||||
assert C_r.table == table4
|
||||
assert C_c.table == table4
|
||||
|
||||
|
||||
def test_look_ahead():
|
||||
# Section 3.2 [Test Example] Example (d) from [2]
|
||||
F, a, b, c = free_group("a, b, c")
|
||||
f = FpGroup(F, [a**11, b**5, c**4, (a*c)**3, b**2*c**-1*b**-1*c, a**4*b**-1*a**-1*b])
|
||||
H = [c, b, c**2]
|
||||
table0 = [[1, 2, 0, 0, 0, 0],
|
||||
[3, 0, 4, 5, 6, 7],
|
||||
[0, 8, 9, 10, 11, 12],
|
||||
[5, 1, 10, 13, 14, 15],
|
||||
[16, 5, 16, 1, 17, 18],
|
||||
[4, 3, 1, 8, 19, 20],
|
||||
[12, 21, 22, 23, 24, 1],
|
||||
[25, 26, 27, 28, 1, 24],
|
||||
[2, 10, 5, 16, 22, 28],
|
||||
[10, 13, 13, 2, 29, 30]]
|
||||
CosetTable.max_stack_size = 10
|
||||
C_c = coset_enumeration_c(f, H)
|
||||
C_c.compress(); C_c.standardize()
|
||||
assert C_c.table[: 10] == table0
|
||||
|
||||
def test_modified_methods():
|
||||
'''
|
||||
Tests for modified coset table methods.
|
||||
Example 5.7 from [1] Holt, D., Eick, B., O'Brien
|
||||
"Handbook of Computational Group Theory".
|
||||
|
||||
'''
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x**3, y**5, (x*y)**2])
|
||||
H = [x*y, x**-1*y**-1*x*y*x]
|
||||
C = CosetTable(f, H)
|
||||
C.modified_define(0, x)
|
||||
identity = C._grp.identity
|
||||
a_0 = C._grp.generators[0]
|
||||
a_1 = C._grp.generators[1]
|
||||
|
||||
assert C.P == [[identity, None, None, None],
|
||||
[None, identity, None, None]]
|
||||
assert C.table == [[1, None, None, None],
|
||||
[None, 0, None, None]]
|
||||
|
||||
C.modified_define(1, x)
|
||||
assert C.table == [[1, None, None, None],
|
||||
[2, 0, None, None],
|
||||
[None, 1, None, None]]
|
||||
assert C.P == [[identity, None, None, None],
|
||||
[identity, identity, None, None],
|
||||
[None, identity, None, None]]
|
||||
|
||||
C.modified_scan(0, x**3, C._grp.identity, fill=False)
|
||||
assert C.P == [[identity, identity, None, None],
|
||||
[identity, identity, None, None],
|
||||
[identity, identity, None, None]]
|
||||
assert C.table == [[1, 2, None, None],
|
||||
[2, 0, None, None],
|
||||
[0, 1, None, None]]
|
||||
|
||||
C.modified_scan(0, x*y, C._grp.generators[0], fill=False)
|
||||
assert C.P == [[identity, identity, None, a_0**-1],
|
||||
[identity, identity, a_0, None],
|
||||
[identity, identity, None, None]]
|
||||
assert C.table == [[1, 2, None, 1],
|
||||
[2, 0, 0, None],
|
||||
[0, 1, None, None]]
|
||||
|
||||
C.modified_define(2, y**-1)
|
||||
assert C.table == [[1, 2, None, 1],
|
||||
[2, 0, 0, None],
|
||||
[0, 1, None, 3],
|
||||
[None, None, 2, None]]
|
||||
assert C.P == [[identity, identity, None, a_0**-1],
|
||||
[identity, identity, a_0, None],
|
||||
[identity, identity, None, identity],
|
||||
[None, None, identity, None]]
|
||||
|
||||
C.modified_scan(0, x**-1*y**-1*x*y*x, C._grp.generators[1])
|
||||
assert C.table == [[1, 2, None, 1],
|
||||
[2, 0, 0, None],
|
||||
[0, 1, None, 3],
|
||||
[3, 3, 2, None]]
|
||||
assert C.P == [[identity, identity, None, a_0**-1],
|
||||
[identity, identity, a_0, None],
|
||||
[identity, identity, None, identity],
|
||||
[a_1, a_1**-1, identity, None]]
|
||||
|
||||
C.modified_scan(2, (x*y)**2, C._grp.identity)
|
||||
assert C.table == [[1, 2, 3, 1],
|
||||
[2, 0, 0, None],
|
||||
[0, 1, None, 3],
|
||||
[3, 3, 2, 0]]
|
||||
assert C.P == [[identity, identity, a_1**-1, a_0**-1],
|
||||
[identity, identity, a_0, None],
|
||||
[identity, identity, None, identity],
|
||||
[a_1, a_1**-1, identity, a_1]]
|
||||
|
||||
C.modified_define(2, y)
|
||||
assert C.table == [[1, 2, 3, 1],
|
||||
[2, 0, 0, None],
|
||||
[0, 1, 4, 3],
|
||||
[3, 3, 2, 0],
|
||||
[None, None, None, 2]]
|
||||
assert C.P == [[identity, identity, a_1**-1, a_0**-1],
|
||||
[identity, identity, a_0, None],
|
||||
[identity, identity, identity, identity],
|
||||
[a_1, a_1**-1, identity, a_1],
|
||||
[None, None, None, identity]]
|
||||
|
||||
C.modified_scan(0, y**5, C._grp.identity)
|
||||
assert C.table == [[1, 2, 3, 1], [2, 0, 0, 4], [0, 1, 4, 3], [3, 3, 2, 0], [None, None, 1, 2]]
|
||||
assert C.P == [[identity, identity, a_1**-1, a_0**-1],
|
||||
[identity, identity, a_0, a_0*a_1**-1],
|
||||
[identity, identity, identity, identity],
|
||||
[a_1, a_1**-1, identity, a_1],
|
||||
[None, None, a_1*a_0**-1, identity]]
|
||||
|
||||
C.modified_scan(1, (x*y)**2, C._grp.identity)
|
||||
assert C.table == [[1, 2, 3, 1],
|
||||
[2, 0, 0, 4],
|
||||
[0, 1, 4, 3],
|
||||
[3, 3, 2, 0],
|
||||
[4, 4, 1, 2]]
|
||||
assert C.P == [[identity, identity, a_1**-1, a_0**-1],
|
||||
[identity, identity, a_0, a_0*a_1**-1],
|
||||
[identity, identity, identity, identity],
|
||||
[a_1, a_1**-1, identity, a_1],
|
||||
[a_0*a_1**-1, a_1*a_0**-1, a_1*a_0**-1, identity]]
|
||||
|
||||
# Modified coset enumeration test
|
||||
f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y])
|
||||
C = coset_enumeration_r(f, [x])
|
||||
C_m = modified_coset_enumeration_r(f, [x])
|
||||
assert C_m.table == C.table
|
||||
@@ -0,0 +1,257 @@
|
||||
from sympy.core.singleton import S
|
||||
from sympy.combinatorics.fp_groups import (FpGroup, low_index_subgroups,
|
||||
reidemeister_presentation, FpSubgroup,
|
||||
simplify_presentation)
|
||||
from sympy.combinatorics.free_groups import (free_group, FreeGroup)
|
||||
|
||||
from sympy.testing.pytest import slow
|
||||
|
||||
"""
|
||||
References
|
||||
==========
|
||||
|
||||
[1] Holt, D., Eick, B., O'Brien, E.
|
||||
"Handbook of Computational Group Theory"
|
||||
|
||||
[2] John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson
|
||||
Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490.
|
||||
"Implementation and Analysis of the Todd-Coxeter Algorithm"
|
||||
|
||||
[3] PROC. SECOND INTERNAT. CONF. THEORY OF GROUPS, CANBERRA 1973,
|
||||
pp. 347-356. "A Reidemeister-Schreier program" by George Havas.
|
||||
http://staff.itee.uq.edu.au/havas/1973cdhw.pdf
|
||||
|
||||
"""
|
||||
|
||||
def test_low_index_subgroups():
|
||||
F, x, y = free_group("x, y")
|
||||
|
||||
# Example 5.10 from [1] Pg. 194
|
||||
f = FpGroup(F, [x**2, y**3, (x*y)**4])
|
||||
L = low_index_subgroups(f, 4)
|
||||
t1 = [[[0, 0, 0, 0]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 3, 3]],
|
||||
[[0, 0, 1, 2], [2, 2, 2, 0], [1, 1, 0, 1]],
|
||||
[[1, 1, 0, 0], [0, 0, 1, 1]]]
|
||||
for i in range(len(t1)):
|
||||
assert L[i].table == t1[i]
|
||||
|
||||
f = FpGroup(F, [x**2, y**3, (x*y)**7])
|
||||
L = low_index_subgroups(f, 15)
|
||||
t2 = [[[0, 0, 0, 0]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5],
|
||||
[4, 4, 5, 3], [6, 6, 3, 4], [5, 5, 6, 6]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5],
|
||||
[6, 6, 5, 3], [5, 5, 3, 4], [4, 4, 6, 6]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5],
|
||||
[6, 6, 5, 3], [7, 7, 3, 4], [4, 4, 8, 9], [5, 5, 10, 11],
|
||||
[11, 11, 9, 6], [9, 9, 6, 8], [12, 12, 11, 7], [8, 8, 7, 10],
|
||||
[10, 10, 13, 14], [14, 14, 14, 12], [13, 13, 12, 13]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5],
|
||||
[6, 6, 5, 3], [7, 7, 3, 4], [4, 4, 8, 9], [5, 5, 10, 11],
|
||||
[11, 11, 9, 6], [12, 12, 6, 8], [10, 10, 11, 7], [8, 8, 7, 10],
|
||||
[9, 9, 13, 14], [14, 14, 14, 12], [13, 13, 12, 13]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5],
|
||||
[6, 6, 5, 3], [7, 7, 3, 4], [4, 4, 8, 9], [5, 5, 10, 11],
|
||||
[11, 11, 9, 6], [12, 12, 6, 8], [13, 13, 11, 7], [8, 8, 7, 10],
|
||||
[9, 9, 12, 12], [10, 10, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 3, 3], [2, 2, 5, 6]
|
||||
, [7, 7, 6, 4], [8, 8, 4, 5], [5, 5, 8, 9], [6, 6, 9, 7],
|
||||
[10, 10, 7, 8], [9, 9, 11, 12], [11, 11, 12, 10], [13, 13, 10, 11],
|
||||
[12, 12, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 3, 3], [2, 2, 5, 6]
|
||||
, [7, 7, 6, 4], [8, 8, 4, 5], [5, 5, 8, 9], [6, 6, 9, 7],
|
||||
[10, 10, 7, 8], [9, 9, 11, 12], [13, 13, 12, 10], [12, 12, 10, 11],
|
||||
[11, 11, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 4, 4]
|
||||
, [7, 7, 6, 3], [8, 8, 3, 5], [5, 5, 8, 9], [6, 6, 9, 7],
|
||||
[10, 10, 7, 8], [9, 9, 11, 12], [13, 13, 12, 10], [12, 12, 10, 11],
|
||||
[11, 11, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [5, 5, 6, 3], [9, 9, 3, 5], [10, 10, 8, 4], [8, 8, 4, 7],
|
||||
[6, 6, 10, 11], [7, 7, 11, 9], [12, 12, 9, 10], [11, 11, 13, 14],
|
||||
[14, 14, 14, 12], [13, 13, 12, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [6, 6, 6, 3], [5, 5, 3, 5], [8, 8, 8, 4], [7, 7, 4, 7]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [9, 9, 6, 3], [6, 6, 3, 5], [10, 10, 8, 4], [11, 11, 4, 7],
|
||||
[5, 5, 10, 12], [7, 7, 12, 9], [8, 8, 11, 11], [13, 13, 9, 10],
|
||||
[12, 12, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [9, 9, 6, 3], [6, 6, 3, 5], [10, 10, 8, 4], [11, 11, 4, 7],
|
||||
[5, 5, 12, 11], [7, 7, 10, 10], [8, 8, 9, 12], [13, 13, 11, 9],
|
||||
[12, 12, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [9, 9, 6, 3], [10, 10, 3, 5], [7, 7, 8, 4], [11, 11, 4, 7],
|
||||
[5, 5, 9, 9], [6, 6, 11, 12], [8, 8, 12, 10], [13, 13, 10, 11],
|
||||
[12, 12, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [9, 9, 6, 3], [10, 10, 3, 5], [7, 7, 8, 4], [11, 11, 4, 7],
|
||||
[5, 5, 12, 11], [6, 6, 10, 10], [8, 8, 9, 12], [13, 13, 11, 9],
|
||||
[12, 12, 13, 13]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8]
|
||||
, [9, 9, 6, 3], [10, 10, 3, 5], [11, 11, 8, 4], [12, 12, 4, 7],
|
||||
[5, 5, 9, 9], [6, 6, 12, 13], [7, 7, 11, 11], [8, 8, 13, 10],
|
||||
[13, 13, 10, 12]],
|
||||
[[1, 1, 0, 0], [0, 0, 2, 3], [4, 4, 3, 1], [5, 5, 1, 2], [2, 2, 4, 4]
|
||||
, [3, 3, 6, 7], [7, 7, 7, 5], [6, 6, 5, 6]]]
|
||||
for i in range(len(t2)):
|
||||
assert L[i].table == t2[i]
|
||||
|
||||
f = FpGroup(F, [x**2, y**3, (x*y)**7])
|
||||
L = low_index_subgroups(f, 10, [x])
|
||||
t3 = [[[0, 0, 0, 0]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [4, 4, 5, 3],
|
||||
[6, 6, 3, 4], [5, 5, 6, 6]],
|
||||
[[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [6, 6, 5, 3],
|
||||
[5, 5, 3, 4], [4, 4, 6, 6]],
|
||||
[[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8],
|
||||
[6, 6, 6, 3], [5, 5, 3, 5], [8, 8, 8, 4], [7, 7, 4, 7]]]
|
||||
for i in range(len(t3)):
|
||||
assert L[i].table == t3[i]
|
||||
|
||||
|
||||
def test_subgroup_presentations():
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x**3, y**5, (x*y)**2])
|
||||
H = [x*y, x**-1*y**-1*x*y*x]
|
||||
p1 = reidemeister_presentation(f, H)
|
||||
assert str(p1) == "((y_1, y_2), (y_1**2, y_2**3, y_2*y_1*y_2*y_1*y_2*y_1))"
|
||||
|
||||
H = f.subgroup(H)
|
||||
assert (H.generators, H.relators) == p1
|
||||
|
||||
f = FpGroup(F, [x**3, y**3, (x*y)**3])
|
||||
H = [x*y, x*y**-1]
|
||||
p2 = reidemeister_presentation(f, H)
|
||||
assert str(p2) == "((x_0, y_0), (x_0**3, y_0**3, x_0*y_0*x_0*y_0*x_0*y_0))"
|
||||
|
||||
f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3])
|
||||
H = [x]
|
||||
p3 = reidemeister_presentation(f, H)
|
||||
assert str(p3) == "((x_0,), (x_0**4,))"
|
||||
|
||||
f = FpGroup(F, [x**3*y**-3, (x*y)**3, (x*y**-1)**2])
|
||||
H = [x]
|
||||
p4 = reidemeister_presentation(f, H)
|
||||
assert str(p4) == "((x_0,), (x_0**6,))"
|
||||
|
||||
# this presentation can be improved, the most simplified form
|
||||
# of presentation is <a, b | a^11, b^2, (a*b)^3, (a^4*b*a^-5*b)^2>
|
||||
# See [2] Pg 474 group PSL_2(11)
|
||||
# This is the group PSL_2(11)
|
||||
F, a, b, c = free_group("a, b, c")
|
||||
f = FpGroup(F, [a**11, b**5, c**4, (b*c**2)**2, (a*b*c)**3, (a**4*c**2)**3, b**2*c**-1*b**-1*c, a**4*b**-1*a**-1*b])
|
||||
H = [a, b, c**2]
|
||||
gens, rels = reidemeister_presentation(f, H)
|
||||
assert str(gens) == "(b_1, c_3)"
|
||||
assert len(rels) == 18
|
||||
|
||||
|
||||
@slow
|
||||
def test_order():
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x**4, y**2, x*y*x**-1*y])
|
||||
assert f.order() == 8
|
||||
|
||||
f = FpGroup(F, [x*y*x**-1*y**-1, y**2])
|
||||
assert f.order() is S.Infinity
|
||||
|
||||
F, a, b, c = free_group("a, b, c")
|
||||
f = FpGroup(F, [a**250, b**2, c*b*c**-1*b, c**4, c**-1*a**-1*c*a, a**-1*b**-1*a*b])
|
||||
assert f.order() == 2000
|
||||
|
||||
F, x = free_group("x")
|
||||
f = FpGroup(F, [])
|
||||
assert f.order() is S.Infinity
|
||||
|
||||
f = FpGroup(free_group('')[0], [])
|
||||
assert f.order() == 1
|
||||
|
||||
def test_fp_subgroup():
|
||||
def _test_subgroup(K, T, S):
|
||||
_gens = T(K.generators)
|
||||
assert all(elem in S for elem in _gens)
|
||||
assert T.is_injective()
|
||||
assert T.image().order() == S.order()
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x**4, y**2, x*y*x**-1*y])
|
||||
S = FpSubgroup(f, [x*y])
|
||||
assert (x*y)**-3 in S
|
||||
K, T = f.subgroup([x*y], homomorphism=True)
|
||||
assert T(K.generators) == [y*x**-1]
|
||||
_test_subgroup(K, T, S)
|
||||
|
||||
S = FpSubgroup(f, [x**-1*y*x])
|
||||
assert x**-1*y**4*x in S
|
||||
assert x**-1*y**4*x**2 not in S
|
||||
K, T = f.subgroup([x**-1*y*x], homomorphism=True)
|
||||
assert T(K.generators[0]**3) == y**3
|
||||
_test_subgroup(K, T, S)
|
||||
|
||||
f = FpGroup(F, [x**3, y**5, (x*y)**2])
|
||||
H = [x*y, x**-1*y**-1*x*y*x]
|
||||
K, T = f.subgroup(H, homomorphism=True)
|
||||
S = FpSubgroup(f, H)
|
||||
_test_subgroup(K, T, S)
|
||||
|
||||
def test_permutation_methods():
|
||||
F, x, y = free_group("x, y")
|
||||
# DihedralGroup(8)
|
||||
G = FpGroup(F, [x**2, y**8, x*y*x**-1*y])
|
||||
T = G._to_perm_group()[1]
|
||||
assert T.is_isomorphism()
|
||||
assert G.center() == [y**4]
|
||||
|
||||
# DiheadralGroup(4)
|
||||
G = FpGroup(F, [x**2, y**4, x*y*x**-1*y])
|
||||
S = FpSubgroup(G, G.normal_closure([x]))
|
||||
assert x in S
|
||||
assert y**-1*x*y in S
|
||||
|
||||
# Z_5xZ_4
|
||||
G = FpGroup(F, [x*y*x**-1*y**-1, y**5, x**4])
|
||||
assert G.is_abelian
|
||||
assert G.is_solvable
|
||||
|
||||
# AlternatingGroup(5)
|
||||
G = FpGroup(F, [x**3, y**2, (x*y)**5])
|
||||
assert not G.is_solvable
|
||||
|
||||
# AlternatingGroup(4)
|
||||
G = FpGroup(F, [x**3, y**2, (x*y)**3])
|
||||
assert len(G.derived_series()) == 3
|
||||
S = FpSubgroup(G, G.derived_subgroup())
|
||||
assert S.order() == 4
|
||||
|
||||
|
||||
def test_simplify_presentation():
|
||||
# ref #16083
|
||||
G = simplify_presentation(FpGroup(FreeGroup([]), []))
|
||||
assert not G.generators
|
||||
assert not G.relators
|
||||
|
||||
# CyclicGroup(3)
|
||||
# The second generator in <x, y | x^2, x^5, y^3> is trivial due to relators {x^2, x^5}
|
||||
F, x, y = free_group("x, y")
|
||||
G = simplify_presentation(FpGroup(F, [x**2, x**5, y**3]))
|
||||
assert x in G.relators
|
||||
|
||||
def test_cyclic():
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x*y, x**-1*y**-1*x*y*x])
|
||||
assert f.is_cyclic
|
||||
f = FpGroup(F, [x*y, x*y**-1])
|
||||
assert f.is_cyclic
|
||||
f = FpGroup(F, [x**4, y**2, x*y*x**-1*y])
|
||||
assert not f.is_cyclic
|
||||
|
||||
|
||||
def test_abelian_invariants():
|
||||
F, x, y = free_group("x, y")
|
||||
f = FpGroup(F, [x*y, x**-1*y**-1*x*y*x])
|
||||
assert f.abelian_invariants() == []
|
||||
f = FpGroup(F, [x*y, x*y**-1])
|
||||
assert f.abelian_invariants() == [2]
|
||||
f = FpGroup(F, [x**4, y**2, x*y*x**-1*y])
|
||||
assert f.abelian_invariants() == [2, 4]
|
||||
@@ -0,0 +1,226 @@
|
||||
from sympy.combinatorics.free_groups import free_group, FreeGroup
|
||||
from sympy.core import Symbol
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.numbers import oo
|
||||
|
||||
F, x, y, z = free_group("x, y, z")
|
||||
|
||||
|
||||
def test_FreeGroup__init__():
|
||||
x, y, z = map(Symbol, "xyz")
|
||||
|
||||
assert len(FreeGroup("x, y, z").generators) == 3
|
||||
assert len(FreeGroup(x).generators) == 1
|
||||
assert len(FreeGroup(("x", "y", "z"))) == 3
|
||||
assert len(FreeGroup((x, y, z)).generators) == 3
|
||||
|
||||
|
||||
def test_FreeGroup__getnewargs__():
|
||||
x, y, z = map(Symbol, "xyz")
|
||||
assert FreeGroup("x, y, z").__getnewargs__() == ((x, y, z),)
|
||||
|
||||
|
||||
def test_free_group():
|
||||
G, a, b, c = free_group("a, b, c")
|
||||
assert F.generators == (x, y, z)
|
||||
assert x*z**2 in F
|
||||
assert x in F
|
||||
assert y*z**-1 in F
|
||||
assert (y*z)**0 in F
|
||||
assert a not in F
|
||||
assert a**0 not in F
|
||||
assert len(F) == 3
|
||||
assert str(F) == '<free group on the generators (x, y, z)>'
|
||||
assert not F == G
|
||||
assert F.order() is oo
|
||||
assert F.is_abelian == False
|
||||
assert F.center() == {F.identity}
|
||||
|
||||
(e,) = free_group("")
|
||||
assert e.order() == 1
|
||||
assert e.generators == ()
|
||||
assert e.elements == {e.identity}
|
||||
assert e.is_abelian == True
|
||||
|
||||
|
||||
def test_FreeGroup__hash__():
|
||||
assert hash(F)
|
||||
|
||||
|
||||
def test_FreeGroup__eq__():
|
||||
assert free_group("x, y, z")[0] == free_group("x, y, z")[0]
|
||||
assert free_group("x, y, z")[0] is free_group("x, y, z")[0]
|
||||
|
||||
assert free_group("x, y, z")[0] != free_group("a, x, y")[0]
|
||||
assert free_group("x, y, z")[0] is not free_group("a, x, y")[0]
|
||||
|
||||
assert free_group("x, y")[0] != free_group("x, y, z")[0]
|
||||
assert free_group("x, y")[0] is not free_group("x, y, z")[0]
|
||||
|
||||
assert free_group("x, y, z")[0] != free_group("x, y")[0]
|
||||
assert free_group("x, y, z")[0] is not free_group("x, y")[0]
|
||||
|
||||
|
||||
def test_FreeGroup__getitem__():
|
||||
assert F[0:] == FreeGroup("x, y, z")
|
||||
assert F[1:] == FreeGroup("y, z")
|
||||
assert F[2:] == FreeGroup("z")
|
||||
|
||||
|
||||
def test_FreeGroupElm__hash__():
|
||||
assert hash(x*y*z)
|
||||
|
||||
|
||||
def test_FreeGroupElm_copy():
|
||||
f = x*y*z**3
|
||||
g = f.copy()
|
||||
h = x*y*z**7
|
||||
|
||||
assert f == g
|
||||
assert f != h
|
||||
|
||||
|
||||
def test_FreeGroupElm_inverse():
|
||||
assert x.inverse() == x**-1
|
||||
assert (x*y).inverse() == y**-1*x**-1
|
||||
assert (y*x*y**-1).inverse() == y*x**-1*y**-1
|
||||
assert (y**2*x**-1).inverse() == x*y**-2
|
||||
|
||||
|
||||
def test_FreeGroupElm_type_error():
|
||||
raises(TypeError, lambda: 2/x)
|
||||
raises(TypeError, lambda: x**2 + y**2)
|
||||
raises(TypeError, lambda: x/2)
|
||||
|
||||
|
||||
def test_FreeGroupElm_methods():
|
||||
assert (x**0).order() == 1
|
||||
assert (y**2).order() is oo
|
||||
assert (x**-1*y).commutator(x) == y**-1*x**-1*y*x
|
||||
assert len(x**2*y**-1) == 3
|
||||
assert len(x**-1*y**3*z) == 5
|
||||
|
||||
|
||||
def test_FreeGroupElm_eliminate_word():
|
||||
w = x**5*y*x**2*y**-4*x
|
||||
assert w.eliminate_word( x, x**2 ) == x**10*y*x**4*y**-4*x**2
|
||||
w3 = x**2*y**3*x**-1*y
|
||||
assert w3.eliminate_word(x, x**2) == x**4*y**3*x**-2*y
|
||||
assert w3.eliminate_word(x, y) == y**5
|
||||
assert w3.eliminate_word(x, y**4) == y**8
|
||||
assert w3.eliminate_word(y, x**-1) == x**-3
|
||||
assert w3.eliminate_word(x, y*z) == y*z*y*z*y**3*z**-1
|
||||
assert (y**-3).eliminate_word(y, x**-1*z**-1) == z*x*z*x*z*x
|
||||
#assert w3.eliminate_word(x, y*x) == y*x*y*x**2*y*x*y*x*y*x*z**3
|
||||
#assert w3.eliminate_word(x, x*y) == x*y*x**2*y*x*y*x*y*x*y*z**3
|
||||
|
||||
|
||||
def test_FreeGroupElm_array_form():
|
||||
assert (x*z).array_form == ((Symbol('x'), 1), (Symbol('z'), 1))
|
||||
assert (x**2*z*y*x**-2).array_form == \
|
||||
((Symbol('x'), 2), (Symbol('z'), 1), (Symbol('y'), 1), (Symbol('x'), -2))
|
||||
assert (x**-2*y**-1).array_form == ((Symbol('x'), -2), (Symbol('y'), -1))
|
||||
|
||||
|
||||
def test_FreeGroupElm_letter_form():
|
||||
assert (x**3).letter_form == (Symbol('x'), Symbol('x'), Symbol('x'))
|
||||
assert (x**2*z**-2*x).letter_form == \
|
||||
(Symbol('x'), Symbol('x'), -Symbol('z'), -Symbol('z'), Symbol('x'))
|
||||
|
||||
|
||||
def test_FreeGroupElm_ext_rep():
|
||||
assert (x**2*z**-2*x).ext_rep == \
|
||||
(Symbol('x'), 2, Symbol('z'), -2, Symbol('x'), 1)
|
||||
assert (x**-2*y**-1).ext_rep == (Symbol('x'), -2, Symbol('y'), -1)
|
||||
assert (x*z).ext_rep == (Symbol('x'), 1, Symbol('z'), 1)
|
||||
|
||||
|
||||
def test_FreeGroupElm__mul__pow__():
|
||||
x1 = x.group.dtype(((Symbol('x'), 1),))
|
||||
assert x**2 == x1*x
|
||||
|
||||
assert (x**2*y*x**-2)**4 == x**2*y**4*x**-2
|
||||
assert (x**2)**2 == x**4
|
||||
assert (x**-1)**-1 == x
|
||||
assert (x**-1)**0 == F.identity
|
||||
assert (y**2)**-2 == y**-4
|
||||
|
||||
assert x**2*x**-1 == x
|
||||
assert x**2*y**2*y**-1 == x**2*y
|
||||
assert x*x**-1 == F.identity
|
||||
|
||||
assert x/x == F.identity
|
||||
assert x/x**2 == x**-1
|
||||
assert (x**2*y)/(x**2*y**-1) == x**2*y**2*x**-2
|
||||
assert (x**2*y)/(y**-1*x**2) == x**2*y*x**-2*y
|
||||
|
||||
assert x*(x**-1*y*z*y**-1) == y*z*y**-1
|
||||
assert x**2*(x**-2*y**-1*z**2*y) == y**-1*z**2*y
|
||||
|
||||
a = F.identity
|
||||
for n in range(10):
|
||||
assert a == x**n
|
||||
assert a**-1 == x**-n
|
||||
a *= x
|
||||
|
||||
|
||||
def test_FreeGroupElm__len__():
|
||||
assert len(x**5*y*x**2*y**-4*x) == 13
|
||||
assert len(x**17) == 17
|
||||
assert len(y**0) == 0
|
||||
|
||||
|
||||
def test_FreeGroupElm_comparison():
|
||||
assert not (x*y == y*x)
|
||||
assert x**0 == y**0
|
||||
|
||||
assert x**2 < y**3
|
||||
assert not x**3 < y**2
|
||||
assert x*y < x**2*y
|
||||
assert x**2*y**2 < y**4
|
||||
assert not y**4 < y**-4
|
||||
assert not y**4 < x**-4
|
||||
assert y**-2 < y**2
|
||||
|
||||
assert x**2 <= y**2
|
||||
assert x**2 <= x**2
|
||||
|
||||
assert not y*z > z*y
|
||||
assert x > x**-1
|
||||
|
||||
assert not x**2 >= y**2
|
||||
|
||||
|
||||
def test_FreeGroupElm_syllables():
|
||||
w = x**5*y*x**2*y**-4*x
|
||||
assert w.number_syllables() == 5
|
||||
assert w.exponent_syllable(2) == 2
|
||||
assert w.generator_syllable(3) == Symbol('y')
|
||||
assert w.sub_syllables(1, 2) == y
|
||||
assert w.sub_syllables(3, 3) == F.identity
|
||||
|
||||
|
||||
def test_FreeGroup_exponents():
|
||||
w1 = x**2*y**3
|
||||
assert w1.exponent_sum(x) == 2
|
||||
assert w1.exponent_sum(x**-1) == -2
|
||||
assert w1.generator_count(x) == 2
|
||||
|
||||
w2 = x**2*y**4*x**-3
|
||||
assert w2.exponent_sum(x) == -1
|
||||
assert w2.generator_count(x) == 5
|
||||
|
||||
|
||||
def test_FreeGroup_generators():
|
||||
assert (x**2*y**4*z**-1).contains_generators() == {x, y, z}
|
||||
assert (x**-1*y**3).contains_generators() == {x, y}
|
||||
|
||||
|
||||
def test_FreeGroupElm_words():
|
||||
w = x**5*y*x**2*y**-4*x
|
||||
assert w.subword(2, 6) == x**3*y
|
||||
assert w.subword(3, 2) == F.identity
|
||||
assert w.subword(6, 10) == x**2*y**-2
|
||||
|
||||
assert w.substituted_word(0, 7, y**-1) == y**-1*x*y**-4*x
|
||||
assert w.substituted_word(0, 7, y**2*x) == y**2*x**2*y**-4*x
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Test groups defined by the galois module. """
|
||||
|
||||
from sympy.combinatorics.galois import (
|
||||
S4TransitiveSubgroups, S5TransitiveSubgroups, S6TransitiveSubgroups,
|
||||
find_transitive_subgroups_of_S6,
|
||||
)
|
||||
from sympy.combinatorics.homomorphisms import is_isomorphic
|
||||
from sympy.combinatorics.named_groups import (
|
||||
SymmetricGroup, AlternatingGroup, CyclicGroup,
|
||||
)
|
||||
|
||||
|
||||
def test_four_group():
|
||||
G = S4TransitiveSubgroups.V.get_perm_group()
|
||||
A4 = AlternatingGroup(4)
|
||||
assert G.is_subgroup(A4)
|
||||
assert G.degree == 4
|
||||
assert G.is_transitive()
|
||||
assert G.order() == 4
|
||||
assert not G.is_cyclic
|
||||
|
||||
|
||||
def test_M20():
|
||||
G = S5TransitiveSubgroups.M20.get_perm_group()
|
||||
S5 = SymmetricGroup(5)
|
||||
A5 = AlternatingGroup(5)
|
||||
assert G.is_subgroup(S5)
|
||||
assert not G.is_subgroup(A5)
|
||||
assert G.degree == 5
|
||||
assert G.is_transitive()
|
||||
assert G.order() == 20
|
||||
|
||||
|
||||
# Setting this True means that for each of the transitive subgroups of S6,
|
||||
# we run a test not only on the fixed representation, but also on one freshly
|
||||
# generated by the search procedure.
|
||||
INCLUDE_SEARCH_REPS = False
|
||||
S6_randomized = {}
|
||||
if INCLUDE_SEARCH_REPS:
|
||||
S6_randomized = find_transitive_subgroups_of_S6(*list(S6TransitiveSubgroups))
|
||||
|
||||
|
||||
def get_versions_of_S6_subgroup(name):
|
||||
vers = [name.get_perm_group()]
|
||||
if INCLUDE_SEARCH_REPS:
|
||||
vers.append(S6_randomized[name])
|
||||
return vers
|
||||
|
||||
|
||||
def test_S6_transitive_subgroups():
|
||||
"""
|
||||
Test enough characteristics to distinguish all 16 transitive subgroups.
|
||||
"""
|
||||
ts = S6TransitiveSubgroups
|
||||
A6 = AlternatingGroup(6)
|
||||
for name, alt, order, is_isom, not_isom in [
|
||||
(ts.C6, False, 6, CyclicGroup(6), None),
|
||||
(ts.S3, False, 6, SymmetricGroup(3), None),
|
||||
(ts.D6, False, 12, None, None),
|
||||
(ts.A4, True, 12, None, None),
|
||||
(ts.G18, False, 18, None, None),
|
||||
(ts.A4xC2, False, 24, None, SymmetricGroup(4)),
|
||||
(ts.S4m, False, 24, SymmetricGroup(4), None),
|
||||
(ts.S4p, True, 24, None, None),
|
||||
(ts.G36m, False, 36, None, None),
|
||||
(ts.G36p, True, 36, None, None),
|
||||
(ts.S4xC2, False, 48, None, None),
|
||||
(ts.PSL2F5, True, 60, None, None),
|
||||
(ts.G72, False, 72, None, None),
|
||||
(ts.PGL2F5, False, 120, None, None),
|
||||
(ts.A6, True, 360, None, None),
|
||||
(ts.S6, False, 720, None, None),
|
||||
]:
|
||||
for G in get_versions_of_S6_subgroup(name):
|
||||
assert G.is_transitive()
|
||||
assert G.degree == 6
|
||||
assert G.is_subgroup(A6) is alt
|
||||
assert G.order() == order
|
||||
if is_isom:
|
||||
assert is_isomorphic(G, is_isom)
|
||||
if not_isom:
|
||||
assert not is_isomorphic(G, not_isom)
|
||||
@@ -0,0 +1,105 @@
|
||||
from sympy.combinatorics.generators import symmetric, cyclic, alternating, \
|
||||
dihedral, rubik
|
||||
from sympy.combinatorics.permutations import Permutation
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
def test_generators():
|
||||
|
||||
assert list(cyclic(6)) == [
|
||||
Permutation([0, 1, 2, 3, 4, 5]),
|
||||
Permutation([1, 2, 3, 4, 5, 0]),
|
||||
Permutation([2, 3, 4, 5, 0, 1]),
|
||||
Permutation([3, 4, 5, 0, 1, 2]),
|
||||
Permutation([4, 5, 0, 1, 2, 3]),
|
||||
Permutation([5, 0, 1, 2, 3, 4])]
|
||||
|
||||
assert list(cyclic(10)) == [
|
||||
Permutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
||||
Permutation([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]),
|
||||
Permutation([2, 3, 4, 5, 6, 7, 8, 9, 0, 1]),
|
||||
Permutation([3, 4, 5, 6, 7, 8, 9, 0, 1, 2]),
|
||||
Permutation([4, 5, 6, 7, 8, 9, 0, 1, 2, 3]),
|
||||
Permutation([5, 6, 7, 8, 9, 0, 1, 2, 3, 4]),
|
||||
Permutation([6, 7, 8, 9, 0, 1, 2, 3, 4, 5]),
|
||||
Permutation([7, 8, 9, 0, 1, 2, 3, 4, 5, 6]),
|
||||
Permutation([8, 9, 0, 1, 2, 3, 4, 5, 6, 7]),
|
||||
Permutation([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])]
|
||||
|
||||
assert list(alternating(4)) == [
|
||||
Permutation([0, 1, 2, 3]),
|
||||
Permutation([0, 2, 3, 1]),
|
||||
Permutation([0, 3, 1, 2]),
|
||||
Permutation([1, 0, 3, 2]),
|
||||
Permutation([1, 2, 0, 3]),
|
||||
Permutation([1, 3, 2, 0]),
|
||||
Permutation([2, 0, 1, 3]),
|
||||
Permutation([2, 1, 3, 0]),
|
||||
Permutation([2, 3, 0, 1]),
|
||||
Permutation([3, 0, 2, 1]),
|
||||
Permutation([3, 1, 0, 2]),
|
||||
Permutation([3, 2, 1, 0])]
|
||||
|
||||
assert list(symmetric(3)) == [
|
||||
Permutation([0, 1, 2]),
|
||||
Permutation([0, 2, 1]),
|
||||
Permutation([1, 0, 2]),
|
||||
Permutation([1, 2, 0]),
|
||||
Permutation([2, 0, 1]),
|
||||
Permutation([2, 1, 0])]
|
||||
|
||||
assert list(symmetric(4)) == [
|
||||
Permutation([0, 1, 2, 3]),
|
||||
Permutation([0, 1, 3, 2]),
|
||||
Permutation([0, 2, 1, 3]),
|
||||
Permutation([0, 2, 3, 1]),
|
||||
Permutation([0, 3, 1, 2]),
|
||||
Permutation([0, 3, 2, 1]),
|
||||
Permutation([1, 0, 2, 3]),
|
||||
Permutation([1, 0, 3, 2]),
|
||||
Permutation([1, 2, 0, 3]),
|
||||
Permutation([1, 2, 3, 0]),
|
||||
Permutation([1, 3, 0, 2]),
|
||||
Permutation([1, 3, 2, 0]),
|
||||
Permutation([2, 0, 1, 3]),
|
||||
Permutation([2, 0, 3, 1]),
|
||||
Permutation([2, 1, 0, 3]),
|
||||
Permutation([2, 1, 3, 0]),
|
||||
Permutation([2, 3, 0, 1]),
|
||||
Permutation([2, 3, 1, 0]),
|
||||
Permutation([3, 0, 1, 2]),
|
||||
Permutation([3, 0, 2, 1]),
|
||||
Permutation([3, 1, 0, 2]),
|
||||
Permutation([3, 1, 2, 0]),
|
||||
Permutation([3, 2, 0, 1]),
|
||||
Permutation([3, 2, 1, 0])]
|
||||
|
||||
assert list(dihedral(1)) == [
|
||||
Permutation([0, 1]), Permutation([1, 0])]
|
||||
|
||||
assert list(dihedral(2)) == [
|
||||
Permutation([0, 1, 2, 3]),
|
||||
Permutation([1, 0, 3, 2]),
|
||||
Permutation([2, 3, 0, 1]),
|
||||
Permutation([3, 2, 1, 0])]
|
||||
|
||||
assert list(dihedral(3)) == [
|
||||
Permutation([0, 1, 2]),
|
||||
Permutation([2, 1, 0]),
|
||||
Permutation([1, 2, 0]),
|
||||
Permutation([0, 2, 1]),
|
||||
Permutation([2, 0, 1]),
|
||||
Permutation([1, 0, 2])]
|
||||
|
||||
assert list(dihedral(5)) == [
|
||||
Permutation([0, 1, 2, 3, 4]),
|
||||
Permutation([4, 3, 2, 1, 0]),
|
||||
Permutation([1, 2, 3, 4, 0]),
|
||||
Permutation([0, 4, 3, 2, 1]),
|
||||
Permutation([2, 3, 4, 0, 1]),
|
||||
Permutation([1, 0, 4, 3, 2]),
|
||||
Permutation([3, 4, 0, 1, 2]),
|
||||
Permutation([2, 1, 0, 4, 3]),
|
||||
Permutation([4, 0, 1, 2, 3]),
|
||||
Permutation([3, 2, 1, 0, 4])]
|
||||
|
||||
raises(ValueError, lambda: rubik(1))
|
||||
@@ -0,0 +1,72 @@
|
||||
from sympy.combinatorics.graycode import (GrayCode, bin_to_gray,
|
||||
random_bitstring, get_subset_from_bitstring, graycode_subsets,
|
||||
gray_to_bin)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
def test_graycode():
|
||||
g = GrayCode(2)
|
||||
got = []
|
||||
for i in g.generate_gray():
|
||||
if i.startswith('0'):
|
||||
g.skip()
|
||||
got.append(i)
|
||||
assert got == '00 11 10'.split()
|
||||
a = GrayCode(6)
|
||||
assert a.current == '0'*6
|
||||
assert a.rank == 0
|
||||
assert len(list(a.generate_gray())) == 64
|
||||
codes = ['011001', '011011', '011010',
|
||||
'011110', '011111', '011101', '011100', '010100', '010101', '010111',
|
||||
'010110', '010010', '010011', '010001', '010000', '110000', '110001',
|
||||
'110011', '110010', '110110', '110111', '110101', '110100', '111100',
|
||||
'111101', '111111', '111110', '111010', '111011', '111001', '111000',
|
||||
'101000', '101001', '101011', '101010', '101110', '101111', '101101',
|
||||
'101100', '100100', '100101', '100111', '100110', '100010', '100011',
|
||||
'100001', '100000']
|
||||
assert list(a.generate_gray(start='011001')) == codes
|
||||
assert list(
|
||||
a.generate_gray(rank=GrayCode(6, start='011001').rank)) == codes
|
||||
assert a.next().current == '000001'
|
||||
assert a.next(2).current == '000011'
|
||||
assert a.next(-1).current == '100000'
|
||||
|
||||
a = GrayCode(5, start='10010')
|
||||
assert a.rank == 28
|
||||
a = GrayCode(6, start='101000')
|
||||
assert a.rank == 48
|
||||
|
||||
assert GrayCode(6, rank=4).current == '000110'
|
||||
assert GrayCode(6, rank=4).rank == 4
|
||||
assert [GrayCode(4, start=s).rank for s in
|
||||
GrayCode(4).generate_gray()] == [0, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 11, 12, 13, 14, 15]
|
||||
a = GrayCode(15, rank=15)
|
||||
assert a.current == '000000000001000'
|
||||
|
||||
assert bin_to_gray('111') == '100'
|
||||
|
||||
a = random_bitstring(5)
|
||||
assert type(a) is str
|
||||
assert len(a) == 5
|
||||
assert all(i in ['0', '1'] for i in a)
|
||||
|
||||
assert get_subset_from_bitstring(
|
||||
['a', 'b', 'c', 'd'], '0011') == ['c', 'd']
|
||||
assert get_subset_from_bitstring('abcd', '1001') == ['a', 'd']
|
||||
assert list(graycode_subsets(['a', 'b', 'c'])) == \
|
||||
[[], ['c'], ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'],
|
||||
['a', 'c'], ['a']]
|
||||
|
||||
raises(ValueError, lambda: GrayCode(0))
|
||||
raises(ValueError, lambda: GrayCode(2.2))
|
||||
raises(ValueError, lambda: GrayCode(2, start=[1, 1, 0]))
|
||||
raises(ValueError, lambda: GrayCode(2, rank=2.5))
|
||||
raises(ValueError, lambda: get_subset_from_bitstring(['c', 'a', 'c'], '1100'))
|
||||
raises(ValueError, lambda: list(GrayCode(3).generate_gray(start="1111")))
|
||||
|
||||
|
||||
def test_live_issue_117():
|
||||
assert bin_to_gray('0100') == '0110'
|
||||
assert bin_to_gray('0101') == '0111'
|
||||
for bits in ('0100', '0101'):
|
||||
assert gray_to_bin(bin_to_gray(bits)) == bits
|
||||
@@ -0,0 +1,15 @@
|
||||
from sympy.combinatorics.group_constructs import DirectProduct
|
||||
from sympy.combinatorics.named_groups import CyclicGroup, DihedralGroup
|
||||
|
||||
|
||||
def test_direct_product_n():
|
||||
C = CyclicGroup(4)
|
||||
D = DihedralGroup(4)
|
||||
G = DirectProduct(C, C, C)
|
||||
assert G.order() == 64
|
||||
assert G.degree == 12
|
||||
assert len(G.orbits()) == 3
|
||||
assert G.is_abelian is True
|
||||
H = DirectProduct(D, C)
|
||||
assert H.order() == 32
|
||||
assert H.is_abelian is False
|
||||
@@ -0,0 +1,110 @@
|
||||
from sympy.combinatorics.group_numbers import (is_nilpotent_number,
|
||||
is_abelian_number, is_cyclic_number, _holder_formula, groups_count)
|
||||
from sympy.ntheory.factor_ import factorint
|
||||
from sympy.ntheory.generate import prime
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy import randprime
|
||||
|
||||
|
||||
def test_is_nilpotent_number():
|
||||
assert is_nilpotent_number(21) == False
|
||||
assert is_nilpotent_number(randprime(1, 30)**12) == True
|
||||
raises(ValueError, lambda: is_nilpotent_number(-5))
|
||||
|
||||
A056867 = [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 15, 16, 17, 19,
|
||||
23, 25, 27, 29, 31, 32, 33, 35, 37, 41, 43, 45,
|
||||
47, 49, 51, 53, 59, 61, 64, 65, 67, 69, 71, 73,
|
||||
77, 79, 81, 83, 85, 87, 89, 91, 95, 97, 99]
|
||||
for n in range(1, 100):
|
||||
assert is_nilpotent_number(n) == (n in A056867)
|
||||
|
||||
|
||||
def test_is_abelian_number():
|
||||
assert is_abelian_number(4) == True
|
||||
assert is_abelian_number(randprime(1, 2000)**2) == True
|
||||
assert is_abelian_number(randprime(1000, 100000)) == True
|
||||
assert is_abelian_number(60) == False
|
||||
assert is_abelian_number(24) == False
|
||||
raises(ValueError, lambda: is_abelian_number(-5))
|
||||
|
||||
A051532 = [1, 2, 3, 4, 5, 7, 9, 11, 13, 15, 17, 19, 23, 25,
|
||||
29, 31, 33, 35, 37, 41, 43, 45, 47, 49, 51, 53,
|
||||
59, 61, 65, 67, 69, 71, 73, 77, 79, 83, 85, 87,
|
||||
89, 91, 95, 97, 99]
|
||||
for n in range(1, 100):
|
||||
assert is_abelian_number(n) == (n in A051532)
|
||||
|
||||
|
||||
A003277 = [1, 2, 3, 5, 7, 11, 13, 15, 17, 19, 23, 29,
|
||||
31, 33, 35, 37, 41, 43, 47, 51, 53, 59, 61,
|
||||
65, 67, 69, 71, 73, 77, 79, 83, 85, 87, 89,
|
||||
91, 95, 97]
|
||||
|
||||
|
||||
def test_is_cyclic_number():
|
||||
assert is_cyclic_number(15) == True
|
||||
assert is_cyclic_number(randprime(1, 2000)**2) == False
|
||||
assert is_cyclic_number(randprime(1000, 100000)) == True
|
||||
assert is_cyclic_number(4) == False
|
||||
raises(ValueError, lambda: is_cyclic_number(-5))
|
||||
|
||||
for n in range(1, 100):
|
||||
assert is_cyclic_number(n) == (n in A003277)
|
||||
|
||||
|
||||
def test_holder_formula():
|
||||
# semiprime
|
||||
assert _holder_formula({3, 5}) == 1
|
||||
assert _holder_formula({5, 11}) == 2
|
||||
# n in A003277 is always 1
|
||||
for n in A003277:
|
||||
assert _holder_formula(set(factorint(n).keys())) == 1
|
||||
# otherwise
|
||||
assert _holder_formula({2, 3, 5, 7}) == 12
|
||||
|
||||
|
||||
def test_groups_count():
|
||||
A000001 = [0, 1, 1, 1, 2, 1, 2, 1, 5, 2, 2, 1, 5, 1,
|
||||
2, 1, 14, 1, 5, 1, 5, 2, 2, 1, 15, 2, 2,
|
||||
5, 4, 1, 4, 1, 51, 1, 2, 1, 14, 1, 2, 2,
|
||||
14, 1, 6, 1, 4, 2, 2, 1, 52, 2, 5, 1, 5,
|
||||
1, 15, 2, 13, 2, 2, 1, 13, 1, 2, 4, 267,
|
||||
1, 4, 1, 5, 1, 4, 1, 50, 1, 2, 3, 4, 1,
|
||||
6, 1, 52, 15, 2, 1, 15, 1, 2, 1, 12, 1,
|
||||
10, 1, 4, 2]
|
||||
for n in range(1, len(A000001)):
|
||||
try:
|
||||
assert groups_count(n) == A000001[n]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
A000679 = [1, 1, 2, 5, 14, 51, 267, 2328, 56092, 10494213, 49487367289]
|
||||
for e in range(1, len(A000679)):
|
||||
assert groups_count(2**e) == A000679[e]
|
||||
|
||||
A090091 = [1, 1, 2, 5, 15, 67, 504, 9310, 1396077, 5937876645]
|
||||
for e in range(1, len(A090091)):
|
||||
assert groups_count(3**e) == A090091[e]
|
||||
|
||||
A090130 = [1, 1, 2, 5, 15, 77, 684, 34297]
|
||||
for e in range(1, len(A090130)):
|
||||
assert groups_count(5**e) == A090130[e]
|
||||
|
||||
A090140 = [1, 1, 2, 5, 15, 83, 860, 113147]
|
||||
for e in range(1, len(A090140)):
|
||||
assert groups_count(7**e) == A090140[e]
|
||||
|
||||
A232105 = [51, 67, 77, 83, 87, 97, 101, 107, 111, 125, 131,
|
||||
145, 149, 155, 159, 173, 183, 193, 203, 207, 217]
|
||||
for i in range(len(A232105)):
|
||||
assert groups_count(prime(i+1)**5) == A232105[i]
|
||||
|
||||
A232106 = [267, 504, 684, 860, 1192, 1476, 1944, 2264, 2876,
|
||||
4068, 4540, 6012, 7064, 7664, 8852, 10908, 13136]
|
||||
for i in range(len(A232106)):
|
||||
assert groups_count(prime(i+1)**6) == A232106[i]
|
||||
|
||||
A232107 = [2328, 9310, 34297, 113147, 750735, 1600573,
|
||||
5546909, 9380741, 23316851, 71271069, 98488755]
|
||||
for i in range(len(A232107)):
|
||||
assert groups_count(prime(i+1)**7) == A232107[i]
|
||||
@@ -0,0 +1,114 @@
|
||||
from sympy.combinatorics import Permutation
|
||||
from sympy.combinatorics.perm_groups import PermutationGroup
|
||||
from sympy.combinatorics.homomorphisms import homomorphism, group_isomorphism, is_isomorphic
|
||||
from sympy.combinatorics.free_groups import free_group
|
||||
from sympy.combinatorics.fp_groups import FpGroup
|
||||
from sympy.combinatorics.named_groups import AlternatingGroup, DihedralGroup, CyclicGroup
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
def test_homomorphism():
|
||||
# FpGroup -> PermutationGroup
|
||||
F, a, b = free_group("a, b")
|
||||
G = FpGroup(F, [a**3, b**3, (a*b)**2])
|
||||
|
||||
c = Permutation(3)(0, 1, 2)
|
||||
d = Permutation(3)(1, 2, 3)
|
||||
A = AlternatingGroup(4)
|
||||
T = homomorphism(G, A, [a, b], [c, d])
|
||||
assert T(a*b**2*a**-1) == c*d**2*c**-1
|
||||
assert T.is_isomorphism()
|
||||
assert T(T.invert(Permutation(3)(0, 2, 3))) == Permutation(3)(0, 2, 3)
|
||||
|
||||
T = homomorphism(G, AlternatingGroup(4), G.generators)
|
||||
assert T.is_trivial()
|
||||
assert T.kernel().order() == G.order()
|
||||
|
||||
E, e = free_group("e")
|
||||
G = FpGroup(E, [e**8])
|
||||
P = PermutationGroup([Permutation(0, 1, 2, 3), Permutation(0, 2)])
|
||||
T = homomorphism(G, P, [e], [Permutation(0, 1, 2, 3)])
|
||||
assert T.image().order() == 4
|
||||
assert T(T.invert(Permutation(0, 2)(1, 3))) == Permutation(0, 2)(1, 3)
|
||||
|
||||
T = homomorphism(E, AlternatingGroup(4), E.generators, [c])
|
||||
assert T.invert(c**2) == e**-1 #order(c) == 3 so c**2 == c**-1
|
||||
|
||||
# FreeGroup -> FreeGroup
|
||||
T = homomorphism(F, E, [a], [e])
|
||||
assert T(a**-2*b**4*a**2).is_identity
|
||||
|
||||
# FreeGroup -> FpGroup
|
||||
G = FpGroup(F, [a*b*a**-1*b**-1])
|
||||
T = homomorphism(F, G, F.generators, G.generators)
|
||||
assert T.invert(a**-1*b**-1*a**2) == a*b**-1
|
||||
|
||||
# PermutationGroup -> PermutationGroup
|
||||
D = DihedralGroup(8)
|
||||
p = Permutation(0, 1, 2, 3, 4, 5, 6, 7)
|
||||
P = PermutationGroup(p)
|
||||
T = homomorphism(P, D, [p], [p])
|
||||
assert T.is_injective()
|
||||
assert not T.is_isomorphism()
|
||||
assert T.invert(p**3) == p**3
|
||||
|
||||
T2 = homomorphism(F, P, [F.generators[0]], P.generators)
|
||||
T = T.compose(T2)
|
||||
assert T.domain == F
|
||||
assert T.codomain == D
|
||||
assert T(a*b) == p
|
||||
|
||||
D3 = DihedralGroup(3)
|
||||
T = homomorphism(D3, D3, D3.generators, D3.generators)
|
||||
assert T.is_isomorphism()
|
||||
|
||||
|
||||
def test_isomorphisms():
|
||||
|
||||
F, a, b = free_group("a, b")
|
||||
E, c, d = free_group("c, d")
|
||||
# Infinite groups with differently ordered relators.
|
||||
G = FpGroup(F, [a**2, b**3])
|
||||
H = FpGroup(F, [b**3, a**2])
|
||||
assert is_isomorphic(G, H)
|
||||
|
||||
# Trivial Case
|
||||
# FpGroup -> FpGroup
|
||||
H = FpGroup(F, [a**3, b**3, (a*b)**2])
|
||||
F, c, d = free_group("c, d")
|
||||
G = FpGroup(F, [c**3, d**3, (c*d)**2])
|
||||
check, T = group_isomorphism(G, H)
|
||||
assert check
|
||||
assert T(c**3*d**2) == a**3*b**2
|
||||
|
||||
# FpGroup -> PermutationGroup
|
||||
# FpGroup is converted to the equivalent isomorphic group.
|
||||
F, a, b = free_group("a, b")
|
||||
G = FpGroup(F, [a**3, b**3, (a*b)**2])
|
||||
H = AlternatingGroup(4)
|
||||
check, T = group_isomorphism(G, H)
|
||||
assert check
|
||||
assert T(b*a*b**-1*a**-1*b**-1) == Permutation(0, 2, 3)
|
||||
assert T(b*a*b*a**-1*b**-1) == Permutation(0, 3, 2)
|
||||
|
||||
# PermutationGroup -> PermutationGroup
|
||||
D = DihedralGroup(8)
|
||||
p = Permutation(0, 1, 2, 3, 4, 5, 6, 7)
|
||||
P = PermutationGroup(p)
|
||||
assert not is_isomorphic(D, P)
|
||||
|
||||
A = CyclicGroup(5)
|
||||
B = CyclicGroup(7)
|
||||
assert not is_isomorphic(A, B)
|
||||
|
||||
# Two groups of the same prime order are isomorphic to each other.
|
||||
G = FpGroup(F, [a, b**5])
|
||||
H = CyclicGroup(5)
|
||||
assert G.order() == H.order()
|
||||
assert is_isomorphic(G, H)
|
||||
|
||||
|
||||
def test_check_homomorphism():
|
||||
a = Permutation(1,2,3,4)
|
||||
b = Permutation(1,3)
|
||||
G = PermutationGroup([a, b])
|
||||
raises(ValueError, lambda: homomorphism(G, G, [a], [a]))
|
||||
@@ -0,0 +1,70 @@
|
||||
from sympy.combinatorics.named_groups import (SymmetricGroup, CyclicGroup,
|
||||
DihedralGroup, AlternatingGroup,
|
||||
AbelianGroup, RubikGroup)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_SymmetricGroup():
|
||||
G = SymmetricGroup(5)
|
||||
elements = list(G.generate())
|
||||
assert (G.generators[0]).size == 5
|
||||
assert len(elements) == 120
|
||||
assert G.is_solvable is False
|
||||
assert G.is_abelian is False
|
||||
assert G.is_nilpotent is False
|
||||
assert G.is_transitive() is True
|
||||
H = SymmetricGroup(1)
|
||||
assert H.order() == 1
|
||||
L = SymmetricGroup(2)
|
||||
assert L.order() == 2
|
||||
|
||||
|
||||
def test_CyclicGroup():
|
||||
G = CyclicGroup(10)
|
||||
elements = list(G.generate())
|
||||
assert len(elements) == 10
|
||||
assert (G.derived_subgroup()).order() == 1
|
||||
assert G.is_abelian is True
|
||||
assert G.is_solvable is True
|
||||
assert G.is_nilpotent is True
|
||||
H = CyclicGroup(1)
|
||||
assert H.order() == 1
|
||||
L = CyclicGroup(2)
|
||||
assert L.order() == 2
|
||||
|
||||
|
||||
def test_DihedralGroup():
|
||||
G = DihedralGroup(6)
|
||||
elements = list(G.generate())
|
||||
assert len(elements) == 12
|
||||
assert G.is_transitive() is True
|
||||
assert G.is_abelian is False
|
||||
assert G.is_solvable is True
|
||||
assert G.is_nilpotent is False
|
||||
H = DihedralGroup(1)
|
||||
assert H.order() == 2
|
||||
L = DihedralGroup(2)
|
||||
assert L.order() == 4
|
||||
assert L.is_abelian is True
|
||||
assert L.is_nilpotent is True
|
||||
|
||||
|
||||
def test_AlternatingGroup():
|
||||
G = AlternatingGroup(5)
|
||||
elements = list(G.generate())
|
||||
assert len(elements) == 60
|
||||
assert [perm.is_even for perm in elements] == [True]*60
|
||||
H = AlternatingGroup(1)
|
||||
assert H.order() == 1
|
||||
L = AlternatingGroup(2)
|
||||
assert L.order() == 1
|
||||
|
||||
|
||||
def test_AbelianGroup():
|
||||
A = AbelianGroup(3, 3, 3)
|
||||
assert A.order() == 27
|
||||
assert A.is_abelian is True
|
||||
|
||||
|
||||
def test_RubikGroup():
|
||||
raises(ValueError, lambda: RubikGroup(1))
|
||||
@@ -0,0 +1,118 @@
|
||||
from sympy.core.sorting import ordered, default_sort_key
|
||||
from sympy.combinatorics.partitions import (Partition, IntegerPartition,
|
||||
RGS_enum, RGS_unrank, RGS_rank,
|
||||
random_integer_partition)
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.utilities.iterables import partitions
|
||||
from sympy.sets.sets import Set, FiniteSet
|
||||
|
||||
|
||||
def test_partition_constructor():
|
||||
raises(ValueError, lambda: Partition([1, 1, 2]))
|
||||
raises(ValueError, lambda: Partition([1, 2, 3], [2, 3, 4]))
|
||||
raises(ValueError, lambda: Partition(1, 2, 3))
|
||||
raises(ValueError, lambda: Partition(*list(range(3))))
|
||||
|
||||
assert Partition([1, 2, 3], [4, 5]) == Partition([4, 5], [1, 2, 3])
|
||||
assert Partition({1, 2, 3}, {4, 5}) == Partition([1, 2, 3], [4, 5])
|
||||
|
||||
a = FiniteSet(1, 2, 3)
|
||||
b = FiniteSet(4, 5)
|
||||
assert Partition(a, b) == Partition([1, 2, 3], [4, 5])
|
||||
assert Partition({a, b}) == Partition(FiniteSet(a, b))
|
||||
assert Partition({a, b}) != Partition(a, b)
|
||||
|
||||
def test_partition():
|
||||
from sympy.abc import x
|
||||
|
||||
a = Partition([1, 2, 3], [4])
|
||||
b = Partition([1, 2], [3, 4])
|
||||
c = Partition([x])
|
||||
l = [a, b, c]
|
||||
l.sort(key=default_sort_key)
|
||||
assert l == [c, a, b]
|
||||
l.sort(key=lambda w: default_sort_key(w, order='rev-lex'))
|
||||
assert l == [c, a, b]
|
||||
|
||||
assert (a == b) is False
|
||||
assert a <= b
|
||||
assert (a > b) is False
|
||||
assert a != b
|
||||
assert a < b
|
||||
|
||||
assert (a + 2).partition == [[1, 2], [3, 4]]
|
||||
assert (b - 1).partition == [[1, 2, 4], [3]]
|
||||
|
||||
assert (a - 1).partition == [[1, 2, 3, 4]]
|
||||
assert (a + 1).partition == [[1, 2, 4], [3]]
|
||||
assert (b + 1).partition == [[1, 2], [3], [4]]
|
||||
|
||||
assert a.rank == 1
|
||||
assert b.rank == 3
|
||||
|
||||
assert a.RGS == (0, 0, 0, 1)
|
||||
assert b.RGS == (0, 0, 1, 1)
|
||||
|
||||
|
||||
def test_integer_partition():
|
||||
# no zeros in partition
|
||||
raises(ValueError, lambda: IntegerPartition(list(range(3))))
|
||||
# check fails since 1 + 2 != 100
|
||||
raises(ValueError, lambda: IntegerPartition(100, list(range(1, 3))))
|
||||
a = IntegerPartition(8, [1, 3, 4])
|
||||
b = a.next_lex()
|
||||
c = IntegerPartition([1, 3, 4])
|
||||
d = IntegerPartition(8, {1: 3, 3: 1, 2: 1})
|
||||
assert a == c
|
||||
assert a.integer == d.integer
|
||||
assert a.conjugate == [3, 2, 2, 1]
|
||||
assert (a == b) is False
|
||||
assert a <= b
|
||||
assert (a > b) is False
|
||||
assert a != b
|
||||
|
||||
for i in range(1, 11):
|
||||
next = set()
|
||||
prev = set()
|
||||
a = IntegerPartition([i])
|
||||
ans = {IntegerPartition(p) for p in partitions(i)}
|
||||
n = len(ans)
|
||||
for j in range(n):
|
||||
next.add(a)
|
||||
a = a.next_lex()
|
||||
IntegerPartition(i, a.partition) # check it by giving i
|
||||
for j in range(n):
|
||||
prev.add(a)
|
||||
a = a.prev_lex()
|
||||
IntegerPartition(i, a.partition) # check it by giving i
|
||||
assert next == ans
|
||||
assert prev == ans
|
||||
|
||||
assert IntegerPartition([1, 2, 3]).as_ferrers() == '###\n##\n#'
|
||||
assert IntegerPartition([1, 1, 3]).as_ferrers('o') == 'ooo\no\no'
|
||||
assert str(IntegerPartition([1, 1, 3])) == '[3, 1, 1]'
|
||||
assert IntegerPartition([1, 1, 3]).partition == [3, 1, 1]
|
||||
|
||||
raises(ValueError, lambda: random_integer_partition(-1))
|
||||
assert random_integer_partition(1) == [1]
|
||||
assert random_integer_partition(10, seed=[1, 3, 2, 1, 5, 1]
|
||||
) == [5, 2, 1, 1, 1]
|
||||
|
||||
|
||||
def test_rgs():
|
||||
raises(ValueError, lambda: RGS_unrank(-1, 3))
|
||||
raises(ValueError, lambda: RGS_unrank(3, 0))
|
||||
raises(ValueError, lambda: RGS_unrank(10, 1))
|
||||
|
||||
raises(ValueError, lambda: Partition.from_rgs(list(range(3)), list(range(2))))
|
||||
raises(ValueError, lambda: Partition.from_rgs(list(range(1, 3)), list(range(2))))
|
||||
assert RGS_enum(-1) == 0
|
||||
assert RGS_enum(1) == 1
|
||||
assert RGS_unrank(7, 5) == [0, 0, 1, 0, 2]
|
||||
assert RGS_unrank(23, 14) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2]
|
||||
assert RGS_rank(RGS_unrank(40, 100)) == 40
|
||||
|
||||
def test_ordered_partition_9608():
|
||||
a = Partition([1, 2, 3], [4])
|
||||
b = Partition([1, 2], [3, 4])
|
||||
assert list(ordered([a,b], Set._infimum_key))
|
||||
@@ -0,0 +1,87 @@
|
||||
from sympy.combinatorics.permutations import Permutation
|
||||
from sympy.combinatorics.named_groups import SymmetricGroup, AlternatingGroup, DihedralGroup
|
||||
from sympy.matrices import Matrix
|
||||
|
||||
def test_pc_presentation():
|
||||
Groups = [SymmetricGroup(3), SymmetricGroup(4), SymmetricGroup(9).sylow_subgroup(3),
|
||||
SymmetricGroup(9).sylow_subgroup(2), SymmetricGroup(8).sylow_subgroup(2), DihedralGroup(10)]
|
||||
|
||||
S = SymmetricGroup(125).sylow_subgroup(5)
|
||||
G = S.derived_series()[2]
|
||||
Groups.append(G)
|
||||
|
||||
G = SymmetricGroup(25).sylow_subgroup(5)
|
||||
Groups.append(G)
|
||||
|
||||
S = SymmetricGroup(11**2).sylow_subgroup(11)
|
||||
G = S.derived_series()[2]
|
||||
Groups.append(G)
|
||||
|
||||
for G in Groups:
|
||||
PcGroup = G.polycyclic_group()
|
||||
collector = PcGroup.collector
|
||||
pc_presentation = collector.pc_presentation
|
||||
|
||||
pcgs = PcGroup.pcgs
|
||||
free_group = collector.free_group
|
||||
free_to_perm = {}
|
||||
for s, g in zip(free_group.symbols, pcgs):
|
||||
free_to_perm[s] = g
|
||||
|
||||
for k, v in pc_presentation.items():
|
||||
k_array = k.array_form
|
||||
if v != ():
|
||||
v_array = v.array_form
|
||||
|
||||
lhs = Permutation()
|
||||
for gen in k_array:
|
||||
s = gen[0]
|
||||
e = gen[1]
|
||||
lhs = lhs*free_to_perm[s]**e
|
||||
|
||||
if v == ():
|
||||
assert lhs.is_identity
|
||||
continue
|
||||
|
||||
rhs = Permutation()
|
||||
for gen in v_array:
|
||||
s = gen[0]
|
||||
e = gen[1]
|
||||
rhs = rhs*free_to_perm[s]**e
|
||||
|
||||
assert lhs == rhs
|
||||
|
||||
|
||||
def test_exponent_vector():
|
||||
|
||||
Groups = [SymmetricGroup(3), SymmetricGroup(4), SymmetricGroup(9).sylow_subgroup(3),
|
||||
SymmetricGroup(9).sylow_subgroup(2), SymmetricGroup(8).sylow_subgroup(2)]
|
||||
|
||||
for G in Groups:
|
||||
PcGroup = G.polycyclic_group()
|
||||
collector = PcGroup.collector
|
||||
|
||||
pcgs = PcGroup.pcgs
|
||||
# free_group = collector.free_group
|
||||
|
||||
for gen in G.generators:
|
||||
exp = collector.exponent_vector(gen)
|
||||
g = Permutation()
|
||||
for i in range(len(exp)):
|
||||
g = g*pcgs[i]**exp[i] if exp[i] else g
|
||||
assert g == gen
|
||||
|
||||
|
||||
def test_induced_pcgs():
|
||||
G = [SymmetricGroup(9).sylow_subgroup(3), SymmetricGroup(20).sylow_subgroup(2), AlternatingGroup(4),
|
||||
DihedralGroup(4), DihedralGroup(10), DihedralGroup(9), SymmetricGroup(3), SymmetricGroup(4)]
|
||||
|
||||
for g in G:
|
||||
PcGroup = g.polycyclic_group()
|
||||
collector = PcGroup.collector
|
||||
gens = list(g.generators)
|
||||
ipcgs = collector.induced_pcgs(gens)
|
||||
m = []
|
||||
for i in ipcgs:
|
||||
m.append(collector.exponent_vector(i))
|
||||
assert Matrix(m).is_upper
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,564 @@
|
||||
from itertools import permutations
|
||||
from copy import copy
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.numbers import Integer
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.core.singleton import S
|
||||
from sympy.combinatorics.permutations import \
|
||||
Permutation, _af_parity, _af_rmul, _af_rmuln, AppliedPermutation, Cycle
|
||||
from sympy.printing import sstr, srepr, pretty, latex
|
||||
from sympy.testing.pytest import raises, warns_deprecated_sympy
|
||||
|
||||
|
||||
rmul = Permutation.rmul
|
||||
a = Symbol('a', integer=True)
|
||||
|
||||
|
||||
def test_Permutation():
|
||||
# don't auto fill 0
|
||||
raises(ValueError, lambda: Permutation([1]))
|
||||
p = Permutation([0, 1, 2, 3])
|
||||
# call as bijective
|
||||
assert [p(i) for i in range(p.size)] == list(p)
|
||||
# call as operator
|
||||
assert p(list(range(p.size))) == list(p)
|
||||
# call as function
|
||||
assert list(p(1, 2)) == [0, 2, 1, 3]
|
||||
raises(TypeError, lambda: p(-1))
|
||||
raises(TypeError, lambda: p(5))
|
||||
# conversion to list
|
||||
assert list(p) == list(range(4))
|
||||
assert p.copy() == p
|
||||
assert copy(p) == p
|
||||
assert Permutation(size=4) == Permutation(3)
|
||||
assert Permutation(Permutation(3), size=5) == Permutation(4)
|
||||
# cycle form with size
|
||||
assert Permutation([[1, 2]], size=4) == Permutation([[1, 2], [0], [3]])
|
||||
# random generation
|
||||
assert Permutation.random(2) in (Permutation([1, 0]), Permutation([0, 1]))
|
||||
|
||||
p = Permutation([2, 5, 1, 6, 3, 0, 4])
|
||||
q = Permutation([[1], [0, 3, 5, 6, 2, 4]])
|
||||
assert len({p, p}) == 1
|
||||
r = Permutation([1, 3, 2, 0, 4, 6, 5])
|
||||
ans = Permutation(_af_rmuln(*[w.array_form for w in (p, q, r)])).array_form
|
||||
assert rmul(p, q, r).array_form == ans
|
||||
# make sure no other permutation of p, q, r could have given
|
||||
# that answer
|
||||
for a, b, c in permutations((p, q, r)):
|
||||
if (a, b, c) == (p, q, r):
|
||||
continue
|
||||
assert rmul(a, b, c).array_form != ans
|
||||
|
||||
assert p.support() == list(range(7))
|
||||
assert q.support() == [0, 2, 3, 4, 5, 6]
|
||||
assert Permutation(p.cyclic_form).array_form == p.array_form
|
||||
assert p.cardinality == 5040
|
||||
assert q.cardinality == 5040
|
||||
assert q.cycles == 2
|
||||
assert rmul(q, p) == Permutation([4, 6, 1, 2, 5, 3, 0])
|
||||
assert rmul(p, q) == Permutation([6, 5, 3, 0, 2, 4, 1])
|
||||
assert _af_rmul(p.array_form, q.array_form) == \
|
||||
[6, 5, 3, 0, 2, 4, 1]
|
||||
|
||||
assert rmul(Permutation([[1, 2, 3], [0, 4]]),
|
||||
Permutation([[1, 2, 4], [0], [3]])).cyclic_form == \
|
||||
[[0, 4, 2], [1, 3]]
|
||||
assert q.array_form == [3, 1, 4, 5, 0, 6, 2]
|
||||
assert q.cyclic_form == [[0, 3, 5, 6, 2, 4]]
|
||||
assert q.full_cyclic_form == [[0, 3, 5, 6, 2, 4], [1]]
|
||||
assert p.cyclic_form == [[0, 2, 1, 5], [3, 6, 4]]
|
||||
t = p.transpositions()
|
||||
assert t == [(0, 5), (0, 1), (0, 2), (3, 4), (3, 6)]
|
||||
assert Permutation.rmul(*[Permutation(Cycle(*ti)) for ti in (t)])
|
||||
assert Permutation([1, 0]).transpositions() == [(0, 1)]
|
||||
|
||||
assert p**13 == p
|
||||
assert q**0 == Permutation(list(range(q.size)))
|
||||
assert q**-2 == ~q**2
|
||||
assert q**2 == Permutation([5, 1, 0, 6, 3, 2, 4])
|
||||
assert q**3 == q**2*q
|
||||
assert q**4 == q**2*q**2
|
||||
|
||||
a = Permutation(1, 3)
|
||||
b = Permutation(2, 0, 3)
|
||||
I = Permutation(3)
|
||||
assert ~a == a**-1
|
||||
assert a*~a == I
|
||||
assert a*b**-1 == a*~b
|
||||
|
||||
ans = Permutation(0, 5, 3, 1, 6)(2, 4)
|
||||
assert (p + q.rank()).rank() == ans.rank()
|
||||
assert (p + q.rank())._rank == ans.rank()
|
||||
assert (q + p.rank()).rank() == ans.rank()
|
||||
raises(TypeError, lambda: p + Permutation(list(range(10))))
|
||||
|
||||
assert (p - q.rank()).rank() == Permutation(0, 6, 3, 1, 2, 5, 4).rank()
|
||||
assert p.rank() - q.rank() < 0 # for coverage: make sure mod is used
|
||||
assert (q - p.rank()).rank() == Permutation(1, 4, 6, 2)(3, 5).rank()
|
||||
|
||||
assert p*q == Permutation(_af_rmuln(*[list(w) for w in (q, p)]))
|
||||
assert p*Permutation([]) == p
|
||||
assert Permutation([])*p == p
|
||||
assert p*Permutation([[0, 1]]) == Permutation([2, 5, 0, 6, 3, 1, 4])
|
||||
assert Permutation([[0, 1]])*p == Permutation([5, 2, 1, 6, 3, 0, 4])
|
||||
|
||||
pq = p ^ q
|
||||
assert pq == Permutation([5, 6, 0, 4, 1, 2, 3])
|
||||
assert pq == rmul(q, p, ~q)
|
||||
qp = q ^ p
|
||||
assert qp == Permutation([4, 3, 6, 2, 1, 5, 0])
|
||||
assert qp == rmul(p, q, ~p)
|
||||
raises(ValueError, lambda: p ^ Permutation([]))
|
||||
|
||||
assert p.commutator(q) == Permutation(0, 1, 3, 4, 6, 5, 2)
|
||||
assert q.commutator(p) == Permutation(0, 2, 5, 6, 4, 3, 1)
|
||||
assert p.commutator(q) == ~q.commutator(p)
|
||||
raises(ValueError, lambda: p.commutator(Permutation([])))
|
||||
|
||||
assert len(p.atoms()) == 7
|
||||
assert q.atoms() == {0, 1, 2, 3, 4, 5, 6}
|
||||
|
||||
assert p.inversion_vector() == [2, 4, 1, 3, 1, 0]
|
||||
assert q.inversion_vector() == [3, 1, 2, 2, 0, 1]
|
||||
|
||||
assert Permutation.from_inversion_vector(p.inversion_vector()) == p
|
||||
assert Permutation.from_inversion_vector(q.inversion_vector()).array_form\
|
||||
== q.array_form
|
||||
raises(ValueError, lambda: Permutation.from_inversion_vector([0, 2]))
|
||||
assert Permutation(list(range(500, -1, -1))).inversions() == 125250
|
||||
|
||||
s = Permutation([0, 4, 1, 3, 2])
|
||||
assert s.parity() == 0
|
||||
_ = s.cyclic_form # needed to create a value for _cyclic_form
|
||||
assert len(s._cyclic_form) != s.size and s.parity() == 0
|
||||
assert not s.is_odd
|
||||
assert s.is_even
|
||||
assert Permutation([0, 1, 4, 3, 2]).parity() == 1
|
||||
assert _af_parity([0, 4, 1, 3, 2]) == 0
|
||||
assert _af_parity([0, 1, 4, 3, 2]) == 1
|
||||
|
||||
s = Permutation([0])
|
||||
|
||||
assert s.is_Singleton
|
||||
assert Permutation([]).is_Empty
|
||||
|
||||
r = Permutation([3, 2, 1, 0])
|
||||
assert (r**2).is_Identity
|
||||
|
||||
assert rmul(~p, p).is_Identity
|
||||
assert (~p)**13 == Permutation([5, 2, 0, 4, 6, 1, 3])
|
||||
assert p.max() == 6
|
||||
assert p.min() == 0
|
||||
|
||||
q = Permutation([[6], [5], [0, 1, 2, 3, 4]])
|
||||
|
||||
assert q.max() == 4
|
||||
assert q.min() == 0
|
||||
|
||||
p = Permutation([1, 5, 2, 0, 3, 6, 4])
|
||||
q = Permutation([[1, 2, 3, 5, 6], [0, 4]])
|
||||
|
||||
assert p.ascents() == [0, 3, 4]
|
||||
assert q.ascents() == [1, 2, 4]
|
||||
assert r.ascents() == []
|
||||
|
||||
assert p.descents() == [1, 2, 5]
|
||||
assert q.descents() == [0, 3, 5]
|
||||
assert Permutation(r.descents()).is_Identity
|
||||
|
||||
assert p.inversions() == 7
|
||||
# test the merge-sort with a longer permutation
|
||||
big = list(p) + list(range(p.max() + 1, p.max() + 130))
|
||||
assert Permutation(big).inversions() == 7
|
||||
assert p.signature() == -1
|
||||
assert q.inversions() == 11
|
||||
assert q.signature() == -1
|
||||
assert rmul(p, ~p).inversions() == 0
|
||||
assert rmul(p, ~p).signature() == 1
|
||||
|
||||
assert p.order() == 6
|
||||
assert q.order() == 10
|
||||
assert (p**(p.order())).is_Identity
|
||||
|
||||
assert p.length() == 6
|
||||
assert q.length() == 7
|
||||
assert r.length() == 4
|
||||
|
||||
assert p.runs() == [[1, 5], [2], [0, 3, 6], [4]]
|
||||
assert q.runs() == [[4], [2, 3, 5], [0, 6], [1]]
|
||||
assert r.runs() == [[3], [2], [1], [0]]
|
||||
|
||||
assert p.index() == 8
|
||||
assert q.index() == 8
|
||||
assert r.index() == 3
|
||||
|
||||
assert p.get_precedence_distance(q) == q.get_precedence_distance(p)
|
||||
assert p.get_adjacency_distance(q) == p.get_adjacency_distance(q)
|
||||
assert p.get_positional_distance(q) == p.get_positional_distance(q)
|
||||
p = Permutation([0, 1, 2, 3])
|
||||
q = Permutation([3, 2, 1, 0])
|
||||
assert p.get_precedence_distance(q) == 6
|
||||
assert p.get_adjacency_distance(q) == 3
|
||||
assert p.get_positional_distance(q) == 8
|
||||
p = Permutation([0, 3, 1, 2, 4])
|
||||
q = Permutation.josephus(4, 5, 2)
|
||||
assert p.get_adjacency_distance(q) == 3
|
||||
raises(ValueError, lambda: p.get_adjacency_distance(Permutation([])))
|
||||
raises(ValueError, lambda: p.get_positional_distance(Permutation([])))
|
||||
raises(ValueError, lambda: p.get_precedence_distance(Permutation([])))
|
||||
|
||||
a = [Permutation.unrank_nonlex(4, i) for i in range(5)]
|
||||
iden = Permutation([0, 1, 2, 3])
|
||||
for i in range(5):
|
||||
for j in range(i + 1, 5):
|
||||
assert a[i].commutes_with(a[j]) == \
|
||||
(rmul(a[i], a[j]) == rmul(a[j], a[i]))
|
||||
if a[i].commutes_with(a[j]):
|
||||
assert a[i].commutator(a[j]) == iden
|
||||
assert a[j].commutator(a[i]) == iden
|
||||
|
||||
a = Permutation(3)
|
||||
b = Permutation(0, 6, 3)(1, 2)
|
||||
assert a.cycle_structure == {1: 4}
|
||||
assert b.cycle_structure == {2: 1, 3: 1, 1: 2}
|
||||
# issue 11130
|
||||
raises(ValueError, lambda: Permutation(3, size=3))
|
||||
raises(ValueError, lambda: Permutation([1, 2, 0, 3], size=3))
|
||||
|
||||
|
||||
def test_Permutation_subclassing():
|
||||
# Subclass that adds permutation application on iterables
|
||||
class CustomPermutation(Permutation):
|
||||
def __call__(self, *i):
|
||||
try:
|
||||
return super().__call__(*i)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
perm_obj = i[0]
|
||||
return [self._array_form[j] for j in perm_obj]
|
||||
except TypeError:
|
||||
raise TypeError('unrecognized argument')
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Permutation):
|
||||
return self._hashable_content() == other._hashable_content()
|
||||
else:
|
||||
return super().__eq__(other)
|
||||
|
||||
def __hash__(self):
|
||||
return super().__hash__()
|
||||
|
||||
p = CustomPermutation([1, 2, 3, 0])
|
||||
q = Permutation([1, 2, 3, 0])
|
||||
|
||||
assert p == q
|
||||
raises(TypeError, lambda: q([1, 2]))
|
||||
assert [2, 3] == p([1, 2])
|
||||
|
||||
assert type(p * q) == CustomPermutation
|
||||
assert type(q * p) == Permutation # True because q.__mul__(p) is called!
|
||||
|
||||
# Run all tests for the Permutation class also on the subclass
|
||||
def wrapped_test_Permutation():
|
||||
# Monkeypatch the class definition in the globals
|
||||
globals()['__Perm'] = globals()['Permutation']
|
||||
globals()['Permutation'] = CustomPermutation
|
||||
test_Permutation()
|
||||
globals()['Permutation'] = globals()['__Perm'] # Restore
|
||||
del globals()['__Perm']
|
||||
|
||||
wrapped_test_Permutation()
|
||||
|
||||
|
||||
def test_josephus():
|
||||
assert Permutation.josephus(4, 6, 1) == Permutation([3, 1, 0, 2, 5, 4])
|
||||
assert Permutation.josephus(1, 5, 1).is_Identity
|
||||
|
||||
|
||||
def test_ranking():
|
||||
assert Permutation.unrank_lex(5, 10).rank() == 10
|
||||
p = Permutation.unrank_lex(15, 225)
|
||||
assert p.rank() == 225
|
||||
p1 = p.next_lex()
|
||||
assert p1.rank() == 226
|
||||
assert Permutation.unrank_lex(15, 225).rank() == 225
|
||||
assert Permutation.unrank_lex(10, 0).is_Identity
|
||||
p = Permutation.unrank_lex(4, 23)
|
||||
assert p.rank() == 23
|
||||
assert p.array_form == [3, 2, 1, 0]
|
||||
assert p.next_lex() is None
|
||||
|
||||
p = Permutation([1, 5, 2, 0, 3, 6, 4])
|
||||
q = Permutation([[1, 2, 3, 5, 6], [0, 4]])
|
||||
a = [Permutation.unrank_trotterjohnson(4, i).array_form for i in range(5)]
|
||||
assert a == [[0, 1, 2, 3], [0, 1, 3, 2], [0, 3, 1, 2], [3, 0, 1,
|
||||
2], [3, 0, 2, 1] ]
|
||||
assert [Permutation(pa).rank_trotterjohnson() for pa in a] == list(range(5))
|
||||
assert Permutation([0, 1, 2, 3]).next_trotterjohnson() == \
|
||||
Permutation([0, 1, 3, 2])
|
||||
|
||||
assert q.rank_trotterjohnson() == 2283
|
||||
assert p.rank_trotterjohnson() == 3389
|
||||
assert Permutation([1, 0]).rank_trotterjohnson() == 1
|
||||
a = Permutation(list(range(3)))
|
||||
b = a
|
||||
l = []
|
||||
tj = []
|
||||
for i in range(6):
|
||||
l.append(a)
|
||||
tj.append(b)
|
||||
a = a.next_lex()
|
||||
b = b.next_trotterjohnson()
|
||||
assert a == b is None
|
||||
assert {tuple(a) for a in l} == {tuple(a) for a in tj}
|
||||
|
||||
p = Permutation([2, 5, 1, 6, 3, 0, 4])
|
||||
q = Permutation([[6], [5], [0, 1, 2, 3, 4]])
|
||||
assert p.rank() == 1964
|
||||
assert q.rank() == 870
|
||||
assert Permutation([]).rank_nonlex() == 0
|
||||
prank = p.rank_nonlex()
|
||||
assert prank == 1600
|
||||
assert Permutation.unrank_nonlex(7, 1600) == p
|
||||
qrank = q.rank_nonlex()
|
||||
assert qrank == 41
|
||||
assert Permutation.unrank_nonlex(7, 41) == Permutation(q.array_form)
|
||||
|
||||
a = [Permutation.unrank_nonlex(4, i).array_form for i in range(24)]
|
||||
assert a == [
|
||||
[1, 2, 3, 0], [3, 2, 0, 1], [1, 3, 0, 2], [1, 2, 0, 3], [2, 3, 1, 0],
|
||||
[2, 0, 3, 1], [3, 0, 1, 2], [2, 0, 1, 3], [1, 3, 2, 0], [3, 0, 2, 1],
|
||||
[1, 0, 3, 2], [1, 0, 2, 3], [2, 1, 3, 0], [2, 3, 0, 1], [3, 1, 0, 2],
|
||||
[2, 1, 0, 3], [3, 2, 1, 0], [0, 2, 3, 1], [0, 3, 1, 2], [0, 2, 1, 3],
|
||||
[3, 1, 2, 0], [0, 3, 2, 1], [0, 1, 3, 2], [0, 1, 2, 3]]
|
||||
|
||||
N = 10
|
||||
p1 = Permutation(a[0])
|
||||
for i in range(1, N+1):
|
||||
p1 = p1*Permutation(a[i])
|
||||
p2 = Permutation.rmul_with_af(*[Permutation(h) for h in a[N::-1]])
|
||||
assert p1 == p2
|
||||
|
||||
ok = []
|
||||
p = Permutation([1, 0])
|
||||
for i in range(3):
|
||||
ok.append(p.array_form)
|
||||
p = p.next_nonlex()
|
||||
if p is None:
|
||||
ok.append(None)
|
||||
break
|
||||
assert ok == [[1, 0], [0, 1], None]
|
||||
assert Permutation([3, 2, 0, 1]).next_nonlex() == Permutation([1, 3, 0, 2])
|
||||
assert [Permutation(pa).rank_nonlex() for pa in a] == list(range(24))
|
||||
|
||||
|
||||
def test_mul():
|
||||
a, b = [0, 2, 1, 3], [0, 1, 3, 2]
|
||||
assert _af_rmul(a, b) == [0, 2, 3, 1]
|
||||
assert _af_rmuln(a, b, list(range(4))) == [0, 2, 3, 1]
|
||||
assert rmul(Permutation(a), Permutation(b)).array_form == [0, 2, 3, 1]
|
||||
|
||||
a = Permutation([0, 2, 1, 3])
|
||||
b = (0, 1, 3, 2)
|
||||
c = (3, 1, 2, 0)
|
||||
assert Permutation.rmul(a, b, c) == Permutation([1, 2, 3, 0])
|
||||
assert Permutation.rmul(a, c) == Permutation([3, 2, 1, 0])
|
||||
raises(TypeError, lambda: Permutation.rmul(b, c))
|
||||
|
||||
n = 6
|
||||
m = 8
|
||||
a = [Permutation.unrank_nonlex(n, i).array_form for i in range(m)]
|
||||
h = list(range(n))
|
||||
for i in range(m):
|
||||
h = _af_rmul(h, a[i])
|
||||
h2 = _af_rmuln(*a[:i + 1])
|
||||
assert h == h2
|
||||
|
||||
|
||||
def test_args():
|
||||
p = Permutation([(0, 3, 1, 2), (4, 5)])
|
||||
assert p._cyclic_form is None
|
||||
assert Permutation(p) == p
|
||||
assert p.cyclic_form == [[0, 3, 1, 2], [4, 5]]
|
||||
assert p._array_form == [3, 2, 0, 1, 5, 4]
|
||||
p = Permutation((0, 3, 1, 2))
|
||||
assert p._cyclic_form is None
|
||||
assert p._array_form == [0, 3, 1, 2]
|
||||
assert Permutation([0]) == Permutation((0, ))
|
||||
assert Permutation([[0], [1]]) == Permutation(((0, ), (1, ))) == \
|
||||
Permutation(((0, ), [1]))
|
||||
assert Permutation([[1, 2]]) == Permutation([0, 2, 1])
|
||||
assert Permutation([[1], [4, 2]]) == Permutation([0, 1, 4, 3, 2])
|
||||
assert Permutation([[1], [4, 2]], size=1) == Permutation([0, 1, 4, 3, 2])
|
||||
assert Permutation(
|
||||
[[1], [4, 2]], size=6) == Permutation([0, 1, 4, 3, 2, 5])
|
||||
assert Permutation([[0, 1], [0, 2]]) == Permutation(0, 1, 2)
|
||||
assert Permutation([], size=3) == Permutation([0, 1, 2])
|
||||
assert Permutation(3).list(5) == [0, 1, 2, 3, 4]
|
||||
assert Permutation(3).list(-1) == []
|
||||
assert Permutation(5)(1, 2).list(-1) == [0, 2, 1]
|
||||
assert Permutation(5)(1, 2).list() == [0, 2, 1, 3, 4, 5]
|
||||
raises(ValueError, lambda: Permutation([1, 2], [0]))
|
||||
# enclosing brackets needed
|
||||
raises(ValueError, lambda: Permutation([[1, 2], 0]))
|
||||
# enclosing brackets needed on 0
|
||||
raises(ValueError, lambda: Permutation([1, 1, 0]))
|
||||
raises(ValueError, lambda: Permutation([4, 5], size=10)) # where are 0-3?
|
||||
# but this is ok because cycles imply that only those listed moved
|
||||
assert Permutation(4, 5) == Permutation([0, 1, 2, 3, 5, 4])
|
||||
|
||||
|
||||
def test_Cycle():
|
||||
assert str(Cycle()) == '()'
|
||||
assert Cycle(Cycle(1,2)) == Cycle(1, 2)
|
||||
assert Cycle(1,2).copy() == Cycle(1,2)
|
||||
assert list(Cycle(1, 3, 2)) == [0, 3, 1, 2]
|
||||
assert Cycle(1, 2)(2, 3) == Cycle(1, 3, 2)
|
||||
assert Cycle(1, 2)(2, 3)(4, 5) == Cycle(1, 3, 2)(4, 5)
|
||||
assert Permutation(Cycle(1, 2)(2, 1, 0, 3)).cyclic_form, Cycle(0, 2, 1)
|
||||
raises(ValueError, lambda: Cycle().list())
|
||||
assert Cycle(1, 2).list() == [0, 2, 1]
|
||||
assert Cycle(1, 2).list(4) == [0, 2, 1, 3]
|
||||
assert Cycle(3).list(2) == [0, 1]
|
||||
assert Cycle(3).list(6) == [0, 1, 2, 3, 4, 5]
|
||||
assert Permutation(Cycle(1, 2), size=4) == \
|
||||
Permutation([0, 2, 1, 3])
|
||||
assert str(Cycle(1, 2)(4, 5)) == '(1 2)(4 5)'
|
||||
assert str(Cycle(1, 2)) == '(1 2)'
|
||||
assert Cycle(Permutation(list(range(3)))) == Cycle()
|
||||
assert Cycle(1, 2).list() == [0, 2, 1]
|
||||
assert Cycle(1, 2).list(4) == [0, 2, 1, 3]
|
||||
assert Cycle().size == 0
|
||||
raises(ValueError, lambda: Cycle((1, 2)))
|
||||
raises(ValueError, lambda: Cycle(1, 2, 1))
|
||||
raises(TypeError, lambda: Cycle(1, 2)*{})
|
||||
raises(ValueError, lambda: Cycle(4)[a])
|
||||
raises(ValueError, lambda: Cycle(2, -4, 3))
|
||||
|
||||
# check round-trip
|
||||
p = Permutation([[1, 2], [4, 3]], size=5)
|
||||
assert Permutation(Cycle(p)) == p
|
||||
|
||||
|
||||
def test_from_sequence():
|
||||
assert Permutation.from_sequence('SymPy') == Permutation(4)(0, 1, 3)
|
||||
assert Permutation.from_sequence('SymPy', key=lambda x: x.lower()) == \
|
||||
Permutation(4)(0, 2)(1, 3)
|
||||
|
||||
|
||||
def test_resize():
|
||||
p = Permutation(0, 1, 2)
|
||||
assert p.resize(5) == Permutation(0, 1, 2, size=5)
|
||||
assert p.resize(4) == Permutation(0, 1, 2, size=4)
|
||||
assert p.resize(3) == p
|
||||
raises(ValueError, lambda: p.resize(2))
|
||||
|
||||
p = Permutation(0, 1, 2)(3, 4)(5, 6)
|
||||
assert p.resize(3) == Permutation(0, 1, 2)
|
||||
raises(ValueError, lambda: p.resize(4))
|
||||
|
||||
|
||||
def test_printing_cyclic():
|
||||
p1 = Permutation([0, 2, 1])
|
||||
assert repr(p1) == 'Permutation(1, 2)'
|
||||
assert str(p1) == '(1 2)'
|
||||
p2 = Permutation()
|
||||
assert repr(p2) == 'Permutation()'
|
||||
assert str(p2) == '()'
|
||||
p3 = Permutation([1, 2, 0, 3])
|
||||
assert repr(p3) == 'Permutation(3)(0, 1, 2)'
|
||||
|
||||
|
||||
def test_printing_non_cyclic():
|
||||
p1 = Permutation([0, 1, 2, 3, 4, 5])
|
||||
assert srepr(p1, perm_cyclic=False) == 'Permutation([], size=6)'
|
||||
assert sstr(p1, perm_cyclic=False) == 'Permutation([], size=6)'
|
||||
p2 = Permutation([0, 1, 2])
|
||||
assert srepr(p2, perm_cyclic=False) == 'Permutation([0, 1, 2])'
|
||||
assert sstr(p2, perm_cyclic=False) == 'Permutation([0, 1, 2])'
|
||||
|
||||
p3 = Permutation([0, 2, 1])
|
||||
assert srepr(p3, perm_cyclic=False) == 'Permutation([0, 2, 1])'
|
||||
assert sstr(p3, perm_cyclic=False) == 'Permutation([0, 2, 1])'
|
||||
p4 = Permutation([0, 1, 3, 2, 4, 5, 6, 7])
|
||||
assert srepr(p4, perm_cyclic=False) == 'Permutation([0, 1, 3, 2], size=8)'
|
||||
|
||||
|
||||
def test_deprecated_print_cyclic():
|
||||
p = Permutation(0, 1, 2)
|
||||
try:
|
||||
Permutation.print_cyclic = True
|
||||
with warns_deprecated_sympy():
|
||||
assert sstr(p) == '(0 1 2)'
|
||||
with warns_deprecated_sympy():
|
||||
assert srepr(p) == 'Permutation(0, 1, 2)'
|
||||
with warns_deprecated_sympy():
|
||||
assert pretty(p) == '(0 1 2)'
|
||||
with warns_deprecated_sympy():
|
||||
assert latex(p) == r'\left( 0\; 1\; 2\right)'
|
||||
|
||||
Permutation.print_cyclic = False
|
||||
with warns_deprecated_sympy():
|
||||
assert sstr(p) == 'Permutation([1, 2, 0])'
|
||||
with warns_deprecated_sympy():
|
||||
assert srepr(p) == 'Permutation([1, 2, 0])'
|
||||
with warns_deprecated_sympy():
|
||||
assert pretty(p, use_unicode=False) == '/0 1 2\\\n\\1 2 0/'
|
||||
with warns_deprecated_sympy():
|
||||
assert latex(p) == \
|
||||
r'\begin{pmatrix} 0 & 1 & 2 \\ 1 & 2 & 0 \end{pmatrix}'
|
||||
finally:
|
||||
Permutation.print_cyclic = None
|
||||
|
||||
|
||||
def test_permutation_equality():
|
||||
a = Permutation(0, 1, 2)
|
||||
b = Permutation(0, 1, 2)
|
||||
assert Eq(a, b) is S.true
|
||||
c = Permutation(0, 2, 1)
|
||||
assert Eq(a, c) is S.false
|
||||
|
||||
d = Permutation(0, 1, 2, size=4)
|
||||
assert unchanged(Eq, a, d)
|
||||
e = Permutation(0, 2, 1, size=4)
|
||||
assert unchanged(Eq, a, e)
|
||||
|
||||
i = Permutation()
|
||||
assert unchanged(Eq, i, 0)
|
||||
assert unchanged(Eq, 0, i)
|
||||
|
||||
|
||||
def test_issue_17661():
|
||||
c1 = Cycle(1,2)
|
||||
c2 = Cycle(1,2)
|
||||
assert c1 == c2
|
||||
assert repr(c1) == 'Cycle(1, 2)'
|
||||
assert c1 == c2
|
||||
|
||||
|
||||
def test_permutation_apply():
|
||||
x = Symbol('x')
|
||||
p = Permutation(0, 1, 2)
|
||||
assert p.apply(0) == 1
|
||||
assert isinstance(p.apply(0), Integer)
|
||||
assert p.apply(x) == AppliedPermutation(p, x)
|
||||
assert AppliedPermutation(p, x).subs(x, 0) == 1
|
||||
|
||||
x = Symbol('x', integer=False)
|
||||
raises(NotImplementedError, lambda: p.apply(x))
|
||||
x = Symbol('x', negative=True)
|
||||
raises(NotImplementedError, lambda: p.apply(x))
|
||||
|
||||
|
||||
def test_AppliedPermutation():
|
||||
x = Symbol('x')
|
||||
p = Permutation(0, 1, 2)
|
||||
raises(ValueError, lambda: AppliedPermutation((0, 1, 2), x))
|
||||
assert AppliedPermutation(p, 1, evaluate=True) == 2
|
||||
assert AppliedPermutation(p, 1, evaluate=False).__class__ == \
|
||||
AppliedPermutation
|
||||
@@ -0,0 +1,105 @@
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.sets.sets import FiniteSet
|
||||
from sympy.combinatorics.polyhedron import (Polyhedron,
|
||||
tetrahedron, cube as square, octahedron, dodecahedron, icosahedron,
|
||||
cube_faces)
|
||||
from sympy.combinatorics.permutations import Permutation
|
||||
from sympy.combinatorics.perm_groups import PermutationGroup
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
rmul = Permutation.rmul
|
||||
|
||||
|
||||
def test_polyhedron():
|
||||
raises(ValueError, lambda: Polyhedron(list('ab'),
|
||||
pgroup=[Permutation([0])]))
|
||||
pgroup = [Permutation([[0, 7, 2, 5], [6, 1, 4, 3]]),
|
||||
Permutation([[0, 7, 1, 6], [5, 2, 4, 3]]),
|
||||
Permutation([[3, 6, 0, 5], [4, 1, 7, 2]]),
|
||||
Permutation([[7, 4, 5], [1, 3, 0], [2], [6]]),
|
||||
Permutation([[1, 3, 2], [7, 6, 5], [4], [0]]),
|
||||
Permutation([[4, 7, 6], [2, 0, 3], [1], [5]]),
|
||||
Permutation([[1, 2, 0], [4, 5, 6], [3], [7]]),
|
||||
Permutation([[4, 2], [0, 6], [3, 7], [1, 5]]),
|
||||
Permutation([[3, 5], [7, 1], [2, 6], [0, 4]]),
|
||||
Permutation([[2, 5], [1, 6], [0, 4], [3, 7]]),
|
||||
Permutation([[4, 3], [7, 0], [5, 1], [6, 2]]),
|
||||
Permutation([[4, 1], [0, 5], [6, 2], [7, 3]]),
|
||||
Permutation([[7, 2], [3, 6], [0, 4], [1, 5]]),
|
||||
Permutation([0, 1, 2, 3, 4, 5, 6, 7])]
|
||||
corners = tuple(symbols('A:H'))
|
||||
faces = cube_faces
|
||||
cube = Polyhedron(corners, faces, pgroup)
|
||||
|
||||
assert cube.edges == FiniteSet(*(
|
||||
(0, 1), (6, 7), (1, 2), (5, 6), (0, 3), (2, 3),
|
||||
(4, 7), (4, 5), (3, 7), (1, 5), (0, 4), (2, 6)))
|
||||
|
||||
for i in range(3): # add 180 degree face rotations
|
||||
cube.rotate(cube.pgroup[i]**2)
|
||||
|
||||
assert cube.corners == corners
|
||||
|
||||
for i in range(3, 7): # add 240 degree axial corner rotations
|
||||
cube.rotate(cube.pgroup[i]**2)
|
||||
|
||||
assert cube.corners == corners
|
||||
cube.rotate(1)
|
||||
raises(ValueError, lambda: cube.rotate(Permutation([0, 1])))
|
||||
assert cube.corners != corners
|
||||
assert cube.array_form == [7, 6, 4, 5, 3, 2, 0, 1]
|
||||
assert cube.cyclic_form == [[0, 7, 1, 6], [2, 4, 3, 5]]
|
||||
cube.reset()
|
||||
assert cube.corners == corners
|
||||
|
||||
def check(h, size, rpt, target):
|
||||
|
||||
assert len(h.faces) + len(h.vertices) - len(h.edges) == 2
|
||||
assert h.size == size
|
||||
|
||||
got = set()
|
||||
for p in h.pgroup:
|
||||
# make sure it restores original
|
||||
P = h.copy()
|
||||
hit = P.corners
|
||||
for i in range(rpt):
|
||||
P.rotate(p)
|
||||
if P.corners == hit:
|
||||
break
|
||||
else:
|
||||
print('error in permutation', p.array_form)
|
||||
for i in range(rpt):
|
||||
P.rotate(p)
|
||||
got.add(tuple(P.corners))
|
||||
c = P.corners
|
||||
f = [[c[i] for i in f] for f in P.faces]
|
||||
assert h.faces == Polyhedron(c, f).faces
|
||||
assert len(got) == target
|
||||
assert PermutationGroup([Permutation(g) for g in got]).is_group
|
||||
|
||||
for h, size, rpt, target in zip(
|
||||
(tetrahedron, square, octahedron, dodecahedron, icosahedron),
|
||||
(4, 8, 6, 20, 12),
|
||||
(3, 4, 4, 5, 5),
|
||||
(12, 24, 24, 60, 60)):
|
||||
check(h, size, rpt, target)
|
||||
|
||||
|
||||
def test_pgroups():
|
||||
from sympy.combinatorics.polyhedron import (cube, tetrahedron_faces,
|
||||
octahedron_faces, dodecahedron_faces, icosahedron_faces)
|
||||
from sympy.combinatorics.polyhedron import _pgroup_calcs
|
||||
(tetrahedron2, cube2, octahedron2, dodecahedron2, icosahedron2,
|
||||
tetrahedron_faces2, cube_faces2, octahedron_faces2,
|
||||
dodecahedron_faces2, icosahedron_faces2) = _pgroup_calcs()
|
||||
|
||||
assert tetrahedron == tetrahedron2
|
||||
assert cube == cube2
|
||||
assert octahedron == octahedron2
|
||||
assert dodecahedron == dodecahedron2
|
||||
assert icosahedron == icosahedron2
|
||||
assert sorted(map(sorted, tetrahedron_faces)) == sorted(map(sorted, tetrahedron_faces2))
|
||||
assert sorted(cube_faces) == sorted(cube_faces2)
|
||||
assert sorted(octahedron_faces) == sorted(octahedron_faces2)
|
||||
assert sorted(dodecahedron_faces) == sorted(dodecahedron_faces2)
|
||||
assert sorted(icosahedron_faces) == sorted(icosahedron_faces2)
|
||||
@@ -0,0 +1,74 @@
|
||||
from sympy.combinatorics.prufer import Prufer
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_prufer():
|
||||
# number of nodes is optional
|
||||
assert Prufer([[0, 1], [0, 2], [0, 3], [0, 4]], 5).nodes == 5
|
||||
assert Prufer([[0, 1], [0, 2], [0, 3], [0, 4]]).nodes == 5
|
||||
|
||||
a = Prufer([[0, 1], [0, 2], [0, 3], [0, 4]])
|
||||
assert a.rank == 0
|
||||
assert a.nodes == 5
|
||||
assert a.prufer_repr == [0, 0, 0]
|
||||
|
||||
a = Prufer([[2, 4], [1, 4], [1, 3], [0, 5], [0, 4]])
|
||||
assert a.rank == 924
|
||||
assert a.nodes == 6
|
||||
assert a.tree_repr == [[2, 4], [1, 4], [1, 3], [0, 5], [0, 4]]
|
||||
assert a.prufer_repr == [4, 1, 4, 0]
|
||||
|
||||
assert Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) == \
|
||||
([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7)
|
||||
assert Prufer([0]*4).size == Prufer([6]*4).size == 1296
|
||||
|
||||
# accept iterables but convert to list of lists
|
||||
tree = [(0, 1), (1, 5), (0, 3), (0, 2), (2, 6), (4, 7), (2, 4)]
|
||||
tree_lists = [list(t) for t in tree]
|
||||
assert Prufer(tree).tree_repr == tree_lists
|
||||
assert sorted(Prufer(set(tree)).tree_repr) == sorted(tree_lists)
|
||||
|
||||
raises(ValueError, lambda: Prufer([[1, 2], [3, 4]])) # 0 is missing
|
||||
raises(ValueError, lambda: Prufer([[2, 3], [3, 4]])) # 0, 1 are missing
|
||||
assert Prufer(*Prufer.edges([1, 2], [3, 4])).prufer_repr == [1, 3]
|
||||
raises(ValueError, lambda: Prufer.edges(
|
||||
[1, 3], [3, 4])) # a broken tree but edges doesn't care
|
||||
raises(ValueError, lambda: Prufer.edges([1, 2], [5, 6]))
|
||||
raises(ValueError, lambda: Prufer([[]]))
|
||||
|
||||
a = Prufer([[0, 1], [0, 2], [0, 3]])
|
||||
b = a.next()
|
||||
assert b.tree_repr == [[0, 2], [0, 1], [1, 3]]
|
||||
assert b.rank == 1
|
||||
|
||||
|
||||
def test_round_trip():
|
||||
def doit(t, b):
|
||||
e, n = Prufer.edges(*t)
|
||||
t = Prufer(e, n)
|
||||
a = sorted(t.tree_repr)
|
||||
b = [i - 1 for i in b]
|
||||
assert t.prufer_repr == b
|
||||
assert sorted(Prufer(b).tree_repr) == a
|
||||
assert Prufer.unrank(t.rank, n).prufer_repr == b
|
||||
|
||||
doit([[1, 2]], [])
|
||||
doit([[2, 1, 3]], [1])
|
||||
doit([[1, 3, 2]], [3])
|
||||
doit([[1, 2, 3]], [2])
|
||||
doit([[2, 1, 4], [1, 3]], [1, 1])
|
||||
doit([[3, 2, 1, 4]], [2, 1])
|
||||
doit([[3, 2, 1], [2, 4]], [2, 2])
|
||||
doit([[1, 3, 2, 4]], [3, 2])
|
||||
doit([[1, 4, 2, 3]], [4, 2])
|
||||
doit([[3, 1, 4, 2]], [4, 1])
|
||||
doit([[4, 2, 1, 3]], [1, 2])
|
||||
doit([[1, 2, 4, 3]], [2, 4])
|
||||
doit([[1, 3, 4, 2]], [3, 4])
|
||||
doit([[2, 4, 1], [4, 3]], [4, 4])
|
||||
doit([[1, 2, 3, 4]], [2, 3])
|
||||
doit([[2, 3, 1], [3, 4]], [3, 3])
|
||||
doit([[1, 4, 3, 2]], [4, 3])
|
||||
doit([[2, 1, 4, 3]], [1, 4])
|
||||
doit([[2, 1, 3, 4]], [1, 3])
|
||||
doit([[6, 2, 1, 4], [1, 3, 5, 8], [3, 7]], [1, 2, 1, 3, 3, 5])
|
||||
@@ -0,0 +1,49 @@
|
||||
from sympy.combinatorics.fp_groups import FpGroup
|
||||
from sympy.combinatorics.free_groups import free_group
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_rewriting():
|
||||
F, a, b = free_group("a, b")
|
||||
G = FpGroup(F, [a*b*a**-1*b**-1])
|
||||
a, b = G.generators
|
||||
R = G._rewriting_system
|
||||
assert R.is_confluent
|
||||
|
||||
assert G.reduce(b**-1*a) == a*b**-1
|
||||
assert G.reduce(b**3*a**4*b**-2*a) == a**5*b
|
||||
assert G.equals(b**2*a**-1*b, b**4*a**-1*b**-1)
|
||||
|
||||
assert R.reduce_using_automaton(b*a*a**2*b**-1) == a**3
|
||||
assert R.reduce_using_automaton(b**3*a**4*b**-2*a) == a**5*b
|
||||
assert R.reduce_using_automaton(b**-1*a) == a*b**-1
|
||||
|
||||
G = FpGroup(F, [a**3, b**3, (a*b)**2])
|
||||
R = G._rewriting_system
|
||||
R.make_confluent()
|
||||
# R._is_confluent should be set to True after
|
||||
# a successful run of make_confluent
|
||||
assert R.is_confluent
|
||||
# but also the system should actually be confluent
|
||||
assert R._check_confluence()
|
||||
assert G.reduce(b*a**-1*b**-1*a**3*b**4*a**-1*b**-15) == a**-1*b**-1
|
||||
# check for automaton reduction
|
||||
assert R.reduce_using_automaton(b*a**-1*b**-1*a**3*b**4*a**-1*b**-15) == a**-1*b**-1
|
||||
|
||||
G = FpGroup(F, [a**2, b**3, (a*b)**4])
|
||||
R = G._rewriting_system
|
||||
assert G.reduce(a**2*b**-2*a**2*b) == b**-1
|
||||
assert R.reduce_using_automaton(a**2*b**-2*a**2*b) == b**-1
|
||||
assert G.reduce(a**3*b**-2*a**2*b) == a**-1*b**-1
|
||||
assert R.reduce_using_automaton(a**3*b**-2*a**2*b) == a**-1*b**-1
|
||||
# Check after adding a rule
|
||||
R.add_rule(a**2, b)
|
||||
assert R.reduce_using_automaton(a**2*b**-2*a**2*b) == b**-1
|
||||
assert R.reduce_using_automaton(a**4*b**-2*a**2*b**3) == b
|
||||
|
||||
R.set_max(15)
|
||||
raises(RuntimeError, lambda: R.add_rule(a**-3, b))
|
||||
R.set_max(20)
|
||||
R.add_rule(a**-3, b)
|
||||
|
||||
assert R.add_rule(a, a) == set()
|
||||
@@ -0,0 +1,55 @@
|
||||
from sympy.core import S, Rational
|
||||
from sympy.combinatorics.schur_number import schur_partition, SchurNumber
|
||||
from sympy.core.random import _randint
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.symbol import symbols
|
||||
|
||||
|
||||
def _sum_free_test(subset):
|
||||
"""
|
||||
Checks if subset is sum-free(There are no x,y,z in the subset such that
|
||||
x + y = z)
|
||||
"""
|
||||
for i in subset:
|
||||
for j in subset:
|
||||
assert (i + j in subset) is False
|
||||
|
||||
|
||||
def test_schur_partition():
|
||||
raises(ValueError, lambda: schur_partition(S.Infinity))
|
||||
raises(ValueError, lambda: schur_partition(-1))
|
||||
raises(ValueError, lambda: schur_partition(0))
|
||||
assert schur_partition(2) == [[1, 2]]
|
||||
|
||||
random_number_generator = _randint(1000)
|
||||
for _ in range(5):
|
||||
n = random_number_generator(1, 1000)
|
||||
result = schur_partition(n)
|
||||
t = 0
|
||||
numbers = []
|
||||
for item in result:
|
||||
_sum_free_test(item)
|
||||
"""
|
||||
Checks if the occurrence of all numbers is exactly one
|
||||
"""
|
||||
t += len(item)
|
||||
for l in item:
|
||||
assert (l in numbers) is False
|
||||
numbers.append(l)
|
||||
assert n == t
|
||||
|
||||
x = symbols("x")
|
||||
raises(ValueError, lambda: schur_partition(x))
|
||||
|
||||
def test_schur_number():
|
||||
first_known_schur_numbers = {1: 1, 2: 4, 3: 13, 4: 44, 5: 160}
|
||||
for k in first_known_schur_numbers:
|
||||
assert SchurNumber(k) == first_known_schur_numbers[k]
|
||||
|
||||
assert SchurNumber(S.Infinity) == S.Infinity
|
||||
assert SchurNumber(0) == 0
|
||||
raises(ValueError, lambda: SchurNumber(0.5))
|
||||
|
||||
n = symbols("n")
|
||||
assert SchurNumber(n).lower_bound() == 3**n/2 - Rational(1, 2)
|
||||
assert SchurNumber(8).lower_bound() == 5039
|
||||
@@ -0,0 +1,63 @@
|
||||
from sympy.combinatorics.subsets import Subset, ksubsets
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_subset():
|
||||
a = Subset(['c', 'd'], ['a', 'b', 'c', 'd'])
|
||||
assert a.next_binary() == Subset(['b'], ['a', 'b', 'c', 'd'])
|
||||
assert a.prev_binary() == Subset(['c'], ['a', 'b', 'c', 'd'])
|
||||
assert a.next_lexicographic() == Subset(['d'], ['a', 'b', 'c', 'd'])
|
||||
assert a.prev_lexicographic() == Subset(['c'], ['a', 'b', 'c', 'd'])
|
||||
assert a.next_gray() == Subset(['c'], ['a', 'b', 'c', 'd'])
|
||||
assert a.prev_gray() == Subset(['d'], ['a', 'b', 'c', 'd'])
|
||||
assert a.rank_binary == 3
|
||||
assert a.rank_lexicographic == 14
|
||||
assert a.rank_gray == 2
|
||||
assert a.cardinality == 16
|
||||
assert a.size == 2
|
||||
assert Subset.bitlist_from_subset(a, ['a', 'b', 'c', 'd']) == '0011'
|
||||
|
||||
a = Subset([2, 5, 7], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.next_binary() == Subset([2, 5, 6], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.prev_binary() == Subset([2, 5], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.next_lexicographic() == Subset([2, 6], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.prev_lexicographic() == Subset([2, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.next_gray() == Subset([2, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.prev_gray() == Subset([2, 5], [1, 2, 3, 4, 5, 6, 7])
|
||||
assert a.rank_binary == 37
|
||||
assert a.rank_lexicographic == 93
|
||||
assert a.rank_gray == 57
|
||||
assert a.cardinality == 128
|
||||
|
||||
superset = ['a', 'b', 'c', 'd']
|
||||
assert Subset.unrank_binary(4, superset).rank_binary == 4
|
||||
assert Subset.unrank_gray(10, superset).rank_gray == 10
|
||||
|
||||
superset = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
assert Subset.unrank_binary(33, superset).rank_binary == 33
|
||||
assert Subset.unrank_gray(25, superset).rank_gray == 25
|
||||
|
||||
a = Subset([], ['a', 'b', 'c', 'd'])
|
||||
i = 1
|
||||
while a.subset != Subset(['d'], ['a', 'b', 'c', 'd']).subset:
|
||||
a = a.next_lexicographic()
|
||||
i = i + 1
|
||||
assert i == 16
|
||||
|
||||
i = 1
|
||||
while a.subset != Subset([], ['a', 'b', 'c', 'd']).subset:
|
||||
a = a.prev_lexicographic()
|
||||
i = i + 1
|
||||
assert i == 16
|
||||
|
||||
raises(ValueError, lambda: Subset(['a', 'b'], ['a']))
|
||||
raises(ValueError, lambda: Subset(['a'], ['b', 'c']))
|
||||
raises(ValueError, lambda: Subset.subset_from_bitlist(['a', 'b'], '010'))
|
||||
|
||||
assert Subset(['a'], ['a', 'b']) != Subset(['b'], ['a', 'b'])
|
||||
assert Subset(['a'], ['a', 'b']) != Subset(['a'], ['a', 'c'])
|
||||
|
||||
def test_ksubsets():
|
||||
assert list(ksubsets([1, 2, 3], 2)) == [(1, 2), (1, 3), (2, 3)]
|
||||
assert list(ksubsets([1, 2, 3, 4, 5], 2)) == [(1, 2), (1, 3), (1, 4),
|
||||
(1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
|
||||
@@ -0,0 +1,560 @@
|
||||
from sympy.combinatorics.permutations import Permutation, Perm
|
||||
from sympy.combinatorics.tensor_can import (perm_af_direct_product, dummy_sgs,
|
||||
riemann_bsgs, get_symmetric_group_sgs, canonicalize, bsgs_direct_product)
|
||||
from sympy.combinatorics.testutil import canonicalize_naive, graph_certificate
|
||||
from sympy.testing.pytest import skip, XFAIL
|
||||
|
||||
def test_perm_af_direct_product():
|
||||
gens1 = [[1,0,2,3], [0,1,3,2]]
|
||||
gens2 = [[1,0]]
|
||||
assert perm_af_direct_product(gens1, gens2, 0) == [[1, 0, 2, 3, 4, 5], [0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 5, 4]]
|
||||
gens1 = [[1,0,2,3,5,4], [0,1,3,2,4,5]]
|
||||
gens2 = [[1,0,2,3]]
|
||||
assert [[1, 0, 2, 3, 4, 5, 7, 6], [0, 1, 3, 2, 4, 5, 6, 7], [0, 1, 2, 3, 5, 4, 6, 7]]
|
||||
|
||||
def test_dummy_sgs():
|
||||
a = dummy_sgs([1,2], 0, 4)
|
||||
assert a == [[0,2,1,3,4,5]]
|
||||
a = dummy_sgs([2,3,4,5], 0, 8)
|
||||
assert a == [x._array_form for x in [Perm(9)(2,3), Perm(9)(4,5),
|
||||
Perm(9)(2,4)(3,5)]]
|
||||
|
||||
a = dummy_sgs([2,3,4,5], 1, 8)
|
||||
assert a == [x._array_form for x in [Perm(2,3)(8,9), Perm(4,5)(8,9),
|
||||
Perm(9)(2,4)(3,5)]]
|
||||
|
||||
def test_get_symmetric_group_sgs():
|
||||
assert get_symmetric_group_sgs(2) == ([0], [Permutation(3)(0,1)])
|
||||
assert get_symmetric_group_sgs(2, 1) == ([0], [Permutation(0,1)(2,3)])
|
||||
assert get_symmetric_group_sgs(3) == ([0,1], [Permutation(4)(0,1), Permutation(4)(1,2)])
|
||||
assert get_symmetric_group_sgs(3, 1) == ([0,1], [Permutation(0,1)(3,4), Permutation(1,2)(3,4)])
|
||||
assert get_symmetric_group_sgs(4) == ([0,1,2], [Permutation(5)(0,1), Permutation(5)(1,2), Permutation(5)(2,3)])
|
||||
assert get_symmetric_group_sgs(4, 1) == ([0,1,2], [Permutation(0,1)(4,5), Permutation(1,2)(4,5), Permutation(2,3)(4,5)])
|
||||
|
||||
|
||||
def test_canonicalize_no_slot_sym():
|
||||
# cases in which there is no slot symmetry after fixing the
|
||||
# free indices; here and in the following if the symmetry of the
|
||||
# metric is not specified, it is assumed to be symmetric.
|
||||
# If it is not specified, tensors are commuting.
|
||||
|
||||
# A_d0 * B^d0; g = [1,0, 2,3]; T_c = A^d0*B_d0; can = [0,1,2,3]
|
||||
base1, gens1 = get_symmetric_group_sgs(1)
|
||||
dummies = [0, 1]
|
||||
g = Permutation([1,0,2,3])
|
||||
can = canonicalize(g, dummies, 0, (base1,gens1,1,0), (base1,gens1,1,0))
|
||||
assert can == [0,1,2,3]
|
||||
# equivalently
|
||||
can = canonicalize(g, dummies, 0, (base1, gens1, 2, None))
|
||||
assert can == [0,1,2,3]
|
||||
|
||||
# with antisymmetric metric; T_c = -A^d0*B_d0; can = [0,1,3,2]
|
||||
can = canonicalize(g, dummies, 1, (base1,gens1,1,0), (base1,gens1,1,0))
|
||||
assert can == [0,1,3,2]
|
||||
|
||||
# A^a * B^b; ord = [a,b]; g = [0,1,2,3]; can = g
|
||||
g = Permutation([0,1,2,3])
|
||||
dummies = []
|
||||
t0 = t1 = (base1, gens1, 1, 0)
|
||||
can = canonicalize(g, dummies, 0, t0, t1)
|
||||
assert can == [0,1,2,3]
|
||||
# B^b * A^a
|
||||
g = Permutation([1,0,2,3])
|
||||
can = canonicalize(g, dummies, 0, t0, t1)
|
||||
assert can == [1,0,2,3]
|
||||
|
||||
# A symmetric
|
||||
# A^{b}_{d0}*A^{d0, a} order a,b,d0,-d0; T_c = A^{a d0}*A{b}_{d0}
|
||||
# g = [1,3,2,0,4,5]; can = [0,2,1,3,4,5]
|
||||
base2, gens2 = get_symmetric_group_sgs(2)
|
||||
dummies = [2,3]
|
||||
g = Permutation([1,3,2,0,4,5])
|
||||
can = canonicalize(g, dummies, 0, (base2, gens2, 2, 0))
|
||||
assert can == [0, 2, 1, 3, 4, 5]
|
||||
# with antisymmetric metric
|
||||
can = canonicalize(g, dummies, 1, (base2, gens2, 2, 0))
|
||||
assert can == [0, 2, 1, 3, 4, 5]
|
||||
# A^{a}_{d0}*A^{d0, b}
|
||||
g = Permutation([0,3,2,1,4,5])
|
||||
can = canonicalize(g, dummies, 1, (base2, gens2, 2, 0))
|
||||
assert can == [0, 2, 1, 3, 5, 4]
|
||||
|
||||
# A, B symmetric
|
||||
# A^b_d0*B^{d0,a}; g=[1,3,2,0,4,5]
|
||||
# T_c = A^{b,d0}*B_{a,d0}; can = [1,2,0,3,4,5]
|
||||
dummies = [2,3]
|
||||
g = Permutation([1,3,2,0,4,5])
|
||||
can = canonicalize(g, dummies, 0, (base2,gens2,1,0), (base2,gens2,1,0))
|
||||
assert can == [1,2,0,3,4,5]
|
||||
# same with antisymmetric metric
|
||||
can = canonicalize(g, dummies, 1, (base2,gens2,1,0), (base2,gens2,1,0))
|
||||
assert can == [1,2,0,3,5,4]
|
||||
|
||||
# A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5]
|
||||
# T_c = A^{d0 d1}*B_d0*C_d1; can = [0,2,1,3,4,5]
|
||||
base1, gens1 = get_symmetric_group_sgs(1)
|
||||
base2, gens2 = get_symmetric_group_sgs(2)
|
||||
g = Permutation([2,1,0,3,4,5])
|
||||
dummies = [0,1,2,3]
|
||||
t0 = (base2, gens2, 1, 0)
|
||||
t1 = t2 = (base1, gens1, 1, 0)
|
||||
can = canonicalize(g, dummies, 0, t0, t1, t2)
|
||||
assert can == [0, 2, 1, 3, 4, 5]
|
||||
|
||||
# A without symmetry
|
||||
# A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5]
|
||||
# T_c = A^{d0 d1}*B_d1*C_d0; can = [0,2,3,1,4,5]
|
||||
g = Permutation([2,1,0,3,4,5])
|
||||
dummies = [0,1,2,3]
|
||||
t0 = ([], [Permutation(list(range(4)))], 1, 0)
|
||||
can = canonicalize(g, dummies, 0, t0, t1, t2)
|
||||
assert can == [0,2,3,1,4,5]
|
||||
# A, B without symmetry
|
||||
# A^{d1}_{d0}*B_{d1}^{d0}; g = [2,1,3,0,4,5]
|
||||
# T_c = A^{d0 d1}*B_{d0 d1}; can = [0,2,1,3,4,5]
|
||||
t0 = t1 = ([], [Permutation(list(range(4)))], 1, 0)
|
||||
dummies = [0,1,2,3]
|
||||
g = Permutation([2,1,3,0,4,5])
|
||||
can = canonicalize(g, dummies, 0, t0, t1)
|
||||
assert can == [0, 2, 1, 3, 4, 5]
|
||||
# A_{d0}^{d1}*B_{d1}^{d0}; g = [1,2,3,0,4,5]
|
||||
# T_c = A^{d0 d1}*B_{d1 d0}; can = [0,2,3,1,4,5]
|
||||
g = Permutation([1,2,3,0,4,5])
|
||||
can = canonicalize(g, dummies, 0, t0, t1)
|
||||
assert can == [0,2,3,1,4,5]
|
||||
|
||||
# A, B, C without symmetry
|
||||
# A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1]
|
||||
# g=[4,2,0,3,5,1,6,7]
|
||||
# T_c=A^{d0 d1}*B_{a d1}*C_{d0 b}; can = [2,4,0,5,3,1,6,7]
|
||||
t0 = t1 = t2 = ([], [Permutation(list(range(4)))], 1, 0)
|
||||
dummies = [2,3,4,5]
|
||||
g = Permutation([4,2,0,3,5,1,6,7])
|
||||
can = canonicalize(g, dummies, 0, t0, t1, t2)
|
||||
assert can == [2,4,0,5,3,1,6,7]
|
||||
|
||||
# A symmetric, B and C without symmetry
|
||||
# A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1]
|
||||
# g=[4,2,0,3,5,1,6,7]
|
||||
# T_c = A^{d0 d1}*B_{a d0}*C_{d1 b}; can = [2,4,0,3,5,1,6,7]
|
||||
t0 = (base2,gens2,1,0)
|
||||
t1 = t2 = ([], [Permutation(list(range(4)))], 1, 0)
|
||||
dummies = [2,3,4,5]
|
||||
g = Permutation([4,2,0,3,5,1,6,7])
|
||||
can = canonicalize(g, dummies, 0, t0, t1, t2)
|
||||
assert can == [2,4,0,3,5,1,6,7]
|
||||
|
||||
# A and C symmetric, B without symmetry
|
||||
# A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1]
|
||||
# g=[4,2,0,3,5,1,6,7]
|
||||
# T_c = A^{d0 d1}*B_{a d0}*C_{b d1}; can = [2,4,0,3,1,5,6,7]
|
||||
t0 = t2 = (base2,gens2,1,0)
|
||||
t1 = ([], [Permutation(list(range(4)))], 1, 0)
|
||||
dummies = [2,3,4,5]
|
||||
g = Permutation([4,2,0,3,5,1,6,7])
|
||||
can = canonicalize(g, dummies, 0, t0, t1, t2)
|
||||
assert can == [2,4,0,3,1,5,6,7]
|
||||
|
||||
# A symmetric, B without symmetry, C antisymmetric
|
||||
# A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1]
|
||||
# g=[4,2,0,3,5,1,6,7]
|
||||
# T_c = -A^{d0 d1}*B_{a d0}*C_{b d1}; can = [2,4,0,3,1,5,7,6]
|
||||
t0 = (base2,gens2, 1, 0)
|
||||
t1 = ([], [Permutation(list(range(4)))], 1, 0)
|
||||
base2a, gens2a = get_symmetric_group_sgs(2, 1)
|
||||
t2 = (base2a, gens2a, 1, 0)
|
||||
dummies = [2,3,4,5]
|
||||
g = Permutation([4,2,0,3,5,1,6,7])
|
||||
can = canonicalize(g, dummies, 0, t0, t1, t2)
|
||||
assert can == [2,4,0,3,1,5,7,6]
|
||||
|
||||
|
||||
def test_canonicalize_no_dummies():
|
||||
base1, gens1 = get_symmetric_group_sgs(1)
|
||||
base2, gens2 = get_symmetric_group_sgs(2)
|
||||
base2a, gens2a = get_symmetric_group_sgs(2, 1)
|
||||
|
||||
# A commuting
|
||||
# A^c A^b A^a; ord = [a,b,c]; g = [2,1,0,3,4]
|
||||
# T_c = A^a A^b A^c; can = list(range(5))
|
||||
g = Permutation([2,1,0,3,4])
|
||||
can = canonicalize(g, [], 0, (base1, gens1, 3, 0))
|
||||
assert can == list(range(5))
|
||||
|
||||
# A anticommuting
|
||||
# A^c A^b A^a; ord = [a,b,c]; g = [2,1,0,3,4]
|
||||
# T_c = -A^a A^b A^c; can = [0,1,2,4,3]
|
||||
g = Permutation([2,1,0,3,4])
|
||||
can = canonicalize(g, [], 0, (base1, gens1, 3, 1))
|
||||
assert can == [0,1,2,4,3]
|
||||
|
||||
# A commuting and symmetric
|
||||
# A^{b,d}*A^{c,a}; ord = [a,b,c,d]; g = [1,3,2,0,4,5]
|
||||
# T_c = A^{a c}*A^{b d}; can = [0,2,1,3,4,5]
|
||||
g = Permutation([1,3,2,0,4,5])
|
||||
can = canonicalize(g, [], 0, (base2, gens2, 2, 0))
|
||||
assert can == [0,2,1,3,4,5]
|
||||
|
||||
# A anticommuting and symmetric
|
||||
# A^{b,d}*A^{c,a}; ord = [a,b,c,d]; g = [1,3,2,0,4,5]
|
||||
# T_c = -A^{a c}*A^{b d}; can = [0,2,1,3,5,4]
|
||||
g = Permutation([1,3,2,0,4,5])
|
||||
can = canonicalize(g, [], 0, (base2, gens2, 2, 1))
|
||||
assert can == [0,2,1,3,5,4]
|
||||
# A^{c,a}*A^{b,d} ; g = [2,0,1,3,4,5]
|
||||
# T_c = A^{a c}*A^{b d}; can = [0,2,1,3,4,5]
|
||||
g = Permutation([2,0,1,3,4,5])
|
||||
can = canonicalize(g, [], 0, (base2, gens2, 2, 1))
|
||||
assert can == [0,2,1,3,4,5]
|
||||
|
||||
def test_no_metric_symmetry():
|
||||
# no metric symmetry
|
||||
# A^d1_d0 * A^d0_d1; ord = [d0,-d0,d1,-d1]; g= [2,1,0,3,4,5]
|
||||
# T_c = A^d0_d1 * A^d1_d0; can = [0,3,2,1,4,5]
|
||||
g = Permutation([2,1,0,3,4,5])
|
||||
can = canonicalize(g, list(range(4)), None, [[], [Permutation(list(range(4)))], 2, 0])
|
||||
assert can == [0,3,2,1,4,5]
|
||||
|
||||
# A^d1_d2 * A^d0_d3 * A^d2_d1 * A^d3_d0
|
||||
# ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3]
|
||||
# 0 1 2 3 4 5 6 7
|
||||
# g = [2,5,0,7,4,3,6,1,8,9]
|
||||
# T_c = A^d0_d1 * A^d1_d0 * A^d2_d3 * A^d3_d2
|
||||
# can = [0,3,2,1,4,7,6,5,8,9]
|
||||
g = Permutation([2,5,0,7,4,3,6,1,8,9])
|
||||
#can = canonicalize(g, list(range(8)), 0, [[], [list(range(4))], 4, 0])
|
||||
#assert can == [0, 2, 3, 1, 4, 6, 7, 5, 8, 9]
|
||||
can = canonicalize(g, list(range(8)), None, [[], [Permutation(list(range(4)))], 4, 0])
|
||||
assert can == [0, 3, 2, 1, 4, 7, 6, 5, 8, 9]
|
||||
|
||||
# A^d0_d2 * A^d1_d3 * A^d3_d0 * A^d2_d1
|
||||
# g = [0,5,2,7,6,1,4,3,8,9]
|
||||
# T_c = A^d0_d1 * A^d1_d2 * A^d2_d3 * A^d3_d0
|
||||
# can = [0,3,2,5,4,7,6,1,8,9]
|
||||
g = Permutation([0,5,2,7,6,1,4,3,8,9])
|
||||
can = canonicalize(g, list(range(8)), None, [[], [Permutation(list(range(4)))], 4, 0])
|
||||
assert can == [0,3,2,5,4,7,6,1,8,9]
|
||||
|
||||
g = Permutation([12,7,10,3,14,13,4,11,6,1,2,9,0,15,8,5,16,17])
|
||||
can = canonicalize(g, list(range(16)), None, [[], [Permutation(list(range(4)))], 8, 0])
|
||||
assert can == [0,3,2,5,4,7,6,1,8,11,10,13,12,15,14,9,16,17]
|
||||
|
||||
def test_canonical_free():
|
||||
# t = A^{d0 a1}*A_d0^a0
|
||||
# ord = [a0,a1,d0,-d0]; g = [2,1,3,0,4,5]; dummies = [[2,3]]
|
||||
# t_c = A_d0^a0*A^{d0 a1}
|
||||
# can = [3,0, 2,1, 4,5]
|
||||
g = Permutation([2,1,3,0,4,5])
|
||||
dummies = [[2,3]]
|
||||
can = canonicalize(g, dummies, [None], ([], [Permutation(3)], 2, 0))
|
||||
assert can == [3,0, 2,1, 4,5]
|
||||
|
||||
def test_canonicalize1():
|
||||
base1, gens1 = get_symmetric_group_sgs(1)
|
||||
base1a, gens1a = get_symmetric_group_sgs(1, 1)
|
||||
base2, gens2 = get_symmetric_group_sgs(2)
|
||||
base3, gens3 = get_symmetric_group_sgs(3)
|
||||
base2a, gens2a = get_symmetric_group_sgs(2, 1)
|
||||
base3a, gens3a = get_symmetric_group_sgs(3, 1)
|
||||
|
||||
# A_d0*A^d0; ord = [d0,-d0]; g = [1,0,2,3]
|
||||
# T_c = A^d0*A_d0; can = [0,1,2,3]
|
||||
g = Permutation([1,0,2,3])
|
||||
can = canonicalize(g, [0, 1], 0, (base1, gens1, 2, 0))
|
||||
assert can == list(range(4))
|
||||
|
||||
# A commuting
|
||||
# A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2]
|
||||
# g = [1,3,5,4,2,0,6,7]
|
||||
# T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2; can = list(range(8))
|
||||
g = Permutation([1,3,5,4,2,0,6,7])
|
||||
can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 0))
|
||||
assert can == list(range(8))
|
||||
|
||||
# A anticommuting
|
||||
# A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2]
|
||||
# g = [1,3,5,4,2,0,6,7]
|
||||
# T_c 0; can = 0
|
||||
g = Permutation([1,3,5,4,2,0,6,7])
|
||||
can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 1))
|
||||
assert can == 0
|
||||
can1 = canonicalize_naive(g, list(range(6)), 0, (base1, gens1, 6, 1))
|
||||
assert can1 == 0
|
||||
|
||||
# A commuting symmetric
|
||||
# A^{d0 b}*A^a_d1*A^d1_d0; ord=[a,b,d0,-d0,d1,-d1]
|
||||
# g = [2,1,0,5,4,3,6,7]
|
||||
# T_c = A^{a d0}*A^{b d1}*A_{d0 d1}; can = [0,2,1,4,3,5,6,7]
|
||||
g = Permutation([2,1,0,5,4,3,6,7])
|
||||
can = canonicalize(g, list(range(2,6)), 0, (base2, gens2, 3, 0))
|
||||
assert can == [0,2,1,4,3,5,6,7]
|
||||
|
||||
# A, B commuting symmetric
|
||||
# A^{d0 b}*A^d1_d0*B^a_d1; ord=[a,b,d0,-d0,d1,-d1]
|
||||
# g = [2,1,4,3,0,5,6,7]
|
||||
# T_c = A^{b d0}*A_d0^d1*B^a_d1; can = [1,2,3,4,0,5,6,7]
|
||||
g = Permutation([2,1,4,3,0,5,6,7])
|
||||
can = canonicalize(g, list(range(2,6)), 0, (base2,gens2,2,0), (base2,gens2,1,0))
|
||||
assert can == [1,2,3,4,0,5,6,7]
|
||||
|
||||
# A commuting symmetric
|
||||
# A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1]
|
||||
# g = [4,2,1,0,5,3,6,7]
|
||||
# T_c = A^{a d0 d1}*A^{b}_{d0 d1}; can = [0,2,4,1,3,5,6,7]
|
||||
g = Permutation([4,2,1,0,5,3,6,7])
|
||||
can = canonicalize(g, list(range(2,6)), 0, (base3, gens3, 2, 0))
|
||||
assert can == [0,2,4,1,3,5,6,7]
|
||||
|
||||
|
||||
# A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0
|
||||
# ord = [a0,a1,a2,a3,d0,-d0,d1,-d1,d2,-d2,d3,-d3]
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
# g = [10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13]
|
||||
# T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3}
|
||||
# can = [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13]
|
||||
g = Permutation([10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13])
|
||||
can = canonicalize(g, list(range(4,12)), 0, (base3, gens3, 4, 0))
|
||||
assert can == [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13]
|
||||
|
||||
# A commuting symmetric, B antisymmetric
|
||||
# A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3
|
||||
# ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3]
|
||||
# g = [0,2,4,5,7,3,1,6,8,9]
|
||||
# in this esxample and in the next three,
|
||||
# renaming dummy indices and using symmetry of A,
|
||||
# T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3
|
||||
# can = 0
|
||||
g = Permutation([0,2,4,5,7,3,1,6,8,9])
|
||||
can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,0), (base2a,gens2a,1,0))
|
||||
assert can == 0
|
||||
# A anticommuting symmetric, B anticommuting
|
||||
# A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3
|
||||
# T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3}
|
||||
# can = [0,2,4, 1,3,6, 5,7, 8,9]
|
||||
can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,1), (base2a,gens2a,1,0))
|
||||
assert can == [0,2,4, 1,3,6, 5,7, 8,9]
|
||||
# A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric
|
||||
# A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3
|
||||
# T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3}
|
||||
# can = [0,2,4, 1,3,6, 5,7, 9,8]
|
||||
can = canonicalize(g, list(range(8)), 1, (base3, gens3,2,1), (base2a,gens2a,1,0))
|
||||
assert can == [0,2,4, 1,3,6, 5,7, 9,8]
|
||||
|
||||
# A anticommuting symmetric, B anticommuting anticommuting,
|
||||
# no metric symmetry
|
||||
# A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3
|
||||
# T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3
|
||||
# can = [0,2,4, 1,3,7, 5,6, 8,9]
|
||||
can = canonicalize(g, list(range(8)), None, (base3, gens3,2,1), (base2a,gens2a,1,0))
|
||||
assert can == [0,2,4,1,3,7,5,6,8,9]
|
||||
|
||||
# Gamma anticommuting
|
||||
# Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha}
|
||||
# ord = [alpha, rho, mu,-mu,nu,-nu]
|
||||
# g = [3,5,1,4,2,0,6,7]
|
||||
# T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu}
|
||||
# can = [2,4,1,0,3,5,7,6]]
|
||||
g = Permutation([3,5,1,4,2,0,6,7])
|
||||
t0 = (base2a, gens2a, 1, None)
|
||||
t1 = (base1, gens1, 1, None)
|
||||
t2 = (base3a, gens3a, 1, None)
|
||||
can = canonicalize(g, list(range(2, 6)), 0, t0, t1, t2)
|
||||
assert can == [2,4,1,0,3,5,7,6]
|
||||
|
||||
# Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha}
|
||||
# ord = [alpha, beta, gamma, -rho, mu,-mu,nu,-nu]
|
||||
# 0 1 2 3 4 5 6 7
|
||||
# g = [5,7,2,1,3,6,4,0,8,9]
|
||||
# T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} # can = [4,6,1,2,3,0,5,7,8,9]
|
||||
t0 = (base2a, gens2a, 2, None)
|
||||
g = Permutation([5,7,2,1,3,6,4,0,8,9])
|
||||
can = canonicalize(g, list(range(4, 8)), 0, t0, t1, t2)
|
||||
assert can == [4,6,1,2,3,0,5,7,8,9]
|
||||
|
||||
# f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry
|
||||
# f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b}
|
||||
# ord = [mu,-mu,nu,-nu,a,-a,b,-b,c,-c,d,-d, e, -e]
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
# g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15]
|
||||
# T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e}
|
||||
# can = [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14]
|
||||
g = Permutation([8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15])
|
||||
base_f, gens_f = bsgs_direct_product(base1, gens1, base2a, gens2a)
|
||||
base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1)
|
||||
t0 = (base_f, gens_f, 2, 0)
|
||||
t1 = (base_A, gens_A, 4, 0)
|
||||
can = canonicalize(g, [list(range(4)), list(range(4, 14))], [0, 0], t0, t1)
|
||||
assert can == [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14]
|
||||
|
||||
|
||||
def test_riemann_invariants():
|
||||
baser, gensr = riemann_bsgs
|
||||
# R^{d0 d1}_{d1 d0}; ord = [d0,-d0,d1,-d1]; g = [0,2,3,1,4,5]
|
||||
# T_c = -R^{d0 d1}_{d0 d1}; can = [0,2,1,3,5,4]
|
||||
g = Permutation([0,2,3,1,4,5])
|
||||
can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0))
|
||||
assert can == [0,2,1,3,5,4]
|
||||
# use a non minimal BSGS
|
||||
can = canonicalize(g, list(range(2, 4)), 0, ([2, 0], [Permutation([1,0,2,3,5,4]), Permutation([2,3,0,1,4,5])], 1, 0))
|
||||
assert can == [0,2,1,3,5,4]
|
||||
|
||||
"""
|
||||
The following tests in test_riemann_invariants and in
|
||||
test_riemann_invariants1 have been checked using xperm.c from XPerm in
|
||||
in [1] and with an older version contained in [2]
|
||||
|
||||
[1] xperm.c part of xPerm written by J. M. Martin-Garcia
|
||||
http://www.xact.es/index.html
|
||||
[2] test_xperm.cc in cadabra by Kasper Peeters, http://cadabra.phi-sci.com/
|
||||
"""
|
||||
# R_d11^d1_d0^d5 * R^{d6 d4 d0}_d5 * R_{d7 d2 d8 d9} *
|
||||
# R_{d10 d3 d6 d4} * R^{d2 d7 d11}_d1 * R^{d8 d9 d3 d10}
|
||||
# ord: contravariant d_k ->2*k, covariant d_k -> 2*k+1
|
||||
# T_c = R^{d0 d1 d2 d3} * R_{d0 d1}^{d4 d5} * R_{d2 d3}^{d6 d7} *
|
||||
# R_{d4 d5}^{d8 d9} * R_{d6 d7}^{d10 d11} * R_{d8 d9 d10 d11}
|
||||
g = Permutation([23,2,1,10,12,8,0,11,15,5,17,19,21,7,13,9,4,14,22,3,16,18,6,20,24,25])
|
||||
can = canonicalize(g, list(range(24)), 0, (baser, gensr, 6, 0))
|
||||
assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,21,23,24,25]
|
||||
|
||||
# use a non minimal BSGS
|
||||
can = canonicalize(g, list(range(24)), 0, ([2, 0], [Permutation([1,0,2,3,5,4]), Permutation([2,3,0,1,4,5])], 6, 0))
|
||||
assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,21,23,24,25]
|
||||
|
||||
g = Permutation([0,2,5,7,4,6,9,11,8,10,13,15,12,14,17,19,16,18,21,23,20,22,25,27,24,26,29,31,28,30,33,35,32,34,37,39,36,38,1,3,40,41])
|
||||
can = canonicalize(g, list(range(40)), 0, (baser, gensr, 10, 0))
|
||||
assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,24,26,21,23,28,30,25,27,32,34,29,31,36,38,33,35,37,39,40,41]
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_riemann_invariants1():
|
||||
skip('takes too much time')
|
||||
baser, gensr = riemann_bsgs
|
||||
g = Permutation([17, 44, 11, 3, 0, 19, 23, 15, 38, 4, 25, 27, 43, 36, 22, 14, 8, 30, 41, 20, 2, 10, 12, 28, 18, 1, 29, 13, 37, 42, 33, 7, 9, 31, 24, 26, 39, 5, 34, 47, 32, 6, 21, 40, 35, 46, 45, 16, 48, 49])
|
||||
can = canonicalize(g, list(range(48)), 0, (baser, gensr, 12, 0))
|
||||
assert can == [0, 2, 4, 6, 1, 3, 8, 10, 5, 7, 12, 14, 9, 11, 16, 18, 13, 15, 20, 22, 17, 19, 24, 26, 21, 23, 28, 30, 25, 27, 32, 34, 29, 31, 36, 38, 33, 35, 40, 42, 37, 39, 44, 46, 41, 43, 45, 47, 48, 49]
|
||||
|
||||
g = Permutation([0,2,4,6, 7,8,10,12, 14,16,18,20, 19,22,24,26, 5,21,28,30, 32,34,36,38, 40,42,44,46, 13,48,50,52, 15,49,54,56, 17,33,41,58, 9,23,60,62, 29,35,63,64, 3,45,66,68, 25,37,47,57, 11,31,69,70, 27,39,53,72, 1,59,73,74, 55,61,67,76, 43,65,75,78, 51,71,77,79, 80,81])
|
||||
can = canonicalize(g, list(range(80)), 0, (baser, gensr, 20, 0))
|
||||
assert can == [0,2,4,6, 1,8,10,12, 3,14,16,18, 5,20,22,24, 7,26,28,30, 9,15,32,34, 11,36,23,38, 13,40,42,44, 17,39,29,46, 19,48,43,50, 21,45,52,54, 25,56,33,58, 27,60,53,62, 31,51,64,66, 35,65,47,68, 37,70,49,72, 41,74,57,76, 55,67,59,78, 61,69,71,75, 63,79,73,77, 80,81]
|
||||
|
||||
|
||||
def test_riemann_products():
|
||||
baser, gensr = riemann_bsgs
|
||||
base1, gens1 = get_symmetric_group_sgs(1)
|
||||
base2, gens2 = get_symmetric_group_sgs(2)
|
||||
base2a, gens2a = get_symmetric_group_sgs(2, 1)
|
||||
|
||||
# R^{a b d0}_d0 = 0
|
||||
g = Permutation([0,1,2,3,4,5])
|
||||
can = canonicalize(g, list(range(2,4)), 0, (baser, gensr, 1, 0))
|
||||
assert can == 0
|
||||
|
||||
# R^{d0 b a}_d0 ; ord = [a,b,d0,-d0}; g = [2,1,0,3,4,5]
|
||||
# T_c = -R^{a d0 b}_d0; can = [0,2,1,3,5,4]
|
||||
g = Permutation([2,1,0,3,4,5])
|
||||
can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0))
|
||||
assert can == [0,2,1,3,5,4]
|
||||
|
||||
# R^d1_d2^b_d0 * R^{d0 a}_d1^d2; ord=[a,b,d0,-d0,d1,-d1,d2,-d2]
|
||||
# g = [4,7,1,3,2,0,5,6,8,9]
|
||||
# T_c = -R^{a d0 d1 d2}* R^b_{d0 d1 d2}
|
||||
# can = [0,2,4,6,1,3,5,7,9,8]
|
||||
g = Permutation([4,7,1,3,2,0,5,6,8,9])
|
||||
can = canonicalize(g, list(range(2,8)), 0, (baser, gensr, 2, 0))
|
||||
assert can == [0,2,4,6,1,3,5,7,9,8]
|
||||
can1 = canonicalize_naive(g, list(range(2,8)), 0, (baser, gensr, 2, 0))
|
||||
assert can == can1
|
||||
|
||||
# A symmetric commuting
|
||||
# R^{d6 d5}_d2^d1 * R^{d4 d0 d2 d3} * A_{d6 d0} A_{d3 d1} * A_{d4 d5}
|
||||
# g = [12,10,5,2, 8,0,4,6, 13,1, 7,3, 9,11,14,15]
|
||||
# T_c = -R^{d0 d1 d2 d3} * R_d0^{d4 d5 d6} * A_{d1 d4}*A_{d2 d5}*A_{d3 d6}
|
||||
|
||||
g = Permutation([12,10,5,2,8,0,4,6,13,1,7,3,9,11,14,15])
|
||||
can = canonicalize(g, list(range(14)), 0, ((baser,gensr,2,0)), (base2,gens2,3,0))
|
||||
assert can == [0, 2, 4, 6, 1, 8, 10, 12, 3, 9, 5, 11, 7, 13, 15, 14]
|
||||
|
||||
# R^{d2 a0 a2 d0} * R^d1_d2^{a1 a3} * R^{a4 a5}_{d0 d1}
|
||||
# ord = [a0,a1,a2,a3,a4,a5,d0,-d0,d1,-d1,d2,-d2]
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
# can = [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13]
|
||||
# T_c = R^{a0 d0 a2 d1}*R^{a1 a3}_d0^d2*R^{a4 a5}_{d1 d2}
|
||||
g = Permutation([10,0,2,6,8,11,1,3,4,5,7,9,12,13])
|
||||
can = canonicalize(g, list(range(6,12)), 0, (baser, gensr, 3, 0))
|
||||
assert can == [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13]
|
||||
#can1 = canonicalize_naive(g, list(range(6,12)), 0, (baser, gensr, 3, 0))
|
||||
#assert can == can1
|
||||
|
||||
# A^n_{i, j} antisymmetric in i,j
|
||||
# A_m0^d0_a1 * A_m1^a0_d0; ord = [m0,m1,a0,a1,d0,-d0]
|
||||
# g = [0,4,3,1,2,5,6,7]
|
||||
# T_c = -A_{m a1}^d0 * A_m1^a0_d0
|
||||
# can = [0,3,4,1,2,5,7,6]
|
||||
base, gens = bsgs_direct_product(base1, gens1, base2a, gens2a)
|
||||
dummies = list(range(4, 6))
|
||||
g = Permutation([0,4,3,1,2,5,6,7])
|
||||
can = canonicalize(g, dummies, 0, (base, gens, 2, 0))
|
||||
assert can == [0, 3, 4, 1, 2, 5, 7, 6]
|
||||
|
||||
|
||||
# A^n_{i, j} symmetric in i,j
|
||||
# A^m0_a0^d2 * A^n0_d2^d1 * A^n1_d1^d0 * A_{m0 d0}^a1
|
||||
# ordering: first the free indices; then first n, then d
|
||||
# ord=[n0,n1,a0,a1, m0,-m0,d0,-d0,d1,-d1,d2,-d2]
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11]
|
||||
# g = [4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13]
|
||||
# if the dummy indices m_i and d_i were separated,
|
||||
# one gets
|
||||
# T_c = A^{n0 d0 d1} * A^n1_d0^d2 * A^m0^a0_d1 * A_m0^a1_d2
|
||||
# can = [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13]
|
||||
# If they are not, so can is
|
||||
# T_c = A^{n0 m0 d0} A^n1_m0^d1 A^{d2 a0}_d0 A_d2^a1_d1
|
||||
# can = [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13]
|
||||
# case with single type of indices
|
||||
|
||||
base, gens = bsgs_direct_product(base1, gens1, base2, gens2)
|
||||
dummies = list(range(4, 12))
|
||||
g = Permutation([4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13])
|
||||
can = canonicalize(g, dummies, 0, (base, gens, 4, 0))
|
||||
assert can == [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13]
|
||||
# case with separated indices
|
||||
dummies = [list(range(4, 6)), list(range(6,12))]
|
||||
sym = [0, 0]
|
||||
can = canonicalize(g, dummies, sym, (base, gens, 4, 0))
|
||||
assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13]
|
||||
# case with separated indices with the second type of index
|
||||
# with antisymmetric metric: there is a sign change
|
||||
sym = [0, 1]
|
||||
can = canonicalize(g, dummies, sym, (base, gens, 4, 0))
|
||||
assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 13, 12]
|
||||
|
||||
def test_graph_certificate():
|
||||
# test tensor invariants constructed from random regular graphs;
|
||||
# checked graph isomorphism with networkx
|
||||
import random
|
||||
def randomize_graph(size, g):
|
||||
p = list(range(size))
|
||||
random.shuffle(p)
|
||||
g1a = {}
|
||||
for k, v in g1.items():
|
||||
g1a[p[k]] = [p[i] for i in v]
|
||||
return g1a
|
||||
|
||||
g1 = {0: [2, 3, 7], 1: [4, 5, 7], 2: [0, 4, 6], 3: [0, 6, 7], 4: [1, 2, 5], 5: [1, 4, 6], 6: [2, 3, 5], 7: [0, 1, 3]}
|
||||
g2 = {0: [2, 3, 7], 1: [2, 4, 5], 2: [0, 1, 5], 3: [0, 6, 7], 4: [1, 5, 6], 5: [1, 2, 4], 6: [3, 4, 7], 7: [0, 3, 6]}
|
||||
|
||||
c1 = graph_certificate(g1)
|
||||
c2 = graph_certificate(g2)
|
||||
assert c1 != c2
|
||||
g1a = randomize_graph(8, g1)
|
||||
c1a = graph_certificate(g1a)
|
||||
assert c1 == c1a
|
||||
|
||||
g1 = {0: [8, 1, 9, 7], 1: [0, 9, 3, 4], 2: [3, 4, 6, 7], 3: [1, 2, 5, 6], 4: [8, 1, 2, 5], 5: [9, 3, 4, 7], 6: [8, 2, 3, 7], 7: [0, 2, 5, 6], 8: [0, 9, 4, 6], 9: [8, 0, 5, 1]}
|
||||
g2 = {0: [1, 2, 5, 6], 1: [0, 9, 5, 7], 2: [0, 4, 6, 7], 3: [8, 9, 6, 7], 4: [8, 2, 6, 7], 5: [0, 9, 8, 1], 6: [0, 2, 3, 4], 7: [1, 2, 3, 4], 8: [9, 3, 4, 5], 9: [8, 1, 3, 5]}
|
||||
c1 = graph_certificate(g1)
|
||||
c2 = graph_certificate(g2)
|
||||
assert c1 != c2
|
||||
g1a = randomize_graph(10, g1)
|
||||
c1a = graph_certificate(g1a)
|
||||
assert c1 == c1a
|
||||
@@ -0,0 +1,55 @@
|
||||
from sympy.combinatorics.named_groups import SymmetricGroup, AlternatingGroup,\
|
||||
CyclicGroup
|
||||
from sympy.combinatorics.testutil import _verify_bsgs, _cmp_perm_lists,\
|
||||
_naive_list_centralizer, _verify_centralizer,\
|
||||
_verify_normal_closure
|
||||
from sympy.combinatorics.permutations import Permutation
|
||||
from sympy.combinatorics.perm_groups import PermutationGroup
|
||||
from sympy.core.random import shuffle
|
||||
|
||||
|
||||
def test_cmp_perm_lists():
|
||||
S = SymmetricGroup(4)
|
||||
els = list(S.generate_dimino())
|
||||
other = els.copy()
|
||||
shuffle(other)
|
||||
assert _cmp_perm_lists(els, other) is True
|
||||
|
||||
|
||||
def test_naive_list_centralizer():
|
||||
# verified by GAP
|
||||
S = SymmetricGroup(3)
|
||||
A = AlternatingGroup(3)
|
||||
assert _naive_list_centralizer(S, S) == [Permutation([0, 1, 2])]
|
||||
assert PermutationGroup(_naive_list_centralizer(S, A)).is_subgroup(A)
|
||||
|
||||
|
||||
def test_verify_bsgs():
|
||||
S = SymmetricGroup(5)
|
||||
S.schreier_sims()
|
||||
base = S.base
|
||||
strong_gens = S.strong_gens
|
||||
assert _verify_bsgs(S, base, strong_gens) is True
|
||||
assert _verify_bsgs(S, base[:-1], strong_gens) is False
|
||||
assert _verify_bsgs(S, base, S.generators) is False
|
||||
|
||||
|
||||
def test_verify_centralizer():
|
||||
# verified by GAP
|
||||
S = SymmetricGroup(3)
|
||||
A = AlternatingGroup(3)
|
||||
triv = PermutationGroup([Permutation([0, 1, 2])])
|
||||
assert _verify_centralizer(S, S, centr=triv)
|
||||
assert _verify_centralizer(S, A, centr=A)
|
||||
|
||||
|
||||
def test_verify_normal_closure():
|
||||
# verified by GAP
|
||||
S = SymmetricGroup(3)
|
||||
A = AlternatingGroup(3)
|
||||
assert _verify_normal_closure(S, A, closure=A)
|
||||
S = SymmetricGroup(5)
|
||||
A = AlternatingGroup(5)
|
||||
C = CyclicGroup(5)
|
||||
assert _verify_normal_closure(S, A, closure=A)
|
||||
assert _verify_normal_closure(S, C, closure=A)
|
||||
@@ -0,0 +1,120 @@
|
||||
from sympy.combinatorics.named_groups import SymmetricGroup, DihedralGroup,\
|
||||
AlternatingGroup
|
||||
from sympy.combinatorics.permutations import Permutation
|
||||
from sympy.combinatorics.util import _check_cycles_alt_sym, _strip,\
|
||||
_distribute_gens_by_base, _strong_gens_from_distr,\
|
||||
_orbits_transversals_from_bsgs, _handle_precomputed_bsgs, _base_ordering,\
|
||||
_remove_gens
|
||||
from sympy.combinatorics.testutil import _verify_bsgs
|
||||
|
||||
|
||||
def test_check_cycles_alt_sym():
|
||||
perm1 = Permutation([[0, 1, 2, 3, 4, 5, 6], [7], [8], [9]])
|
||||
perm2 = Permutation([[0, 1, 2, 3, 4, 5], [6, 7, 8, 9]])
|
||||
perm3 = Permutation([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
|
||||
assert _check_cycles_alt_sym(perm1) is True
|
||||
assert _check_cycles_alt_sym(perm2) is False
|
||||
assert _check_cycles_alt_sym(perm3) is False
|
||||
|
||||
|
||||
def test_strip():
|
||||
D = DihedralGroup(5)
|
||||
D.schreier_sims()
|
||||
member = Permutation([4, 0, 1, 2, 3])
|
||||
not_member1 = Permutation([0, 1, 4, 3, 2])
|
||||
not_member2 = Permutation([3, 1, 4, 2, 0])
|
||||
identity = Permutation([0, 1, 2, 3, 4])
|
||||
res1 = _strip(member, D.base, D.basic_orbits, D.basic_transversals)
|
||||
res2 = _strip(not_member1, D.base, D.basic_orbits, D.basic_transversals)
|
||||
res3 = _strip(not_member2, D.base, D.basic_orbits, D.basic_transversals)
|
||||
assert res1[0] == identity
|
||||
assert res1[1] == len(D.base) + 1
|
||||
assert res2[0] == not_member1
|
||||
assert res2[1] == len(D.base) + 1
|
||||
assert res3[0] != identity
|
||||
assert res3[1] == 2
|
||||
|
||||
|
||||
def test_distribute_gens_by_base():
|
||||
base = [0, 1, 2]
|
||||
gens = [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2]),
|
||||
Permutation([0, 2, 3, 1]), Permutation([3, 2, 1, 0])]
|
||||
assert _distribute_gens_by_base(base, gens) == [gens,
|
||||
[Permutation([0, 1, 2, 3]),
|
||||
Permutation([0, 1, 3, 2]),
|
||||
Permutation([0, 2, 3, 1])],
|
||||
[Permutation([0, 1, 2, 3]),
|
||||
Permutation([0, 1, 3, 2])]]
|
||||
|
||||
|
||||
def test_strong_gens_from_distr():
|
||||
strong_gens_distr = [[Permutation([0, 2, 1]), Permutation([1, 2, 0]),
|
||||
Permutation([1, 0, 2])], [Permutation([0, 2, 1])]]
|
||||
assert _strong_gens_from_distr(strong_gens_distr) == \
|
||||
[Permutation([0, 2, 1]),
|
||||
Permutation([1, 2, 0]),
|
||||
Permutation([1, 0, 2])]
|
||||
|
||||
|
||||
def test_orbits_transversals_from_bsgs():
|
||||
S = SymmetricGroup(4)
|
||||
S.schreier_sims()
|
||||
base = S.base
|
||||
strong_gens = S.strong_gens
|
||||
strong_gens_distr = _distribute_gens_by_base(base, strong_gens)
|
||||
result = _orbits_transversals_from_bsgs(base, strong_gens_distr)
|
||||
orbits = result[0]
|
||||
transversals = result[1]
|
||||
base_len = len(base)
|
||||
for i in range(base_len):
|
||||
for el in orbits[i]:
|
||||
assert transversals[i][el](base[i]) == el
|
||||
for j in range(i):
|
||||
assert transversals[i][el](base[j]) == base[j]
|
||||
order = 1
|
||||
for i in range(base_len):
|
||||
order *= len(orbits[i])
|
||||
assert S.order() == order
|
||||
|
||||
|
||||
def test_handle_precomputed_bsgs():
|
||||
A = AlternatingGroup(5)
|
||||
A.schreier_sims()
|
||||
base = A.base
|
||||
strong_gens = A.strong_gens
|
||||
result = _handle_precomputed_bsgs(base, strong_gens)
|
||||
strong_gens_distr = _distribute_gens_by_base(base, strong_gens)
|
||||
assert strong_gens_distr == result[2]
|
||||
transversals = result[0]
|
||||
orbits = result[1]
|
||||
base_len = len(base)
|
||||
for i in range(base_len):
|
||||
for el in orbits[i]:
|
||||
assert transversals[i][el](base[i]) == el
|
||||
for j in range(i):
|
||||
assert transversals[i][el](base[j]) == base[j]
|
||||
order = 1
|
||||
for i in range(base_len):
|
||||
order *= len(orbits[i])
|
||||
assert A.order() == order
|
||||
|
||||
|
||||
def test_base_ordering():
|
||||
base = [2, 4, 5]
|
||||
degree = 7
|
||||
assert _base_ordering(base, degree) == [3, 4, 0, 5, 1, 2, 6]
|
||||
|
||||
|
||||
def test_remove_gens():
|
||||
S = SymmetricGroup(10)
|
||||
base, strong_gens = S.schreier_sims_incremental()
|
||||
new_gens = _remove_gens(base, strong_gens)
|
||||
assert _verify_bsgs(S, base, new_gens) is True
|
||||
A = AlternatingGroup(7)
|
||||
base, strong_gens = A.schreier_sims_incremental()
|
||||
new_gens = _remove_gens(base, strong_gens)
|
||||
assert _verify_bsgs(A, base, new_gens) is True
|
||||
D = DihedralGroup(2)
|
||||
base, strong_gens = D.schreier_sims_incremental()
|
||||
new_gens = _remove_gens(base, strong_gens)
|
||||
assert _verify_bsgs(D, base, new_gens) is True
|
||||
Reference in New Issue
Block a user