Given a graph \$G = (V,E)\$ with a unique labeling of each vertex, let the transposition \$(i,j)\$ (where \$i,j\$ are the labels on adjacent vertices) represent selecting an edge and swapping the labels \$i\$ and \$j\$.
I would like to take a list of edges in a graph (a cube in this code), and determine the number of permutations on \$V\$ that are representable as a product of at most some \$k\$ sets of disjoint transpositions of the above form. For example, a permutation \$(62154703)\$ can be expressed as \$[(67)(03)][(37)(56)][(45)(26)](12)\$, where the brackets are only to emphasize the specific disjoint set.
How can I improve my run time? Currently my runtime is about 18 hours. I don't know the runtime of the last step, but currently the first step in CreateAllPermutations takes 2 seconds, and the second step takes 1765 seconds.
Additional question: is the Permutation class from sympy.combinatorics slowing me down?
Here is the input file, and some truncated expected sample output (this output will not be printed, but it is what is being generated) from GetSteps()
, which is a smaller case of CreateAllPermutations()
, along with what I expect to see from print(len(allPerms))
:
Input file:
01 03 04 12 15 23 26 37 45 47 56 67
Sample output from GetSteps()
and allPerms
:
Completed all permutations of 1 step! There are 107 such permutations. (4 7) (0 1)(2 6)(3 7) (0 3)(4 7) (7)(0 4)(1 5) (7)(0 3)(1 5)(2 6) (7)(2 3)(5 6) (7)(1 5)(2 3) (0 4)(1 5)(2 3)(6 7) (7)(2 3)(4 5) (0 1)(3 7)(5 6) (7)(0 3) (1 5)(4 7) (6 7) (0 4)(1 2)(3 7) (0 3)(1 5)(4 7) 40320 #8!, as I am expecting to generate every permutation on 8 elements
Main code:
import time, itertools
from sympy.combinatorics import Permutation as Perm
def GetEdges():
edgeFile = open("EdgesQ3.txt","r")
edges = []
for line in edgeFile:
line = line.strip()
line = list(line)
for vertex in line:
line[line.index(vertex)] = int(vertex)
edges.append([line])
return edgeFile, edges
def AreDisjoint(s1,s2):
v1 = {point for edge in s1 for point in edge}
v2 = {point for edge in s2 for point in edge}
shared = v1 & v2
return shared == set()
def GetSteps(edges,maxMatching):
"""The variable maxMatching is to give a value for the maximum number
of disjoint permutations in a set"""
steps = []
steps.extend(edges)
for i in range(1,maxMatching):
for s1 in steps:
if len(s1) == i:
for s2 in steps:
newStep = []
newStep.extend([s for s in s1])
newStep.extend([s for s in s2])
newStep.sort()
if AreDisjoint(s1,s2) and newStep not in steps:
steps.append(newStep)
return steps
def CreateOneStepPermutations(steps, size):
oneStep = set()
for step in steps:
perm = Perm([],size = size)
for edge in step:
perm *= Perm([edge], size = size)
oneStep = oneStep | {perm}
print("Completed all permutations of 1 step! There are {} such permutations.".format(len(oneStep)), flush = True)
return oneStep
def CreateStepDictionary(oneStep):
stepDict = {}
stepDict[1] = oneStep
return stepDict
def CreateAllPermutations(oneStep,stepDict):
allPerms = set()
for i in range(1,4):
count = 0
routing = set()
for p1 in stepDict[1]:
for p2 in stepDict[i]:
p = p1 * p2
routing = routing | {p}
count += 1
if count % 100 == 0:
print("You have computed {} permutations in this block.".format(count), flush = True)
for j in range(1,i+1):
routing = routing - set(stepDict[j])
stepDict[i+1] = routing
print("Completed all permutations of {} steps! There are {} such permutations.".format(i+1, len(routing)), flush = True)
for i in range(1,5):
allPerms = allPerms | stepDict[i]
return allPerms
def main():
maxMatching = 4
vertexSetSize = 8
edgeFile, edges = GetEdges()
steps = GetSteps(edges, maxMatching)
oneStep = CreateOneStepPermutations(steps, vertexSetSize)
stepDict = CreateStepDictionary(oneStep)
allPerms = CreateAllPermutations(oneStep, stepDict)
print(len(allPerms)) #Tells me how much of the symmetric group I get
main()