@@ -28,26 +28,26 @@ concept edge_weight_function2 = // e.g. weight(uv)
28
28
basic_edge_weight_function2<G, WF, Distance, less<range_value_t <Distance>>, plus<range_value_t <Distance>>>;
29
29
30
30
31
- class null_range_type : public std ::vector<size_t > {
31
+ class _null_range_type : public std ::vector<size_t > {
32
32
using T = size_t ;
33
33
using Allocator = std::allocator<T>;
34
34
using Base = std::vector<T, Allocator>;
35
35
36
36
public:
37
- null_range_type () noexcept (noexcept (Allocator())) = default ;
38
- explicit null_range_type (const Allocator& alloc) noexcept {}
39
- null_range_type (Base::size_type count, const T& value, const Allocator& alloc = Allocator()) {}
40
- explicit null_range_type (Base::size_type count, const Allocator& alloc = Allocator()) {}
37
+ _null_range_type () noexcept (noexcept (Allocator())) = default ;
38
+ explicit _null_range_type (const Allocator& alloc) noexcept {}
39
+ _null_range_type (Base::size_type count, const T& value, const Allocator& alloc = Allocator()) {}
40
+ explicit _null_range_type (Base::size_type count, const Allocator& alloc = Allocator()) {}
41
41
template <class InputIt >
42
- null_range_type (InputIt first, InputIt last, const Allocator& alloc = Allocator()) {}
43
- null_range_type (const null_range_type & other) : Base() {}
44
- null_range_type (const null_range_type & other, const Allocator& alloc) {}
45
- null_range_type (null_range_type && other) noexcept {}
46
- null_range_type (null_range_type && other, const Allocator& alloc) {}
47
- null_range_type (std::initializer_list<T> init, const Allocator& alloc = Allocator()) {}
42
+ _null_range_type (InputIt first, InputIt last, const Allocator& alloc = Allocator()) {}
43
+ _null_range_type (const _null_range_type & other) : Base() {}
44
+ _null_range_type (const _null_range_type & other, const Allocator& alloc) {}
45
+ _null_range_type (_null_range_type && other) noexcept {}
46
+ _null_range_type (_null_range_type && other, const Allocator& alloc) {}
47
+ _null_range_type (std::initializer_list<T> init, const Allocator& alloc = Allocator()) {}
48
48
};
49
49
50
- inline static null_range_type null_predecessors;
50
+ inline static _null_range_type null_predecessors;
51
51
52
52
53
53
template <class ... Ts>
@@ -80,6 +80,9 @@ constexpr auto print_types(Ts...) {
80
80
* The edge weight function must not throw an exception.
81
81
* The edge weight function must not modify the graph, the edge, or the vertex (nor any of their associated data).
82
82
*/
83
+
84
+ #if 1 // not using Identifiers (original)
85
+
83
86
template <adjacency_list G,
84
87
random_access_range Distance,
85
88
random_access_range Predecessor,
@@ -101,7 +104,7 @@ void dijkstra_clrs(
101
104
102
105
// Remark(Andrew): Do we want to allow null distance? What about if both are null? Still run algorithm at all?
103
106
104
- size_t N (size ( vertices ( g))); // Question(Andrew): Do we want a num_vertices(g) CPO?
107
+ size_t N (num_vertices ( g));
105
108
assert (seed < N && seed >= 0 );
106
109
107
110
std::ranges::fill (distance, std::numeric_limits<weight_type>::max ());
@@ -129,12 +132,68 @@ void dijkstra_clrs(
129
132
// weight_type w = weight(uv);
130
133
if (distance[uid] + w < distance[vid]) {
131
134
distance[vid] = distance[uid] + w;
132
- if constexpr (!is_same_v<Predecessor, null_range_type>)
135
+ if constexpr (!is_same_v<Predecessor, _null_range_type>)
136
+ predecessor[vid] = uid;
137
+ Q.push ({vid, distance[vid]});
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ #else // using Identifiers
144
+
145
+ template <adjacency_list G,
146
+ random_access_range Distance,
147
+ random_access_range Predecessor,
148
+ class WF = function<range_value_t<Distance>(edge_identifier_t<G>)>>
149
+ requires random_access_range<vertex_range_t<G>> && //
150
+ integral<vertex_id_t<G>> && //
151
+ is_arithmetic_v<range_value_t<Distance>> && //
152
+ convertible_to<vertex_id_t<G>, range_value_t<Predecessor>> && //
153
+ edge_weight_function<G, WF>
154
+ void dijkstra_clrs(
155
+ G&& g, // graph
156
+ vertex_identifier_t<G> seed, // starting vertex_id
157
+ Distance& distance, // out: distance[uid] of uid from seed
158
+ Predecessor& predecessor, // out: predecessor[uid] of uid in path
159
+ WF&& weight = [](edge_identifier_t<G> uv) { return range_value_t<Distance>(1); }) // default weight(uv) -> 1
160
+ {
161
+ using id_type = vertex_id_t<G>;
162
+ using weight_type = invoke_result_t<WF, edge_identifer_t<G>>;
163
+ const id_type seed_id = vertex_id(g, seed);
164
+
165
+ size_t N(num_vertices(g));
166
+ assert(seed_id < N && seed_id >= 0);
167
+
168
+ std::ranges::fill(distance, std::numeric_limits<weight_type>::max());
169
+ distance[seed_id] = 0;
170
+
171
+ struct weighted_vertex {
172
+ id_type vertex_id = id_type();
173
+ weight_type weight = weight_type();
174
+ };
175
+
176
+ using q_compare = decltype([](const weighted_vertex& a, const weighted_vertex& b) { return a.weight > b.weight; });
177
+ std::priority_queue<weighted_vertex, std::vector<weighted_vertex>, q_compare> Q;
178
+
179
+ Q.push({seed_id, distance[seed_id]});
180
+
181
+ while (!Q.empty()) {
182
+ auto uid = Q.top().vertex_id;
183
+ Q.pop();
184
+
185
+ for (auto&& [v_identifier, uv_identifier, w] : views::incidence(g, find_vertex(g, uid), weight)) {
186
+ id_type vid = vertex_id(v_identifier);
187
+ if (distance[uid] + w < distance[vid]) {
188
+ distance[vid] = distance[uid] + w;
189
+ if constexpr (!is_same_v<Predecessor, _null_range_type>)
133
190
predecessor[vid] = uid;
134
191
Q.push({vid, distance[vid]});
135
192
}
136
193
}
137
194
}
138
195
}
139
196
197
+ #endif // Identifiers
198
+
140
199
} // namespace graph
0 commit comments