forked from Project-OSRM/osrm-backend
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathstatic_graph.hpp
326 lines (269 loc) · 10.4 KB
/
static_graph.hpp
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#ifndef STATIC_GRAPH_HPP
#define STATIC_GRAPH_HPP
#include "util/graph_traits.hpp"
#include "util/integer_range.hpp"
#include "util/percent.hpp"
#include "util/permutation.hpp"
#include "util/typedefs.hpp"
#include "util/vector_view.hpp"
#include "storage/shared_memory_ownership.hpp"
#include "storage/tar_fwd.hpp"
#include <boost/assert.hpp>
#include <algorithm>
#include <limits>
#include <type_traits>
#include <utility>
#include <vector>
namespace osrm
{
namespace util
{
template <typename EdgeDataT, storage::Ownership Ownership> class StaticGraph;
namespace serialization
{
template <typename EdgeDataT, storage::Ownership Ownership>
void read(storage::tar::FileReader &reader,
const std::string &name,
StaticGraph<EdgeDataT, Ownership> &graph);
template <typename EdgeDataT, storage::Ownership Ownership>
void write(storage::tar::FileWriter &writer,
const std::string &name,
const StaticGraph<EdgeDataT, Ownership> &graph);
}
namespace static_graph_details
{
using NodeIterator = NodeID;
using EdgeIterator = NodeID;
struct NodeArrayEntry
{
// index of the first edge
EdgeIterator first_edge;
};
template <typename EdgeDataT> struct EdgeArrayEntry;
template <typename EdgeDataT> struct EdgeArrayEntry
{
NodeID target;
EdgeDataT data;
};
template <> struct EdgeArrayEntry<void>
{
NodeID target;
};
template <typename EdgeDataT> struct SortableEdgeWithData;
template <> struct SortableEdgeWithData<void>
{
NodeIterator source;
NodeIterator target;
SortableEdgeWithData() = default;
SortableEdgeWithData(NodeIterator source, NodeIterator target) : source(source), target(target)
{
}
bool operator<(const SortableEdgeWithData &right) const
{
return std::tie(source, target) < std::tie(right.source, right.target);
}
bool operator==(const SortableEdgeWithData &right) const
{
return std::tie(source, target) == std::tie(right.source, right.target);
}
};
template <typename EdgeDataT> struct SortableEdgeWithData : SortableEdgeWithData<void>
{
using Base = SortableEdgeWithData<void>;
EdgeDataT data;
SortableEdgeWithData() = default;
template <typename... Ts>
SortableEdgeWithData(NodeIterator source, NodeIterator target, Ts &&... data)
: Base{source, target}, data{std::forward<Ts>(data)...}
{
}
};
template <typename EntryT, typename OtherEdge>
EntryT edgeToEntry(const OtherEdge &from, std::true_type)
{
return EntryT{from.target, from.data};
}
template <typename EntryT, typename OtherEdge>
EntryT edgeToEntry(const OtherEdge &from, std::false_type)
{
return EntryT{from.target};
}
} // namespace static_graph_details
template <typename EdgeDataT, storage::Ownership Ownership = storage::Ownership::Container>
class StaticGraph
{
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
public:
using InputEdge = static_graph_details::SortableEdgeWithData<EdgeDataT>;
using NodeIterator = static_graph_details::NodeIterator;
using EdgeIterator = static_graph_details::EdgeIterator;
using EdgeRange = range<EdgeIterator>;
using NodeArrayEntry = static_graph_details::NodeArrayEntry;
using EdgeArrayEntry = static_graph_details::EdgeArrayEntry<EdgeDataT>;
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
{
return irange(BeginEdges(node), EndEdges(node));
}
StaticGraph() {}
template <typename ContainerT> StaticGraph(const std::uint32_t nodes, const ContainerT &edges)
{
BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(edges).begin(),
const_cast<ContainerT &>(edges).end()));
InitializeFromSortedEdgeRange(nodes, edges.begin(), edges.end());
}
StaticGraph(Vector<NodeArrayEntry> node_array_, Vector<EdgeArrayEntry> edge_array_)
: node_array(std::move(node_array_)), edge_array(std::move(edge_array_))
{
BOOST_ASSERT(!node_array.empty());
number_of_nodes = static_cast<decltype(number_of_nodes)>(node_array.size() - 1);
number_of_edges = static_cast<decltype(number_of_edges)>(node_array.back().first_edge);
BOOST_ASSERT(number_of_edges <= edge_array.size());
BOOST_ASSERT(number_of_nodes == node_array.size() - 1);
}
unsigned GetNumberOfNodes() const { return number_of_nodes; }
unsigned GetNumberOfEdges() const { return number_of_edges; }
unsigned GetOutDegree(const NodeIterator n) const { return EndEdges(n) - BeginEdges(n); }
inline NodeIterator GetTarget(const EdgeIterator e) const
{
return NodeIterator(edge_array[e].target);
}
auto &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
const auto &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; }
EdgeIterator BeginEdges(const NodeIterator n) const
{
return EdgeIterator(node_array.at(n).first_edge);
}
EdgeIterator EndEdges(const NodeIterator n) const
{
return EdgeIterator(node_array.at(n + 1).first_edge);
}
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
for (const auto i : irange(BeginEdges(from), EndEdges(from)))
{
if (to == edge_array[i].target)
{
return i;
}
}
return SPECIAL_EDGEID;
}
/**
* Finds the edge with the smallest `.weight` going from `from` to `to`
* @param from the source node ID
* @param to the target node ID
* @param filter a functor that returns a `bool` that determines whether an edge should be
* tested or not.
* Takes `EdgeData` as a parameter.
* @return the ID of the smallest edge if any were found that satisfied *filter*, or
* `SPECIAL_EDGEID` if no
* matching edge is found.
*/
template <typename FilterFunction>
EdgeIterator
FindSmallestEdge(const NodeIterator from, const NodeIterator to, FilterFunction &&filter) const
{
static_assert(traits::HasDataMember<EdgeArrayEntry>::value,
"Filtering on .data not possible without .data member attribute");
EdgeIterator smallest_edge = SPECIAL_EDGEID;
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
for (auto edge : GetAdjacentEdgeRange(from))
{
const NodeID target = GetTarget(edge);
const auto &data = GetEdgeData(edge);
if (target == to && data.weight < smallest_weight &&
std::forward<FilterFunction>(filter)(data))
{
smallest_edge = edge;
smallest_weight = data.weight;
}
}
return smallest_edge;
}
EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
{
EdgeIterator tmp = FindEdge(from, to);
return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
}
EdgeIterator
FindEdgeIndicateIfReverse(const NodeIterator from, const NodeIterator to, bool &result) const
{
EdgeIterator current_iterator = FindEdge(from, to);
if (SPECIAL_NODEID == current_iterator)
{
current_iterator = FindEdge(to, from);
if (SPECIAL_NODEID != current_iterator)
{
result = true;
}
}
return current_iterator;
}
void Renumber(const std::vector<NodeID> &old_to_new_node)
{
std::vector<NodeID> new_to_old_node(number_of_nodes);
for (auto node : util::irange<NodeID>(0, number_of_nodes))
new_to_old_node[old_to_new_node[node]] = node;
Vector<NodeArrayEntry> new_node_array(node_array.size());
// Build up edge permutation
auto new_edge_index = 0;
std::vector<EdgeID> old_to_new_edge(edge_array.size(), SPECIAL_EDGEID);
for (auto node : util::irange<NodeID>(0, number_of_nodes))
{
auto new_first_edge = new_edge_index;
for (auto edge : GetAdjacentEdgeRange(new_to_old_node[node]))
{
edge_array[edge].target = old_to_new_node[edge_array[edge].target];
old_to_new_edge[edge] = new_edge_index++;
}
new_node_array[node].first_edge = new_first_edge;
}
new_node_array.back().first_edge = new_edge_index;
node_array = std::move(new_node_array);
BOOST_ASSERT(std::find(old_to_new_edge.begin(), old_to_new_edge.end(), SPECIAL_EDGEID) ==
old_to_new_edge.end());
util::inplacePermutation(edge_array.begin(), edge_array.end(), old_to_new_edge);
}
friend void serialization::read<EdgeDataT, Ownership>(storage::tar::FileReader &reader,
const std::string &name,
StaticGraph<EdgeDataT, Ownership> &graph);
friend void
serialization::write<EdgeDataT, Ownership>(storage::tar::FileWriter &writer,
const std::string &name,
const StaticGraph<EdgeDataT, Ownership> &graph);
protected:
template <typename IterT>
void InitializeFromSortedEdgeRange(const std::uint32_t nodes, IterT begin, IterT end)
{
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(std::distance(begin, end));
node_array.reserve(number_of_nodes + 1);
node_array.push_back(NodeArrayEntry{0u});
auto iter = begin;
for (auto node : util::irange(0u, nodes))
{
iter =
std::find_if(iter, end, [node](const auto &edge) { return edge.source != node; });
unsigned offset = std::distance(begin, iter);
node_array.push_back(NodeArrayEntry{offset});
}
BOOST_ASSERT_MSG(
iter == end,
("Still " + std::to_string(std::distance(iter, end)) + " edges left.").c_str());
BOOST_ASSERT(node_array.size() == number_of_nodes + 1);
edge_array.resize(number_of_edges);
std::transform(begin, end, edge_array.begin(), [](const auto &from) {
return static_graph_details::edgeToEntry<EdgeArrayEntry>(
from, traits::HasDataMember<EdgeArrayEntry>{});
});
}
protected:
NodeIterator number_of_nodes;
EdgeIterator number_of_edges;
Vector<NodeArrayEntry> node_array;
Vector<EdgeArrayEntry> edge_array;
};
} // namespace util
} // namespace osrm
#endif // STATIC_GRAPH_HPP