@@ -46,19 +46,19 @@ static SmallVector<Value> getCycle(const DenseMap<Value, Value> &parents,
46
46
// / cycle, u \in C, are replaced with a single edge (v_C, v), and the selected
47
47
// / node u is marked in the ouptut map actualSource[v].
48
48
static void contract (RootOrderingGraph &graph, ArrayRef<Value> cycle,
49
- const DenseMap<Value, unsigned > &parentCosts ,
49
+ const DenseMap<Value, unsigned > &parentDepths ,
50
50
DenseMap<Value, Value> &actualSource,
51
51
DenseMap<Value, Value> &actualTarget) {
52
52
Value rep = cycle.front ();
53
53
DenseSet<Value> cycleSet (cycle.begin (), cycle.end ());
54
54
55
55
// Now, contract the cycle, marking the actual sources and targets.
56
- DenseMap<Value, RootOrderingCost> repCosts ;
56
+ DenseMap<Value, RootOrderingEntry> repEntries ;
57
57
for (auto outer = graph.begin (), e = graph.end (); outer != e; ++outer) {
58
58
Value target = outer->first ;
59
59
if (cycleSet.contains (target)) {
60
60
// Target in the cycle => edges incoming to the cycle or within the cycle.
61
- unsigned parentCost = parentCosts .lookup (target);
61
+ unsigned parentDepth = parentDepths .lookup (target);
62
62
for (const auto &inner : outer->second ) {
63
63
Value source = inner.first ;
64
64
// Ignore edges within the cycle.
@@ -67,30 +67,30 @@ static void contract(RootOrderingGraph &graph, ArrayRef<Value> cycle,
67
67
68
68
// Edge incoming to the cycle.
69
69
std::pair<unsigned , unsigned > cost = inner.second .cost ;
70
- assert (parentCost <= cost.first && " invalid parent cost " );
70
+ assert (parentDepth <= cost.first && " invalid parent depth " );
71
71
72
72
// Subtract the cost of the parent within the cycle from the cost of
73
73
// the edge incoming to the cycle. This update ensures that the cost
74
74
// of the minimum-weight spanning arborescence of the entire graph is
75
75
// the cost of arborescence for the contracted graph plus the cost of
76
76
// the cycle, no matter which edge in the cycle we choose to drop.
77
- cost.first -= parentCost ;
78
- auto it = repCosts .find (source);
79
- if (it == repCosts .end () || it->second .cost > cost) {
77
+ cost.first -= parentDepth ;
78
+ auto it = repEntries .find (source);
79
+ if (it == repEntries .end () || it->second .cost > cost) {
80
80
actualTarget[source] = target;
81
81
// Do not bother populating the connector (the connector is only
82
82
// relevant for the final traversal, not for the optimal branching).
83
- repCosts [source].cost = cost;
83
+ repEntries [source].cost = cost;
84
84
}
85
85
}
86
86
// Erase the node in the cycle.
87
87
graph.erase (outer);
88
88
} else {
89
89
// Target not in cycle => edges going away from or unrelated to the cycle.
90
- DenseMap<Value, RootOrderingCost > &costs = outer->second ;
90
+ DenseMap<Value, RootOrderingEntry > &entries = outer->second ;
91
91
Value bestSource;
92
92
std::pair<unsigned , unsigned > bestCost;
93
- auto inner = costs .begin (), innerE = costs .end ();
93
+ auto inner = entries .begin (), innerE = entries .end ();
94
94
while (inner != innerE) {
95
95
Value source = inner->first ;
96
96
if (cycleSet.contains (source)) {
@@ -99,22 +99,22 @@ static void contract(RootOrderingGraph &graph, ArrayRef<Value> cycle,
99
99
bestSource = source;
100
100
bestCost = inner->second .cost ;
101
101
}
102
- costs .erase (inner++);
102
+ entries .erase (inner++);
103
103
} else {
104
104
++inner;
105
105
}
106
106
}
107
107
108
108
// There were going-away edges, contract them.
109
109
if (bestSource) {
110
- costs [rep].cost = bestCost;
110
+ entries [rep].cost = bestCost;
111
111
actualSource[target] = bestSource;
112
112
}
113
113
}
114
114
}
115
115
116
116
// Store the edges to the representative.
117
- graph[rep] = std::move (repCosts );
117
+ graph[rep] = std::move (repEntries );
118
118
}
119
119
120
120
OptimalBranching::OptimalBranching (RootOrderingGraph graph, Value root)
@@ -128,8 +128,8 @@ unsigned OptimalBranching::solve() {
128
128
129
129
// A map that stores the cost of the optimal local choice for each node
130
130
// in a directed cycle. This map is cleared every time we seed the search.
131
- DenseMap<Value, unsigned > parentCosts ;
132
- parentCosts .reserve (graph.size ());
131
+ DenseMap<Value, unsigned > parentDepths ;
132
+ parentDepths .reserve (graph.size ());
133
133
134
134
// Determine if the optimal local choice results in an acyclic graph. This is
135
135
// done by computing the optimal local choice and traversing up the computed
@@ -142,27 +142,30 @@ unsigned OptimalBranching::solve() {
142
142
// Follow the trail of best sources until we reach an already visited node.
143
143
// The code will assert if we cannot reach an already visited node, i.e.,
144
144
// the graph is not strongly connected.
145
- parentCosts .clear ();
145
+ parentDepths .clear ();
146
146
do {
147
147
auto it = graph.find (node);
148
148
assert (it != graph.end () && " the graph is not strongly connected" );
149
149
150
+ // Find the best local parent, taking into account both the depth and the
151
+ // tie breaking rules.
150
152
Value &bestSource = parents[node];
151
- unsigned &bestCost = parentCosts[node] ;
153
+ std::pair< unsigned , unsigned > bestCost ;
152
154
for (const auto &inner : it->second ) {
153
- const RootOrderingCost &cost = inner.second ;
154
- if (!bestSource /* initial */ || bestCost > cost .cost . first ) {
155
+ const RootOrderingEntry &entry = inner.second ;
156
+ if (!bestSource /* initial */ || bestCost > entry .cost ) {
155
157
bestSource = inner.first ;
156
- bestCost = cost .cost . first ;
158
+ bestCost = entry .cost ;
157
159
}
158
160
}
159
161
assert (bestSource && " the graph is not strongly connected" );
162
+ parentDepths[node] = bestCost.first ;
160
163
node = bestSource;
161
- totalCost += bestCost;
164
+ totalCost += bestCost. first ;
162
165
} while (!parents.count (node));
163
166
164
167
// If we reached a non-root node, we have a cycle.
165
- if (parentCosts .count (node)) {
168
+ if (parentDepths .count (node)) {
166
169
// Determine the cycle starting at the representative node.
167
170
SmallVector<Value> cycle = getCycle (parents, node);
168
171
@@ -171,7 +174,7 @@ unsigned OptimalBranching::solve() {
171
174
DenseMap<Value, Value> actualSource, actualTarget;
172
175
173
176
// Contract the cycle and recurse.
174
- contract (graph, cycle, parentCosts , actualSource, actualTarget);
177
+ contract (graph, cycle, parentDepths , actualSource, actualTarget);
175
178
totalCost = solve ();
176
179
177
180
// Redirect the going-away edges.
@@ -186,7 +189,7 @@ unsigned OptimalBranching::solve() {
186
189
Value entry = actualTarget.lookup (parent);
187
190
cycle.push_back (node); // complete the cycle
188
191
for (size_t i = 0 , e = cycle.size () - 1 ; i < e; ++i) {
189
- totalCost += parentCosts .lookup (cycle[i]);
192
+ totalCost += parentDepths .lookup (cycle[i]);
190
193
if (cycle[i] == entry)
191
194
parents[cycle[i]] = parent; // break the cycle
192
195
else
0 commit comments