forked from Project-OSRM/osrm-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecursive_bisection_state.cpp
184 lines (154 loc) · 6.97 KB
/
recursive_bisection_state.cpp
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include "partition/recursive_bisection_state.hpp"
#include "extractor/tarjan_scc.hpp"
#include "partition/tarjan_graph_wrapper.hpp"
#include <algorithm>
#include <climits> // for CHAR_BIT
#include <numeric>
#include <set>
#include <unordered_map>
namespace osrm
{
namespace partition
{
RecursiveBisectionState::RecursiveBisectionState(BisectionGraph &bisection_graph_)
: scc_levels(0), bisection_graph(bisection_graph_)
{
bisection_ids.resize(bisection_graph.NumberOfNodes(), BisectionID{0});
}
RecursiveBisectionState::~RecursiveBisectionState() {}
BisectionID RecursiveBisectionState::GetBisectionID(const NodeID node) const
{
return bisection_ids[node];
}
RecursiveBisectionState::NodeIterator
RecursiveBisectionState::ApplyBisection(const NodeIterator const_begin,
const NodeIterator const_end,
const std::size_t depth,
const std::vector<bool> &partition)
{
BOOST_ASSERT(depth >= scc_levels);
// ensure that the iterators belong to the graph
BOOST_ASSERT(bisection_graph.GetID(*const_begin) < bisection_graph.NumberOfNodes() &&
bisection_graph.GetID(*const_begin) + std::distance(const_begin, const_end) <=
bisection_graph.NumberOfNodes());
// augment the partition ids
const auto flag = BisectionID{1} << (sizeof(BisectionID) * CHAR_BIT - depth - 1);
for (auto itr = const_begin; itr != const_end; ++itr)
{
const auto nid = std::distance(const_begin, itr);
if (partition[nid])
bisection_ids[itr->original_id] |= flag;
}
// Keep items with `0` as partition id to the left, move other to the right
auto by_flag_bit = [this, flag](const auto &node) {
return BisectionID{0} == (bisection_ids[node.original_id] & flag);
};
auto begin = bisection_graph.Begin() + std::distance(bisection_graph.CBegin(), const_begin);
const auto end = begin + std::distance(const_begin, const_end);
// remap the edges
std::vector<NodeID> mapping(std::distance(const_begin, const_end), SPECIAL_NODEID);
// calculate a mapping of all node ids
std::size_t lesser_id = 0, upper_id = 0;
std::transform(const_begin,
const_end,
mapping.begin(),
[by_flag_bit, &lesser_id, &upper_id](const auto &node) {
return by_flag_bit(node) ? lesser_id++ : upper_id++;
});
// erase all edges that point into different partitions
std::for_each(begin, end, [&](auto &node) {
const auto node_flag = by_flag_bit(node);
bisection_graph.RemoveEdges(node, [&](const BisectionGraph::EdgeT &edge) {
const auto target_flag = by_flag_bit(*(const_begin + edge.target));
return (node_flag != target_flag);
});
});
auto center = std::stable_partition(begin, end, by_flag_bit);
// remap all remaining edges
std::for_each(const_begin, const_end, [&](const auto &node) {
for (auto &edge : bisection_graph.Edges(node))
edge.target = mapping[edge.target];
});
return const_begin + std::distance(begin, center);
}
std::vector<GraphView>
RecursiveBisectionState::PrePartitionWithSCC(const std::size_t small_component_size)
{
// since our graphs are unidirectional, we don't realy need the scc. But tarjan is so nice and
// assigns IDs and counts sizes
TarjanGraphWrapper wrapped_graph(bisection_graph);
extractor::TarjanSCC<TarjanGraphWrapper> scc_algo(wrapped_graph);
scc_algo.Run();
// Map Edges to Sccs
const auto in_small = [&scc_algo, small_component_size](const NodeID node_id) {
return scc_algo.GetComponentSize(scc_algo.GetComponentID(node_id)) <= small_component_size;
};
const constexpr std::size_t small_component_id = -1;
std::unordered_map<std::size_t, std::size_t> component_map;
const auto transform_id = [&](const NodeID node_id) -> std::size_t {
if (in_small(node_id))
return small_component_id;
else
return scc_algo.GetComponentID(node_id);
};
std::vector<NodeID> mapping(bisection_graph.NumberOfNodes(), SPECIAL_NODEID);
for (const auto &node : bisection_graph.Nodes())
mapping[node.original_id] = component_map[transform_id(node.original_id)]++;
// needs to remove edges, if we should ever switch to directed graphs here
std::stable_sort(
bisection_graph.Begin(), bisection_graph.End(), [&](const auto &lhs, const auto &rhs) {
return transform_id(lhs.original_id) < transform_id(rhs.original_id);
});
// remap all remaining edges
std::for_each(bisection_graph.Begin(), bisection_graph.End(), [&](const auto &node) {
for (auto &edge : bisection_graph.Edges(node))
edge.target = mapping[edge.target];
});
std::vector<GraphView> views;
auto last = bisection_graph.CBegin();
auto last_id = transform_id(bisection_graph.Begin()->original_id);
std::set<std::size_t> ordered_component_ids;
for (auto itr = bisection_graph.CBegin(); itr != bisection_graph.CEnd(); ++itr)
{
auto itr_id = transform_id(itr->original_id);
ordered_component_ids.insert(itr_id);
if (last_id != itr_id)
{
views.push_back(GraphView(bisection_graph, last, itr));
last_id = itr_id;
last = itr;
}
}
views.push_back(GraphView(bisection_graph, last, bisection_graph.CEnd()));
bool has_small_component = [&]() {
for (std::size_t i = 0; i < scc_algo.GetNumberOfComponents(); ++i)
if (scc_algo.GetComponentSize(i) <= small_component_size)
return true;
return false;
}();
if (!has_small_component)
views.push_back(GraphView(bisection_graph, bisection_graph.CEnd(), bisection_graph.CEnd()));
// apply scc as bisections, we need scc_level bits for this with scc_levels =
// ceil(log_2(components))
scc_levels = ceil(log(views.size()) / log(2.0));
const auto conscutive_component_id = [&](const NodeID nid) {
const auto component_id = transform_id(nid);
const auto itr = ordered_component_ids.find(component_id);
BOOST_ASSERT(itr != ordered_component_ids.end());
BOOST_ASSERT(static_cast<std::size_t>(std::distance(ordered_component_ids.begin(), itr)) <
ordered_component_ids.size());
return std::distance(ordered_component_ids.begin(), itr);
};
const auto shift = sizeof(BisectionID) * CHAR_BIT - scc_levels;
// store the component ids as first part of the bisection id
for (const auto &node : bisection_graph.Nodes())
bisection_ids[node.original_id] = conscutive_component_id(node.original_id) << shift;
return views;
}
const std::vector<BisectionID> &RecursiveBisectionState::BisectionIDs() const
{
return bisection_ids;
}
std::uint32_t RecursiveBisectionState::SCCDepth() const { return scc_levels; }
} // namespace partition
} // namespace osrm