-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathequivalence.py
More file actions
112 lines (107 loc) · 3.03 KB
/
equivalence.py
File metadata and controls
112 lines (107 loc) · 3.03 KB
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
def array_alignment(members_size, i_mbr_byte_offset_pairs):
n = members_size
diff_matrix = [None] * (n*(n-1))
msg_prefix = "equivalence.array_alignment(): "
msg_directly_conflicting = msg_prefix + "directly conflicting input"
for p0,p1 in i_mbr_byte_offset_pairs:
i0,a0 = p0
i1,a1 = p1
if (i0 == i1):
if (a0 != a1):
raise RuntimeError(msg_directly_conflicting)
else:
if (i0 < i1):
i = i0 * n + i1
d = a0 - a1
else:
i = i1 * n + i0
d = a1 - a0
dd = diff_matrix[i]
if (dd is None):
diff_matrix[i] = d
elif (dd != d):
raise RuntimeError(msg_directly_conflicting)
cluster_indices = range(n)
clusters = []
for i in xrange(n):
clusters.append([])
for i0 in xrange(n-1):
for i1 in xrange(i0+1,n):
i = i0 * n + i1
d = diff_matrix[i]
if (d is not None):
ci0 = cluster_indices[i0]
ci1 = cluster_indices[i1]
if (ci0 == ci1):
continue
if (ci0 > ci1):
ci0, ci1 = ci1, ci0
d *= -1
i0, i1 = i1, i0
if (ci1 != i1):
continue
c0 = clusters[ci0]
c1 = clusters[ci1]
if (ci0 != i0):
for i,o in c0:
if (i == i0):
d += o
break
c0.append((ci1, d))
cluster_indices[ci1] = ci0
for i,o in c1:
c0.append((i, o+d))
cluster_indices[i] = ci0
clusters[ci1] = []
if (cluster_indices.count(0) != n):
raise RuntimeError(msg_prefix + "insufficient input")
assert len(clusters[0]) == n-1
diffs0 = [None] * n
diffs0[0] = 0
for i,o in clusters[0]:
assert i != 0
assert diffs0[i] is None
diffs0[i] = o
for i0 in xrange(n-1):
for i1 in xrange(i0+1,n):
i = i0 * n + i1
d = diff_matrix[i]
if ( d is not None
and diffs0[i1] - diffs0[i0] != d):
raise RuntimeError(msg_prefix + "indirectly conflicting input")
return diffs0
class cluster_unions(object):
__slots__ = ["unions", "indices"]
def __init__(O):
O.unions = []
O.indices = {}
def add(O, key_cluster):
curr_index = None
for key in key_cluster:
prev_index = O.indices.get(key)
if (curr_index is None):
if (prev_index is None):
O.indices[key] = curr_index = len(O.unions)
O.unions.append([key])
else:
curr_index = prev_index
elif (prev_index is None):
O.indices[key] = curr_index
O.unions[curr_index].append(key)
elif (prev_index != curr_index):
if (prev_index < curr_index):
curr_index, prev_index = prev_index, curr_index
for key in O.unions[prev_index]:
O.indices[key] = curr_index
O.unions[curr_index].append(key)
O.unions[prev_index] = None
def tidy(O):
unions = []
indices = {}
for union in O.unions:
if (union is not None):
for key in union:
indices[key] = len(unions)
unions.append(union)
O.unions = unions
O.indices = indices