263 lines
6.4 KiB
Python
Executable File
263 lines
6.4 KiB
Python
Executable File
import time
|
|
import random
|
|
from multiprocessing import Process, Pool
|
|
|
|
|
|
def main():
|
|
start = time.time()
|
|
# number process
|
|
k=int(input('Number of parallel processes: '))
|
|
# data points per process
|
|
m=int(input('Number of data points per process: '))
|
|
# vertices per graph
|
|
n=int(input('Number of vertices per graph: '))
|
|
# probability of each edge appearing
|
|
p=float(input('Probability of an edge connecting two vertices: '))
|
|
|
|
numlinks=[]
|
|
|
|
pool = Pool(k)
|
|
|
|
results=[pool.apply_async(generate_data,args=(n,m,p,)) for i in range(k)]
|
|
|
|
count=[]
|
|
|
|
for result in results:
|
|
result.wait()
|
|
output = result.get()
|
|
count=merge_data(count,output)
|
|
|
|
print('Distribution of linking numbers: ' + str(count))
|
|
sum_squared=0
|
|
for i in range(len(count)):
|
|
sum_squared+= i*i* count[i]
|
|
avg = 1. * sum_squared/k/m
|
|
print('Average sum of linking number squared: ' + str(avg))
|
|
|
|
end = time.time()
|
|
print('Total time: ' + str(end-start))
|
|
|
|
|
|
def generate_data(n,m,p):
|
|
count = []
|
|
for i in range(m):
|
|
# generate random graph
|
|
data = random_graph(n,p)
|
|
|
|
# merge data
|
|
merge_data(count,data)
|
|
return count
|
|
|
|
|
|
def merge_data(count, data):
|
|
while len(count)< len(data):
|
|
count.append(0)
|
|
for i in range(len(data)):
|
|
count[i]+=data[i]
|
|
return count
|
|
|
|
|
|
def generate_coords(len):
|
|
#pts = [[1,1,1], [2,2,2], [3,3,3], [4,4,4], [5,5,5], [6,6,6]]
|
|
pts=[]
|
|
for i in range(len):
|
|
pts.append([random.random(),random.random(),random.random()])
|
|
return pts
|
|
|
|
|
|
def generate_adj(len,p):
|
|
adj = []
|
|
for i in range(len):
|
|
adj.append([])
|
|
for j in range(len):
|
|
if j>i:
|
|
if random.random()<p:
|
|
adj[i].append(1)
|
|
else:
|
|
adj[i].append(0)
|
|
elif j==i:
|
|
adj[i].append(0)
|
|
else:
|
|
adj[i].append(adj[j][i])
|
|
|
|
return adj
|
|
|
|
|
|
def random_graph(n,p):
|
|
pts = generate_coords(n)
|
|
adj = generate_adj(n,p)
|
|
count=[]
|
|
|
|
components_list = generate_components([],[],range(n))
|
|
for pair in components_list:
|
|
cycle1_list = permute_cycle([], pair[0],adj)
|
|
cycle2_list = permute_cycle([], pair[1],adj)
|
|
for cycle1 in cycle1_list:
|
|
for cycle2 in cycle2_list:
|
|
link=linking_number(cycle1,cycle2,pts)
|
|
while len(count)<=link:
|
|
count.append(0)
|
|
count[link]+=1
|
|
return count
|
|
|
|
|
|
def generate_components(link1, link2, points):
|
|
if len(points)==0:
|
|
if len(link1)>2 and len(link2)>2:
|
|
return [[link1, link2]]
|
|
else:
|
|
return []
|
|
else:
|
|
output = []
|
|
output+=generate_components(link1+[points[0]], link2, points[1:])
|
|
output+=generate_components(link1,link2,points[1:])
|
|
if len(link1)>0:
|
|
output+=generate_components(link1,link2+[points[0]],points[1:])
|
|
return output
|
|
|
|
|
|
def permute_cycle(perm, remainder,adj):
|
|
if len(remainder) == 0:
|
|
# remove duplicates with reverse orientation
|
|
if perm[1] < perm[-1]:
|
|
# also check if last and first are connected
|
|
if adj[perm[0]][perm[-1]]==1:
|
|
return [perm]
|
|
else:
|
|
return []
|
|
else:
|
|
return []
|
|
if len(perm) == 0:
|
|
return permute_cycle([remainder[0]], remainder[1:],adj)
|
|
else:
|
|
output=[]
|
|
for i in range(len(remainder)):
|
|
if adj[perm[-1]][remainder[i]]==1:
|
|
output+= permute_cycle(perm +[remainder[i]], remainder[:i]+remainder[i+1:],adj)
|
|
return output
|
|
|
|
|
|
def linking_number(link1,link2,pts):
|
|
len1 = len(link1)
|
|
len2 = len(link2)
|
|
|
|
cross_num=0
|
|
|
|
for i in range(len1):
|
|
for k in range(len2):
|
|
j=(i+1) % len1
|
|
l=(k+1) % len2
|
|
p1=pts[link1[i]]
|
|
p2=pts[link1[j]]
|
|
q1=pts[link2[k]]
|
|
q2=pts[link2[l]]
|
|
cross_num+=check_crossing(p1,p2,q1,q2)
|
|
|
|
|
|
# string output for mathematica
|
|
comp1 = ''
|
|
comp2 = ''
|
|
for i in range(len1):
|
|
comp1 += '{' + str(link1[i])[1:-1] + '},'
|
|
for k in range(len2):
|
|
comp2 += '{' + str(link2[k])[1:-1] + '},'
|
|
comp1 += '{' + str(link1[0])[1:-1] + '}'
|
|
comp2 += '{' + str(link2[0])[1:-1] + '}'
|
|
|
|
#print('Graphics3D[{Red,Line[{'+comp1+'}],Blue,Line[{'+comp2+'}]}]')
|
|
|
|
return abs(cross_num // 2)
|
|
|
|
|
|
def check_crossing(p1,p2,q1,q2):
|
|
# solve linear system for when two lines cross
|
|
dxp = p2[0]-p1[0]
|
|
dyp = p2[1]-p1[1]
|
|
dxq = q2[0]-q1[0]
|
|
dyq = q2[1]-q1[1]
|
|
dxc = q1[0]-p1[0]
|
|
dyc = q1[1]-p1[1]
|
|
det=dyp*dxq-dxp*dyq
|
|
t=( dxq*dyc-dyq*dxc ) / det
|
|
s=( dxp*dyc-dyp*dxc ) / det
|
|
|
|
# check if the lines cross inside the segments from p1 to p2 and q1 to q2
|
|
if (0<t<1) and (0<s<1):
|
|
# segments cross, find which is the over crossing
|
|
if (p1[2] + t*(p2[2]-p1[2])) > (q1[2]+s*(q2[2]-q1[2])):
|
|
overunder= 1
|
|
else:
|
|
overunder= -1
|
|
else:
|
|
overunder= 0
|
|
|
|
# now determine sign of crossing
|
|
if (det*overunder >0):
|
|
return 1
|
|
elif (det*overunder < 0):
|
|
return -1
|
|
else:
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
#Number of parallel processes: 1
|
|
#Number of data points per process: 1
|
|
#Number of vertices per graph: 12
|
|
#Distribution of linking numbers: [21803078, 12436371, 1439391, 70623, 1826, 20]
|
|
#Average sum of linking number squared: 18859258.0
|
|
#Total time: 6144.5997149944305
|
|
|
|
#Number of parallel processes: 4
|
|
#Number of data points per process: 25
|
|
#Number of vertices per graph: 11
|
|
#Distribution of linking numbers: [197717315, 88252703, 6298213, 152203, 2447, 18, 1]
|
|
#Average sum of linking number squared: 1148550.2
|
|
#Total time: 11594.052151679993
|
|
|
|
#Number of parallel processes: 4
|
|
#Number of data points per process: 25
|
|
#Number of vertices per graph: 10
|
|
#Distribution of linking numbers: [18121918, 6927567, 347324, 5051, 40]
|
|
#Average sum of linking number squared: 83629.62
|
|
#Total time: 925.2083818912506
|
|
|
|
#Number of parallel processes: 10
|
|
#Number of data points per process: 100
|
|
#Number of vertices per graph: 10
|
|
#Distribution of linking numbers: [181141920, 69334838, 3495202, 46635, 404, 1]
|
|
#Average sum of linking number squared: 83741.85
|
|
#Total time: 4584.27324009
|
|
|
|
#Number of parallel processes: 4
|
|
#Number of data points per process: 25
|
|
#Number of vertices per graph: 9
|
|
#Distribution of linking numbers: [1747822, 543817, 16180, 81]
|
|
#Average sum of linking number squared: 6092.66
|
|
#Total time: 84.65731692314148
|
|
|
|
#Number of parallel processes: 4
|
|
#Number of data points per process: 25
|
|
#Number of vertices per graph: 8
|
|
#Distribution of linking numbers: [167672, 42308, 720]
|
|
#Average sum of linking number squared: 451.88
|
|
#Total time: 9.123421669006348
|
|
|
|
#Number of parallel processes: 4
|
|
#Number of data points per process: 25
|
|
#Number of vertices per graph: 7
|
|
#Distribution of linking numbers: [14437, 3046, 17]
|
|
#Average sum of linking number squared: 31.14
|
|
#Total time: 3.5018203258514404
|
|
|
|
#Number of parallel processes: 4
|
|
#Number of data points per process: 25
|
|
#Number of vertices per graph: 6
|
|
#Distribution of linking numbers: [838, 162]
|
|
#Average sum of linking number squared: 1.62
|
|
#Total time: 3.2760980129241943
|
|
|
|
|