-
Notifications
You must be signed in to change notification settings - Fork 0
/
DynPartitioner.py
154 lines (130 loc) · 4.83 KB
/
DynPartitioner.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
from networkit import *
import math, sys
def continuousPartition(G, X, tolerance, k=0, isCharged={}):
# validate input
n = G.numberOfNodes()
if len(isCharged) > 0:
assert(len(isCharged)==n)
if k > 0:
assert(sum(isCharged) <= k)
else:
isCharged = [False for i in range(n)]
assert(X > 0)
assert(tolerance >= 0)
if (n % X > 0 or (k>0 and k*X != n)) and tolerance == 0:
if (k > 0):
print("Creating", k, "partitions of size", X, "from a graph with", n, " nodes and tolerance 0 is impossible.")
else:
print("Creating partitions of size", X, "from a graph with", n, " nodes and tolerance 0 is impossible.")
print("Set tolerance to 1.")
tolerance = 1
if k > 0:
assert(n <= (X + tolerance)*k)
assert(n >= (X - tolerance)*k)
maxNumberOfPartitions = int(n / max(X - tolerance, 1)) if (k == 0) else k
def w(i):
"""
Weight of cutting after node i.
TODO: consider other weights beside the single cut edge
"""
assert(i >= 0)
assert(i < n)
if (i == n-1):
return 0
else:
return G.weight(i,i+1)
# allocate cut and predecessor table
table = [[float("inf") for j in range(maxNumberOfPartitions)] for i in range(n)]
pred = [[-1 for j in range(maxNumberOfPartitions)] for i in range(n)]
# fill table
for i in range(n):
for j in range(maxNumberOfPartitions):
if (j == 0):
if abs(i+1-X) <= tolerance:
table[i][j] = w(i)
elif (i >= (X-tolerance)):
windowStart = max(i-(X+tolerance),0)
# make sure that no two charged nodes are in the same partition
chargeEncountered = False
for l in reversed(range(windowStart, i+1)):
assert(l >= windowStart)
if isCharged[l]:
if chargeEncountered:
windowStart = l
break
else:
chargeEncountered = True
predList = [table[l][j-1] for l in range(windowStart, min(i,i-(X-tolerance)+1))]
if (len(predList) > 0):
minPred = min(predList)
table[i][j] = minPred + w(i)
pred[i][j] = predList.index(minPred) + windowStart
#for i in range(n):
# row = table[i]
# print(i, ': [',end="")
# for elem in row:
# if math.isinf(elem):
# print("inf, ", end="")
# else:
# print(int(elem*100)/100, ", ", end="")
# print("]")
# get result from table
resultlist = [table[n-1][j] for j in range(maxNumberOfPartitions)]
if len(resultlist) == 0:
raise ValueError("Combination of parameters allows no partition!")
# if k is given, select best solution with k subsets. If not, select best overall solution
if (k == 0):
bestCutValue = min(resultlist)
k = resultlist.index(bestCutValue) + 1
else:
bestCutValue = table[n-1][k-1]
if (bestCutValue == float("inf")):
raise ValueError("Combination of parameters allows no partition!")
result = partitioning.Partition(n)
result.setUpperBound(k)
# search best path backwards
j = k-1
i = n-1
c = bestCutValue
while (j > 0):
nextI = pred[i][j]
assert(nextI >= 0)
# assign partitions to nodes
for l in range(nextI+1, i+1):
result[l] = j
j -= 1
c -=w(i)
i = nextI
# assign partitions to first nodes not covered by previous loop
for l in range(0, nextI+1):
result[l] = 0
# check results:
for i in range(n):
assert(result[i] >= 0)
assert(result[i] < k)
for size in result.subsetSizes():
if (abs(size-X) > tolerance):
print("For n=", n, ", k=", k, ", X=", X, ", tolerance=", tolerance, ", ", size, " is wrong.")
assert(abs(size-X) <= tolerance)
return result
filename = sys.argv[1]
X = int(sys.argv[2])
tolerance = int(sys.argv[3])
k = int(sys.argv[4]) if len(sys.argv) >= 5 else 0
chargedNodes = []
for i in range(5, len(sys.argv)):
chargedNodes.append(int(sys.argv[i]))
G = readGraph(filename, Format.METIS)
n = G.numberOfNodes()
isCharged = [False for i in range(n)]
for c in chargedNodes:
assert(c < n)
isCharged[c] = True
part = continuousPartition(G, X, tolerance, k, isCharged)
for a in chargedNodes:
for b in chargedNodes:
if a != b:
assert(part[a] != part[b])
for i in range(n):
print(part[i])
#community.PartitionWriter().write(part, filename+'.part')