# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1282514050 -7200
# Node ID dca9eed2c375a0121a33e12412ae4be3e6dceed5
# Parent 24b3f18ed9e2bea99ab482c493c3db769362ecf0
Improve the tree update process and a pivot rule (#391)
and make some parts of the code clearer using better names
diff --git a/lemon/network_simplex.h b/lemon/network_simplex.h
a
|
b
|
|
166 | 166 | typedef std::vector<int> IntVector; |
167 | 167 | typedef std::vector<Value> ValueVector; |
168 | 168 | typedef std::vector<Cost> CostVector; |
169 | | typedef std::vector<char> BoolVector; |
170 | | // Note: vector<char> is used instead of vector<bool> for efficiency reasons |
| 169 | typedef std::vector<signed char> CharVector; |
| 170 | // Note: vector<signed char> is used instead of vector<ArcState> and |
| 171 | // vector<ArcDirection> for efficiency reasons |
171 | 172 | |
172 | 173 | // State constants for arcs |
173 | 174 | enum ArcState { |
… |
… |
|
176 | 177 | STATE_LOWER = 1 |
177 | 178 | }; |
178 | 179 | |
179 | | typedef std::vector<signed char> StateVector; |
180 | | // Note: vector<signed char> is used instead of vector<ArcState> for |
181 | | // efficiency reasons |
| 180 | // Direction constants for tree arcs |
| 181 | enum ArcDirection { |
| 182 | DIR_DOWN = -1, |
| 183 | DIR_UP = 1 |
| 184 | }; |
182 | 185 | |
183 | 186 | private: |
184 | 187 | |
… |
… |
|
217 | 220 | IntVector _rev_thread; |
218 | 221 | IntVector _succ_num; |
219 | 222 | IntVector _last_succ; |
| 223 | CharVector _pred_dir; |
| 224 | CharVector _state; |
220 | 225 | IntVector _dirty_revs; |
221 | | BoolVector _forward; |
222 | | StateVector _state; |
223 | 226 | int _root; |
224 | 227 | |
225 | 228 | // Temporary data used in the current pivot iteration |
226 | 229 | int in_arc, join, u_in, v_in, u_out, v_out; |
227 | | int first, second, right, last; |
228 | | int stem, par_stem, new_stem; |
229 | 230 | Value delta; |
230 | 231 | |
231 | 232 | const Value MAX; |
… |
… |
|
250 | 251 | const IntVector &_source; |
251 | 252 | const IntVector &_target; |
252 | 253 | const CostVector &_cost; |
253 | | const StateVector &_state; |
| 254 | const CharVector &_state; |
254 | 255 | const CostVector &_pi; |
255 | 256 | int &_in_arc; |
256 | 257 | int _search_arc_num; |
… |
… |
|
302 | 303 | const IntVector &_source; |
303 | 304 | const IntVector &_target; |
304 | 305 | const CostVector &_cost; |
305 | | const StateVector &_state; |
| 306 | const CharVector &_state; |
306 | 307 | const CostVector &_pi; |
307 | 308 | int &_in_arc; |
308 | 309 | int _search_arc_num; |
… |
… |
|
341 | 342 | const IntVector &_source; |
342 | 343 | const IntVector &_target; |
343 | 344 | const CostVector &_cost; |
344 | | const StateVector &_state; |
| 345 | const CharVector &_state; |
345 | 346 | const CostVector &_pi; |
346 | 347 | int &_in_arc; |
347 | 348 | int _search_arc_num; |
… |
… |
|
414 | 415 | const IntVector &_source; |
415 | 416 | const IntVector &_target; |
416 | 417 | const CostVector &_cost; |
417 | | const StateVector &_state; |
| 418 | const CharVector &_state; |
418 | 419 | const CostVector &_pi; |
419 | 420 | int &_in_arc; |
420 | 421 | int _search_arc_num; |
… |
… |
|
517 | 518 | const IntVector &_source; |
518 | 519 | const IntVector &_target; |
519 | 520 | const CostVector &_cost; |
520 | | const StateVector &_state; |
| 521 | const CharVector &_state; |
521 | 522 | const CostVector &_pi; |
522 | 523 | int &_in_arc; |
523 | 524 | int _search_arc_num; |
… |
… |
|
570 | 571 | bool findEnteringArc() { |
571 | 572 | // Check the current candidate list |
572 | 573 | int e; |
| 574 | Cost c; |
573 | 575 | for (int i = 0; i != _curr_length; ++i) { |
574 | 576 | e = _candidates[i]; |
575 | | _cand_cost[e] = _state[e] * |
576 | | (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); |
577 | | if (_cand_cost[e] >= 0) { |
| 577 | c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); |
| 578 | if (c < 0) { |
| 579 | _cand_cost[e] = c; |
| 580 | } else { |
578 | 581 | _candidates[i--] = _candidates[--_curr_length]; |
579 | 582 | } |
580 | 583 | } |
… |
… |
|
584 | 587 | int limit = _head_length; |
585 | 588 | |
586 | 589 | for (e = _next_arc; e != _search_arc_num; ++e) { |
587 | | _cand_cost[e] = _state[e] * |
588 | | (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); |
589 | | if (_cand_cost[e] < 0) { |
| 590 | c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); |
| 591 | if (c < 0) { |
| 592 | _cand_cost[e] = c; |
590 | 593 | _candidates[_curr_length++] = e; |
591 | 594 | } |
592 | 595 | if (--cnt == 0) { |
… |
… |
|
913 | 916 | |
914 | 917 | _parent.resize(all_node_num); |
915 | 918 | _pred.resize(all_node_num); |
916 | | _forward.resize(all_node_num); |
| 919 | _pred_dir.resize(all_node_num); |
917 | 920 | _thread.resize(all_node_num); |
918 | 921 | _rev_thread.resize(all_node_num); |
919 | 922 | _succ_num.resize(all_node_num); |
… |
… |
|
1116 | 1119 | _cap[e] = INF; |
1117 | 1120 | _state[e] = STATE_TREE; |
1118 | 1121 | if (_supply[u] >= 0) { |
1119 | | _forward[u] = true; |
| 1122 | _pred_dir[u] = DIR_UP; |
1120 | 1123 | _pi[u] = 0; |
1121 | 1124 | _source[e] = u; |
1122 | 1125 | _target[e] = _root; |
1123 | 1126 | _flow[e] = _supply[u]; |
1124 | 1127 | _cost[e] = 0; |
1125 | 1128 | } else { |
1126 | | _forward[u] = false; |
| 1129 | _pred_dir[u] = DIR_DOWN; |
1127 | 1130 | _pi[u] = ART_COST; |
1128 | 1131 | _source[e] = _root; |
1129 | 1132 | _target[e] = u; |
… |
… |
|
1143 | 1146 | _succ_num[u] = 1; |
1144 | 1147 | _last_succ[u] = u; |
1145 | 1148 | if (_supply[u] >= 0) { |
1146 | | _forward[u] = true; |
| 1149 | _pred_dir[u] = DIR_UP; |
1147 | 1150 | _pi[u] = 0; |
1148 | 1151 | _pred[u] = e; |
1149 | 1152 | _source[e] = u; |
… |
… |
|
1153 | 1156 | _cost[e] = 0; |
1154 | 1157 | _state[e] = STATE_TREE; |
1155 | 1158 | } else { |
1156 | | _forward[u] = false; |
| 1159 | _pred_dir[u] = DIR_DOWN; |
1157 | 1160 | _pi[u] = ART_COST; |
1158 | 1161 | _pred[u] = f; |
1159 | 1162 | _source[f] = _root; |
… |
… |
|
1184 | 1187 | _succ_num[u] = 1; |
1185 | 1188 | _last_succ[u] = u; |
1186 | 1189 | if (_supply[u] <= 0) { |
1187 | | _forward[u] = false; |
| 1190 | _pred_dir[u] = DIR_DOWN; |
1188 | 1191 | _pi[u] = 0; |
1189 | 1192 | _pred[u] = e; |
1190 | 1193 | _source[e] = _root; |
… |
… |
|
1194 | 1197 | _cost[e] = 0; |
1195 | 1198 | _state[e] = STATE_TREE; |
1196 | 1199 | } else { |
1197 | | _forward[u] = true; |
| 1200 | _pred_dir[u] = DIR_UP; |
1198 | 1201 | _pi[u] = -ART_COST; |
1199 | 1202 | _pred[u] = f; |
1200 | 1203 | _source[f] = u; |
… |
… |
|
1237 | 1240 | bool findLeavingArc() { |
1238 | 1241 | // Initialize first and second nodes according to the direction |
1239 | 1242 | // of the cycle |
| 1243 | int first, second; |
1240 | 1244 | if (_state[in_arc] == STATE_LOWER) { |
1241 | 1245 | first = _source[in_arc]; |
1242 | 1246 | second = _target[in_arc]; |
… |
… |
|
1246 | 1250 | } |
1247 | 1251 | delta = _cap[in_arc]; |
1248 | 1252 | int result = 0; |
1249 | | Value d; |
| 1253 | Value c, d; |
1250 | 1254 | int e; |
1251 | 1255 | |
1252 | | // Search the cycle along the path form the first node to the root |
| 1256 | // Search the cycle form the first node to the join node |
1253 | 1257 | for (int u = first; u != join; u = _parent[u]) { |
1254 | 1258 | e = _pred[u]; |
1255 | | d = _forward[u] ? |
1256 | | _flow[e] : (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]); |
| 1259 | d = _flow[e]; |
| 1260 | if (_pred_dir[u] == DIR_DOWN) { |
| 1261 | c = _cap[e]; |
| 1262 | d = c >= MAX ? INF : c - d; |
| 1263 | } |
1257 | 1264 | if (d < delta) { |
1258 | 1265 | delta = d; |
1259 | 1266 | u_out = u; |
1260 | 1267 | result = 1; |
1261 | 1268 | } |
1262 | 1269 | } |
1263 | | // Search the cycle along the path form the second node to the root |
| 1270 | |
| 1271 | // Search the cycle form the second node to the join node |
1264 | 1272 | for (int u = second; u != join; u = _parent[u]) { |
1265 | 1273 | e = _pred[u]; |
1266 | | d = _forward[u] ? |
1267 | | (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]) : _flow[e]; |
| 1274 | d = _flow[e]; |
| 1275 | if (_pred_dir[u] == DIR_UP) { |
| 1276 | c = _cap[e]; |
| 1277 | d = c >= MAX ? INF : c - d; |
| 1278 | } |
1268 | 1279 | if (d <= delta) { |
1269 | 1280 | delta = d; |
1270 | 1281 | u_out = u; |
… |
… |
|
1289 | 1300 | Value val = _state[in_arc] * delta; |
1290 | 1301 | _flow[in_arc] += val; |
1291 | 1302 | for (int u = _source[in_arc]; u != join; u = _parent[u]) { |
1292 | | _flow[_pred[u]] += _forward[u] ? -val : val; |
| 1303 | _flow[_pred[u]] -= _pred_dir[u] * val; |
1293 | 1304 | } |
1294 | 1305 | for (int u = _target[in_arc]; u != join; u = _parent[u]) { |
1295 | | _flow[_pred[u]] += _forward[u] ? val : -val; |
| 1306 | _flow[_pred[u]] += _pred_dir[u] * val; |
1296 | 1307 | } |
1297 | 1308 | } |
1298 | 1309 | // Update the state of the entering and leaving arcs |
… |
… |
|
1307 | 1318 | |
1308 | 1319 | // Update the tree structure |
1309 | 1320 | void updateTreeStructure() { |
1310 | | int u, w; |
1311 | 1321 | int old_rev_thread = _rev_thread[u_out]; |
1312 | 1322 | int old_succ_num = _succ_num[u_out]; |
1313 | 1323 | int old_last_succ = _last_succ[u_out]; |
1314 | 1324 | v_out = _parent[u_out]; |
1315 | 1325 | |
1316 | | u = _last_succ[u_in]; // the last successor of u_in |
1317 | | right = _thread[u]; // the node after it |
| 1326 | // Check if u_in and u_out coincide |
| 1327 | if (u_in == u_out) { |
| 1328 | // Update _parent, _pred, _pred_dir |
| 1329 | _parent[u_in] = v_in; |
| 1330 | _pred[u_in] = in_arc; |
| 1331 | _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; |
1318 | 1332 | |
1319 | | // Handle the case when old_rev_thread equals to v_in |
1320 | | // (it also means that join and v_out coincide) |
1321 | | if (old_rev_thread == v_in) { |
1322 | | last = _thread[_last_succ[u_out]]; |
| 1333 | // Update _thread and _rev_thread |
| 1334 | if (_thread[v_in] != u_out) { |
| 1335 | int after = _thread[old_last_succ]; |
| 1336 | _thread[old_rev_thread] = after; |
| 1337 | _rev_thread[after] = old_rev_thread; |
| 1338 | after = _thread[v_in]; |
| 1339 | _thread[v_in] = u_out; |
| 1340 | _rev_thread[u_out] = v_in; |
| 1341 | _thread[old_last_succ] = after; |
| 1342 | _rev_thread[after] = old_last_succ; |
| 1343 | } |
1323 | 1344 | } else { |
1324 | | last = _thread[v_in]; |
1325 | | } |
| 1345 | // Handle the case when old_rev_thread equals to v_in |
| 1346 | // (it also means that join and v_out coincide) |
| 1347 | int thread_continue = old_rev_thread == v_in ? |
| 1348 | _thread[old_last_succ] : _thread[v_in]; |
1326 | 1349 | |
1327 | | // Update _thread and _parent along the stem nodes (i.e. the nodes |
1328 | | // between u_in and u_out, whose parent have to be changed) |
1329 | | _thread[v_in] = stem = u_in; |
1330 | | _dirty_revs.clear(); |
1331 | | _dirty_revs.push_back(v_in); |
1332 | | par_stem = v_in; |
1333 | | while (stem != u_out) { |
1334 | | // Insert the next stem node into the thread list |
1335 | | new_stem = _parent[stem]; |
1336 | | _thread[u] = new_stem; |
1337 | | _dirty_revs.push_back(u); |
| 1350 | // Update _thread and _parent along the stem nodes (i.e. the nodes |
| 1351 | // between u_in and u_out, whose parent have to be changed) |
| 1352 | int stem = u_in; // the current stem node |
| 1353 | int par_stem = v_in; // the new parent of stem |
| 1354 | int next_stem; // the next stem node |
| 1355 | int last = _last_succ[u_in]; // the last successor of stem |
| 1356 | int before, after = _thread[last]; |
| 1357 | _thread[v_in] = u_in; |
| 1358 | _dirty_revs.clear(); |
| 1359 | _dirty_revs.push_back(v_in); |
| 1360 | while (stem != u_out) { |
| 1361 | // Insert the next stem node into the thread list |
| 1362 | next_stem = _parent[stem]; |
| 1363 | _thread[last] = next_stem; |
| 1364 | _dirty_revs.push_back(last); |
1338 | 1365 | |
1339 | | // Remove the subtree of stem from the thread list |
1340 | | w = _rev_thread[stem]; |
1341 | | _thread[w] = right; |
1342 | | _rev_thread[right] = w; |
| 1366 | // Remove the subtree of stem from the thread list |
| 1367 | before = _rev_thread[stem]; |
| 1368 | _thread[before] = after; |
| 1369 | _rev_thread[after] = before; |
1343 | 1370 | |
1344 | | // Change the parent node and shift stem nodes |
1345 | | _parent[stem] = par_stem; |
1346 | | par_stem = stem; |
1347 | | stem = new_stem; |
| 1371 | // Change the parent node and shift stem nodes |
| 1372 | _parent[stem] = par_stem; |
| 1373 | par_stem = stem; |
| 1374 | stem = next_stem; |
1348 | 1375 | |
1349 | | // Update u and right |
1350 | | u = _last_succ[stem] == _last_succ[par_stem] ? |
1351 | | _rev_thread[par_stem] : _last_succ[stem]; |
1352 | | right = _thread[u]; |
1353 | | } |
1354 | | _parent[u_out] = par_stem; |
1355 | | _thread[u] = last; |
1356 | | _rev_thread[last] = u; |
1357 | | _last_succ[u_out] = u; |
| 1376 | // Update last and after |
| 1377 | last = _last_succ[stem] == _last_succ[par_stem] ? |
| 1378 | _rev_thread[par_stem] : _last_succ[stem]; |
| 1379 | after = _thread[last]; |
| 1380 | } |
| 1381 | _parent[u_out] = par_stem; |
| 1382 | _thread[last] = thread_continue; |
| 1383 | _rev_thread[thread_continue] = last; |
| 1384 | _last_succ[u_out] = last; |
1358 | 1385 | |
1359 | | // Remove the subtree of u_out from the thread list except for |
1360 | | // the case when old_rev_thread equals to v_in |
1361 | | // (it also means that join and v_out coincide) |
1362 | | if (old_rev_thread != v_in) { |
1363 | | _thread[old_rev_thread] = right; |
1364 | | _rev_thread[right] = old_rev_thread; |
1365 | | } |
| 1386 | // Remove the subtree of u_out from the thread list except for |
| 1387 | // the case when old_rev_thread equals to v_in |
| 1388 | if (old_rev_thread != v_in) { |
| 1389 | _thread[old_rev_thread] = after; |
| 1390 | _rev_thread[after] = old_rev_thread; |
| 1391 | } |
1366 | 1392 | |
1367 | | // Update _rev_thread using the new _thread values |
1368 | | for (int i = 0; i != int(_dirty_revs.size()); ++i) { |
1369 | | u = _dirty_revs[i]; |
1370 | | _rev_thread[_thread[u]] = u; |
1371 | | } |
| 1393 | // Update _rev_thread using the new _thread values |
| 1394 | for (int i = 0; i != int(_dirty_revs.size()); ++i) { |
| 1395 | int u = _dirty_revs[i]; |
| 1396 | _rev_thread[_thread[u]] = u; |
| 1397 | } |
1372 | 1398 | |
1373 | | // Update _pred, _forward, _last_succ and _succ_num for the |
1374 | | // stem nodes from u_out to u_in |
1375 | | int tmp_sc = 0, tmp_ls = _last_succ[u_out]; |
1376 | | u = u_out; |
1377 | | while (u != u_in) { |
1378 | | w = _parent[u]; |
1379 | | _pred[u] = _pred[w]; |
1380 | | _forward[u] = !_forward[w]; |
1381 | | tmp_sc += _succ_num[u] - _succ_num[w]; |
1382 | | _succ_num[u] = tmp_sc; |
1383 | | _last_succ[w] = tmp_ls; |
1384 | | u = w; |
1385 | | } |
1386 | | _pred[u_in] = in_arc; |
1387 | | _forward[u_in] = (u_in == _source[in_arc]); |
1388 | | _succ_num[u_in] = old_succ_num; |
1389 | | |
1390 | | // Set limits for updating _last_succ form v_in and v_out |
1391 | | // towards the root |
1392 | | int up_limit_in = -1; |
1393 | | int up_limit_out = -1; |
1394 | | if (_last_succ[join] == v_in) { |
1395 | | up_limit_out = join; |
1396 | | } else { |
1397 | | up_limit_in = join; |
| 1399 | // Update _pred, _pred_dir, _last_succ and _succ_num for the |
| 1400 | // stem nodes from u_out to u_in |
| 1401 | int tmp_sc = 0, tmp_ls = _last_succ[u_out]; |
| 1402 | for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) { |
| 1403 | _pred[u] = _pred[p]; |
| 1404 | _pred_dir[u] = -_pred_dir[p]; |
| 1405 | tmp_sc += _succ_num[u] - _succ_num[p]; |
| 1406 | _succ_num[u] = tmp_sc; |
| 1407 | _last_succ[p] = tmp_ls; |
| 1408 | } |
| 1409 | _pred[u_in] = in_arc; |
| 1410 | _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; |
| 1411 | _succ_num[u_in] = old_succ_num; |
1398 | 1412 | } |
1399 | 1413 | |
1400 | 1414 | // Update _last_succ from v_in towards the root |
1401 | | for (u = v_in; u != up_limit_in && _last_succ[u] == v_in; |
1402 | | u = _parent[u]) { |
1403 | | _last_succ[u] = _last_succ[u_out]; |
| 1415 | int up_limit_out = _last_succ[join] == v_in ? join : -1; |
| 1416 | int last_succ_out = _last_succ[u_out]; |
| 1417 | for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) { |
| 1418 | _last_succ[u] = last_succ_out; |
1404 | 1419 | } |
| 1420 | |
1405 | 1421 | // Update _last_succ from v_out towards the root |
1406 | 1422 | if (join != old_rev_thread && v_in != old_rev_thread) { |
1407 | | for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; |
| 1423 | for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; |
1408 | 1424 | u = _parent[u]) { |
1409 | 1425 | _last_succ[u] = old_rev_thread; |
1410 | 1426 | } |
1411 | | } else { |
1412 | | for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; |
| 1427 | } |
| 1428 | else if (last_succ_out != old_last_succ) { |
| 1429 | for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; |
1413 | 1430 | u = _parent[u]) { |
1414 | | _last_succ[u] = _last_succ[u_out]; |
| 1431 | _last_succ[u] = last_succ_out; |
1415 | 1432 | } |
1416 | 1433 | } |
1417 | 1434 | |
1418 | 1435 | // Update _succ_num from v_in to join |
1419 | | for (u = v_in; u != join; u = _parent[u]) { |
| 1436 | for (int u = v_in; u != join; u = _parent[u]) { |
1420 | 1437 | _succ_num[u] += old_succ_num; |
1421 | 1438 | } |
1422 | 1439 | // Update _succ_num from v_out to join |
1423 | | for (u = v_out; u != join; u = _parent[u]) { |
| 1440 | for (int u = v_out; u != join; u = _parent[u]) { |
1424 | 1441 | _succ_num[u] -= old_succ_num; |
1425 | 1442 | } |
1426 | 1443 | } |
1427 | 1444 | |
1428 | | // Update potentials |
| 1445 | // Update potentials in the subtree that has been moved |
1429 | 1446 | void updatePotential() { |
1430 | | Cost sigma = _forward[u_in] ? |
1431 | | _pi[v_in] - _pi[u_in] - _cost[_pred[u_in]] : |
1432 | | _pi[v_in] - _pi[u_in] + _cost[_pred[u_in]]; |
1433 | | // Update potentials in the subtree, which has been moved |
| 1447 | Cost sigma = _pi[v_in] - _pi[u_in] - |
| 1448 | _pred_dir[u_in] * _cost[in_arc]; |
1434 | 1449 | int end = _thread[_last_succ[u_in]]; |
1435 | 1450 | for (int u = u_in; u != end; u = _thread[u]) { |
1436 | 1451 | _pi[u] += sigma; |