-
Notifications
You must be signed in to change notification settings - Fork 0
/
automorphismSimple.py
302 lines (246 loc) · 11.4 KB
/
automorphismSimple.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
from sympy.combinatorics.named_groups import SymmetricGroup
from sympy.combinatorics.perm_groups import PermutationGroup
import numpy as np
##################
## AUTOMORPHISM ##
##################
def automorphism():
""" automorphism runs an interface to make it easier for the user to input posets and permutations.
It has the option to find all of the automorphisms for a given poset or check if a mapping is an automorphism.
"""
print('Hello! This finds and checks for automorphisms on posets!')
print()
instructions = input('Do you want instructions? Enter y for yes : ')
if instructions == 'y' or instructions == 'Y':
print()
print('Enter the strictly less than relations as two element pairs separated')
print('by lines with the lower element on the left.')
print('Ensure that you label your nodes with integers starting at 0. Start by entering the number of relations')
print()
print('For example, the input for a chain of 3 nodes where 0 < 1 < 2 would be :')
print('Number of Relations : 2')
print('Enter a relation : 0 1')
print('Enter a relation : 1 2')
print()
relationsList = []
n = int(input("Number of Relations : "))
print()
for i in range(0, n):
ele = list(map(int,input("Enter a relation : ").strip().split()))[:2]
relationsList.append(ele)
print()
numNodes = int(input('How many nodes are in your poset? '))
myArr = leqMatrix(numNodes, relationsList)
print()
print('Do you want to find all of the automorphisms for your poset')
print('or check if a permutation is an automorphism?')
choice = input('Enter in a for all automorphisms or b to check : ')
print()
if choice == 'a' or choice == 'A':
fancyAutomorphisms(myArr)
elif choice == 'b' or choice == 'B':
instructions = input('Do you want instructions? Enter y for yes : ')
if instructions == 'y' or 'Y':
print()
print('Enter the mappings as two element pairs separated by lines.')
print('Ensure that you follow the same node labeling as you did while entering the poset.')
print('You do need to include mappings for elements that do not change.')
print()
print('For example, the mapping 0 -> 0, 1 -> 2, 2 -> 3, 3 -> 1 would be entered as :')
print('Number of Mappings : 3')
print('Enter a mapping : 1 2')
print('Enter a mapping : 2 3')
print('Enter a mapping : 3 1')
print()
print('For a mapping where you have something along the lines of a <-> b. You must enter it as :')
print('Number of Mappings : 2')
print('Enter a mapping : a b')
print('Enter a mapping : b a')
print()
print('Make sure that you only enter integers')
mappingList = []
numMap = int(input("Number of Mappings : "))
print()
for i in range(0, numMap):
mapping = list(map(int,input("Enter a mapping : ").strip().split()))[:2]
mappingList.append(mapping)
print()
perm = listToPerm(mappingList, numNodes)
# print(perm)
automorphismChecker(myArr, perm)
else:
print('Invalid input :(')
##########################
## AUTOMORPHISM CHECKER ##
##########################
def automorphismChecker(myArr, autPermutation):
""" automorphismChecker takes in an array representation of a matrix (less than matrix, similar to adjacency) and a permutation, and returns a boolean
parameters: myArr: an array representation of a matrix where less than/equal to relations
are represented by 1s by rows and non adjacent/ greater than relations
are 0s. (see the examples and the reference picture)
autPermutation: a list representation of the permutation
(eg 0 -> 1, 1 -> 0, 0 -> 0 would be [1, 0, 2])
output: boolean: True if autPermutation is an automorphism on myArr.
False if it is not.
"""
if autPermutation == 0:
print('Invalid input :(')
return False
posetArr = np.array(myArr)
elements = elementList(myArr)
possiblePoset = np.array(myArr)
possiblePoset[:] = possiblePoset[:, autPermutation]
possiblePoset[elements] = possiblePoset[autPermutation]
if (possiblePoset == posetArr).all():
print('Your input is an automorphism on the given poset')
return True
else:
print('Your input is not an automorphism on the given poset')
return False
#########################
## AUTOMORPHISM FINDER ##
#########################
def fancyAutomorphisms(myArr):
""" automorphisms takes in an array representation of a matrix (less than matrix, similar to adjacency)
and returns the number of automorphisms and the mappings (as permutations)
parameters: myArr: an array representation of a matrix where less than/equal to relations
are represented by 1s by rows and non adjacent/ greater than relations
are 0s. (see the examples and the reference picture)
output: automorphism counter: returns the number of automorphisms
permutations: prints the mappings as permutations
(eg 0 -> 1, 1 -> 0, 0 -> 0 would be [1, 0, 2])
"""
posetArr = np.array(myArr)
possibleMaps = permutationGroup(myArr)
autCount = 0
elements = elementList(myArr)
autsArr = []
for permutation in possibleMaps:
possiblePoset = np.array(myArr)
# swap cols
possiblePoset[:] = possiblePoset[:, permutation]
# swap rows
possiblePoset[elements] = possiblePoset[permutation]
if (possiblePoset == posetArr).all():
autCount += 1
autsArr += [permutation]
print('The automorphisms on this poset are : \n')
for i in range(len(autsArr)):
print('f' + str(i) + ': \n')
for j in range(len(autsArr[i])):
print(str(j) + ' -> ' + str(autsArr[i][j]))
print('\n')
print('This poset has ' + str(autCount) + ' automorphisms')
return autsArr, autCount
#############
## HELPERS ##
#############
def permutationGroup(myArr):
""" permutationGroup outputs the permutation group for all of the nodes in a given poset matrix
primarily a helper function
parameters: myArr: an array representation of a matrix where less than/equal to relations
are represented by 1s by rows and non adjacent/ greater than relations
are 0s. (see the examples and the reference picture)
output: permutations: a list of the permutaions in the permutation group
"""
generators = SymmetricGroup(len(myArr))
permutations = list(generators.generate_schreier_sims(af=True))
return permutations
def elementList(myArr):
""" elementList outputs a list of the nodes in myArr
primarily a helper function
parameters: myArr: an array representation of a matrix where less than/equal to relations
are represented by 1s by rows and non adjacent/ greater than relations
are 0s. (see the examples and the reference picture)
output: a list of nodes.
"""
elementsList = []
start = 0
for x in range(len(myArr)):
elementsList += [start]
start += 1
return elementsList
def defaultMatrix(numNodes):
""" defaultMatrix makes an n x n identity matrix where n is equal to numNodes
parameters: numNodes: an integer that corresponds to the number of nodes in the poset
output: a nested array where each sub array is a row in the matrix.
"""
resArr = []
for i in range(numNodes):
subArr = []
for j in range(numNodes):
if i == j:
subArr += [1]
else:
subArr += [0]
resArr += [subArr]
return resArr
def toRelationsDictionary(relationsList):
""" toRelationsDictionary makes a dictionary out of an array of 2-element arrays
parameters: relationsList: an array of 2-element arrays where the elements or the sub arrays are nodes
output: a dictionary where the keys are the first values in the 2 element arrays and the values
are the second values in the sub arrays.
"""
dictionary = {}
for i in relationsList:
dictionary.setdefault(i[0],[]).append(i[1])
return dictionary
def leqMatrix(numNodes, relationsList):
""" leqMatrix makes an array representation of a matrix where less than/equal to relations
are represented by 1s by rows and non adjacent/ greater than relations are 0s.
parameters: numNodes: an integer corresponding to the number of nodes in the poset
relationsList: an array of 2-element arrays where the elements or the sub arrays are nodes.
the 2-element arrays represent less than relations, so for example,
[1, 2] corresponds to 1 < 2.
output: a nested array where each sub array is a row in the matrix.
"""
relationsDict = toRelationsDictionary(relationsList)
resMatrix = defaultMatrix(numNodes)
for i in range(numNodes):
if i in relationsDict:
for x in relationsDict[i]:
resMatrix[i][x] = 1
return resMatrix
def listToPerm (mappings, numNodes):
""" listToPerm creates a permutation representation from a list of mappings
parameters: mappings: an array of 2-element arrays where the 2-element arrays correspond to mappings.
For example, [1, 2] corresponds to 1 -> 2
numNodes: an integer corresponding to the number of nodes in the poset
output: an array representation of the permutation. For example, for the mapping 1 -> 2, 2 -> 1 on the nodes
0, 1, 2, the output would be [0, 2, 1].
if there is an invalid input such that the mapping does not result in a permutation,
listToPerm returns 0
"""
mappingDict = toRelationsDictionary(mappings)
perm = []
for i in range(numNodes):
if i in mappingDict:
perm += mappingDict[i]
else:
perm += [i]
if len(set(perm)) != numNodes:
return 0
else:
return perm
########################
## examples for ##
## fancyAutomorphisms ##
########################
# test 1
# test = [[1, 1, 1, 0], [0, 1, 0, 1], [0, 0, 1, 1], [0, 0, 0, 1]]
# print(fancyAutomorphisms(test))
# test 2: chain
# test = [[1, 1, 0, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1]]
# print(fancyAutomorphisms(test))
# test 3: separate
# test = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
# print(fancyAutomorphisms(test))
# test 4:
# test = [[1, 1, 1, 1, 0], [0, 1, 0, 0, 1], [0, 0, 1, 0, 1], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1]]
# print(fancyAutomorphisms(test))
# test 5:
# test = [[1, 1, 1, 1, 0, 0], [0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0], [0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1]]
# print(fancyAutomorphisms(test))
# test 6:
# test = [[1, 1, 1, 0, 0], [0, 1, 0, 0, 1], [0, 0, 1, 0, 1], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1]]
# print(fancyAutomorphisms(test))