-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathorder_resolve_conflicts.go
More file actions
110 lines (100 loc) · 2.74 KB
/
Copy pathorder_resolve_conflicts.go
File metadata and controls
110 lines (100 loc) · 2.74 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
package dagro
type conflictEntry struct {
orderEntry
indegree int
in []*conflictEntry
out []*conflictEntry
merged bool
}
func resolveConflicts(entries []orderEntry, cg *Graph) []orderEntry {
mappedEntries := make(map[string]*conflictEntry, len(entries))
mappedOrder := newOrderedSet()
for i, entry := range entries {
tmp := &conflictEntry{orderEntry: orderEntry{
V: entry.V,
VS: []string{entry.V},
I: i,
Barycenter: entry.Barycenter,
Weight: entry.Weight,
HasBarycenter: entry.HasBarycenter,
}}
mappedEntries[entry.V] = tmp
mappedOrder.add(entry.V)
}
for _, e := range cg.Edges() {
entryV, okV := mappedEntries[e.V]
entryW, okW := mappedEntries[e.W]
if okV && okW {
entryW.indegree++
entryV.out = append(entryV.out, entryW)
}
}
sourceSet := make([]*conflictEntry, 0, len(mappedEntries))
for _, v := range mappedOrder.values() {
entry := mappedEntries[v]
if entry.indegree == 0 {
sourceSet = append(sourceSet, entry)
}
}
return doResolveConflicts(sourceSet)
}
func doResolveConflicts(sourceSet []*conflictEntry) []orderEntry {
entries := make([]*conflictEntry, 0)
for len(sourceSet) > 0 {
entry := sourceSet[len(sourceSet)-1]
sourceSet = sourceSet[:len(sourceSet)-1]
entries = append(entries, entry)
for left, right := 0, len(entry.in)-1; left < right; left, right = left+1, right-1 {
entry.in[left], entry.in[right] = entry.in[right], entry.in[left]
}
for _, incoming := range entry.in {
if incoming.merged {
continue
}
if !incoming.HasBarycenter || !entry.HasBarycenter || incoming.Barycenter >= entry.Barycenter {
mergeEntries(entry, incoming)
}
}
for _, outgoing := range entry.out {
outgoing.in = append(outgoing.in, entry)
outgoing.indegree--
if outgoing.indegree == 0 {
sourceSet = append(sourceSet, outgoing)
}
}
}
result := make([]orderEntry, 0, len(entries))
for _, entry := range entries {
if entry.merged {
continue
}
result = append(result, orderEntry{
VS: append([]string(nil), entry.VS...),
I: entry.I,
Barycenter: entry.Barycenter,
Weight: entry.Weight,
HasBarycenter: entry.HasBarycenter,
})
}
return result
}
func mergeEntries(target, source *conflictEntry) {
sum := 0.0
weight := 0.0
if jsTruthyNumber(target.Weight) {
sum += target.Barycenter * target.Weight
weight += target.Weight
}
if jsTruthyNumber(source.Weight) {
sum += source.Barycenter * source.Weight
weight += source.Weight
}
target.VS = append(append([]string(nil), source.VS...), target.VS...)
target.Barycenter = sum / weight
target.Weight = weight
target.HasBarycenter = true
if source.I < target.I {
target.I = source.I
}
source.merged = true
}