I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -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

View File

@ -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]

View File

@ -0,0 +1,221 @@
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_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

View File

@ -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)

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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]))

View File

@ -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))

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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])

View File

@ -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()

View File

@ -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

View File

@ -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)]

View File

@ -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

View File

@ -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[:]
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)

View File

@ -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