@@ -120,42 +120,45 @@ using adj_list::index_vertex_range;
120120// We use std::remove_reference_t<G> in WF default types, invoke_result_t, and concept
121121// constraints so that "const std::remove_reference_t<G>&" always means a true const ref.
122122// Default lambdas use "const auto&" instead of "const G&" to sidestep the issue entirely.
123- template <adjacency_list G,
124- input_range Sources,
125- class Distances ,
126- class Predecessors ,
127- class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
128- class Visitor = empty_visitor,
129- class Compare = less<vertex_property_map_value_t <Distances>>,
130- class Combine = plus<vertex_property_map_value_t <Distances>>>
131- requires vertex_property_map_for<Distances, G> && //
132- (is_null_range_v<Predecessors> || vertex_property_map_for<Predecessors, G>) && //
133- convertible_to<range_value_t <Sources>, vertex_id_t <G>> && //
134- is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
123+ template <
124+ adjacency_list G,
125+ input_range Sources,
126+ class Distances ,
127+ class Predecessors ,
128+ class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
129+ class Visitor = empty_visitor,
130+ class Compare = less<vertex_property_map_value_t <Distances>>,
131+ class Combine = plus<vertex_property_map_value_t <Distances>>>
132+ requires vertex_property_map_for<Distances, G> && //
133+ (is_null_range_v<Predecessors> || vertex_property_map_for<Predecessors, G>) && //
134+ convertible_to<range_value_t <Sources>, vertex_id_t <G>> && //
135+ is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
135136 basic_edge_weight_function<G, WF, vertex_property_map_value_t <Distances>, Compare, Combine>
136137constexpr void dijkstra_shortest_paths (
137138 G&& g,
138139 const Sources& sources,
139140 Distances& distances,
140141 Predecessors& predecessor,
141- WF&& weight = [](const auto &,
142- const edge_t <G>& uv) { return vertex_property_map_value_t <Distances>(1 ); }, // default weight(g, uv) -> 1
143- Visitor&& visitor = empty_visitor(),
144- Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
145- Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
142+ WF&& weight =
143+ [](const auto &, const edge_t <G>& uv) {
144+ return vertex_property_map_value_t <Distances>(1 );
145+ }, // default weight(g, uv) -> 1
146+ Visitor&& visitor = empty_visitor(),
147+ Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
148+ Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
146149 using id_type = vertex_id_t <G>;
147150 using distance_type = vertex_property_map_value_t <Distances>;
148151 using weight_type = invoke_result_t <WF, const std::remove_reference_t <G>&, edge_t <G>>;
149152
150153 // relaxing the target is the function of reducing the distance from the source to the target
151154 auto relax_target = [&g, &predecessor, &distances, &compare, &combine] //
152- (const edge_t <G>& e , const vertex_id_t <G>& uid, const weight_type& w_e ) -> bool {
153- const id_type vid = target_id (g, e );
155+ (const edge_t <G>& uv , const vertex_id_t <G>& uid, const weight_type& w ) -> bool {
156+ const id_type vid = target_id (g, uv );
154157 const distance_type d_u = distances[uid];
155158 const distance_type d_v = distances[vid];
156159
157- if (compare (combine (d_u, w_e ), d_v)) {
158- distances[vid] = combine (d_u, w_e );
160+ if (compare (combine (d_u, w ), d_v)) {
161+ distances[vid] = combine (d_u, w );
159162 if constexpr (!is_null_range_v<Predecessors>) {
160163 predecessor[vid] = uid;
161164 }
@@ -182,60 +185,65 @@ constexpr void dijkstra_shortest_paths(
182185 constexpr auto zero = shortest_path_zero<distance_type>();
183186 constexpr auto infinite = shortest_path_infinite_distance<distance_type>();
184187
185- // Priority queue stores vertex descriptors — lightweight 8-byte values (index or iterator),
186- // eliminating string copies for map-based graphs and enabling O(1) vertex_id extraction.
187- using vertex_desc = vertex_t <std::remove_reference_t <G>>;
188- auto qcompare = [&g, &distances](vertex_desc a, vertex_desc b) {
189- return distances[vertex_id (g, a)] > distances[vertex_id (g, b)];
188+ struct weighted_vertex {
189+ vertex_t <std::remove_reference_t <G>> vertex_desc = {};
190+ distance_type weight = distance_type();
190191 };
191- using Queue = std::priority_queue<vertex_desc, std::vector<vertex_desc>, decltype (qcompare)>;
192+ auto qcompare = [&compare](const weighted_vertex& a, const weighted_vertex& b) {
193+ return compare (b.weight , a.weight ); // min-heap: pop lowest weight first
194+ };
195+ using Queue = std::priority_queue<weighted_vertex, std::vector<weighted_vertex>, decltype (qcompare)>;
192196 Queue queue (qcompare);
193197
194198 // (The optimizer removes this loop if on_initialize_vertex() is empty.)
195- if constexpr (has_on_initialize_vertex<G, Visitor>) {
196- for (auto && [uid, u] : views::vertexlist (g)) {
197- visitor.on_initialize_vertex (g, u);
198- }
199- } else if constexpr (has_on_initialize_vertex_id<G, Visitor>) {
199+ if constexpr (has_on_initialize_vertex<G, Visitor> || has_on_initialize_vertex_id<G, Visitor>) {
200200 for (auto && [uid, u] : views::vertexlist (g)) {
201- visitor.on_initialize_vertex (g, uid);
201+ if constexpr (has_on_initialize_vertex<G, Visitor>) {
202+ visitor.on_initialize_vertex (g, u);
203+ } else if constexpr (has_on_initialize_vertex_id<G, Visitor>) {
204+ visitor.on_initialize_vertex (g, uid);
205+ }
202206 }
203207 }
204208
205209 // Seed the queue with the initial vertice(s)
206- for (auto && source : sources) {
210+ for (auto && uid : sources) {
211+ vertex_t <G> u;
207212 if constexpr (index_vertex_range<std::remove_reference_t <G>>) {
208- if (source >= num_vertices (g)) {
209- throw std::out_of_range (std::format (" dijkstra_shortest_paths: source vertex id '{}' is out of range" , source));
213+ if (uid >= num_vertices (g)) {
214+ throw std::out_of_range (
215+ std::format (" dijkstra_shortest_paths: uid vertex id '{}' is out of range" , uid));
210216 }
217+ u = *find_vertex (g, uid);
211218 } else {
212- if (find_vertex (g, source) == std::ranges::end (vertices (g))) {
213- throw std::out_of_range (std::format (" dijkstra_shortest_paths: source vertex id '{}' is out of range" , source));
219+ auto v_it = find_vertex (g, uid);
220+ if (v_it == std::ranges::end (vertices (g))) {
221+ throw std::out_of_range (
222+ std::format (" dijkstra_shortest_paths: uid vertex id '{}' is out of range" , uid));
214223 }
224+ u = *v_it;
215225 }
216- auto s_desc = *find_vertex (g, source);
217- queue.push (s_desc);
218- distances[source] = zero; // mark source as discovered
226+ distances[uid] = zero; // mark uid as discovered
227+ queue.push ({u, zero});
219228 if constexpr (has_on_discover_vertex<G, Visitor>) {
220- visitor.on_discover_vertex (g, s_desc );
229+ visitor.on_discover_vertex (g, u );
221230 } else if constexpr (has_on_discover_vertex_id<G, Visitor>) {
222- visitor.on_discover_vertex (g, source );
231+ visitor.on_discover_vertex (g, uid );
223232 }
224233 }
225234
226235 // Main loop to process the queue
227236 while (!queue.empty ()) {
228- auto u = queue.top ();
237+ auto [u, w] = queue.top ();
229238 queue.pop ();
230- const id_type uid = vertex_id (g, u); // O(1) extraction from descriptor
239+ const id_type uid = vertex_id (g, u);
231240 if constexpr (has_on_examine_vertex<G, Visitor>) {
232- visitor.on_examine_vertex (g, u); // descriptor already available, no find_vertex
241+ visitor.on_examine_vertex (g, u);
233242 } else if constexpr (has_on_examine_vertex_id<G, Visitor>) {
234243 visitor.on_examine_vertex (g, uid);
235244 }
236245
237246 // Process all outgoing edges from the current vertex
238- // Using descriptor directly avoids find_vertex for incidence view creation
239247 for (auto && [vid, uv, w] : views::incidence (g, u, weight)) {
240248 if constexpr (has_on_examine_edge<G, Visitor>) {
241249 visitor.on_examine_edge (g, uv);
@@ -258,14 +266,12 @@ constexpr void dijkstra_shortest_paths(
258266 if constexpr (has_on_edge_relaxed<G, Visitor>) {
259267 visitor.on_edge_relaxed (g, uv);
260268 }
261- // Convert target_id to descriptor once; serves both visitor and queue push
262- auto v_desc = *find_vertex (g, vid);
263269 if constexpr (has_on_discover_vertex<G, Visitor>) {
264- visitor.on_discover_vertex (g, v_desc );
270+ visitor.on_discover_vertex (g, * find_vertex (g, vid) );
265271 } else if constexpr (has_on_discover_vertex_id<G, Visitor>) {
266272 visitor.on_discover_vertex (g, vid);
267273 }
268- queue.push (v_desc); // push descriptor (8 bytes ), not vertex ID
274+ queue.push ({* find_vertex (g, vid ), distances[vid]});
269275 } else {
270276 // This is an indicator of a bug in the algorithm and should be investigated.
271277 throw std::logic_error (
@@ -277,7 +283,7 @@ constexpr void dijkstra_shortest_paths(
277283 if constexpr (has_on_edge_relaxed<G, Visitor>) {
278284 visitor.on_edge_relaxed (g, uv);
279285 }
280- queue.push (*find_vertex (g, vid)); // re-enqueue descriptor to re-evaluate
286+ queue.push ({ *find_vertex (g, vid), distances[vid]} ); // re-enqueue with updated distance
281287 } else {
282288 if constexpr (has_on_edge_not_relaxed<G, Visitor>) {
283289 visitor.on_edge_not_relaxed (g, uv);
@@ -290,8 +296,9 @@ constexpr void dijkstra_shortest_paths(
290296 // and another path to this vertex has a lower accumulated weight, we'll process it again.
291297 // A consequence is that examine_vertex could be called twice (or more) on the same vertex.
292298 if constexpr (has_on_finish_vertex<G, Visitor>) {
293- visitor.on_finish_vertex (g, u); // descriptor already available, no find_vertex
294- } else if constexpr (has_on_finish_vertex_id<G, Visitor>) {
299+ visitor.on_finish_vertex (g, *find_vertex (g, uid));
300+ }
301+ if constexpr (has_on_finish_vertex_id<G, Visitor>) {
295302 visitor.on_finish_vertex (g, uid);
296303 }
297304 } // while(!queue.empty())
@@ -306,27 +313,30 @@ constexpr void dijkstra_shortest_paths(
306313 *
307314 * @see dijkstra_shortest_paths(G&&, const Sources&, Distances&, Predecessors&, WF&&, Visitor&&, Compare&&, Combine&&)
308315 */
309- template <adjacency_list G,
310- class Distances ,
311- class Predecessors ,
312- class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
313- class Visitor = empty_visitor,
314- class Compare = less<vertex_property_map_value_t <Distances>>,
315- class Combine = plus<vertex_property_map_value_t <Distances>>>
316- requires vertex_property_map_for<Distances, G> && //
317- (is_null_range_v<Predecessors> || vertex_property_map_for<Predecessors, G>) && //
318- is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
316+ template <
317+ adjacency_list G,
318+ class Distances ,
319+ class Predecessors ,
320+ class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
321+ class Visitor = empty_visitor,
322+ class Compare = less<vertex_property_map_value_t <Distances>>,
323+ class Combine = plus<vertex_property_map_value_t <Distances>>>
324+ requires vertex_property_map_for<Distances, G> && //
325+ (is_null_range_v<Predecessors> || vertex_property_map_for<Predecessors, G>) && //
326+ is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
319327 basic_edge_weight_function<G, WF, vertex_property_map_value_t <Distances>, Compare, Combine>
320328constexpr void dijkstra_shortest_paths (
321- G&& g,
322- const vertex_id_t <G>& source,
323- Distances& distances,
324- Predecessors& predecessor,
325- WF&& weight = [](const auto &,
326- const edge_t <G>& uv) { return vertex_property_map_value_t <Distances>(1 ); }, // default weight(g, uv) -> 1
327- Visitor&& visitor = empty_visitor(),
328- Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
329- Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
329+ G&& g,
330+ const vertex_id_t <G>& source,
331+ Distances& distances,
332+ Predecessors& predecessor,
333+ WF&& weight =
334+ [](const auto &, const edge_t <G>& uv) {
335+ return vertex_property_map_value_t <Distances>(1 );
336+ }, // default weight(g, uv) -> 1
337+ Visitor&& visitor = empty_visitor(),
338+ Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
339+ Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
330340 dijkstra_shortest_paths (g, subrange (&source, (&source + 1 )), distances, predecessor, weight,
331341 forward<Visitor>(visitor), forward<Compare>(compare), forward<Combine>(combine));
332342}
@@ -362,26 +372,29 @@ constexpr void dijkstra_shortest_paths(
362372 *
363373 * @see dijkstra_shortest_paths() for full documentation and complexity analysis.
364374 */
365- template <adjacency_list G,
366- input_range Sources,
367- class Distances ,
368- class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
369- class Visitor = empty_visitor,
370- class Compare = less<vertex_property_map_value_t <Distances>>,
371- class Combine = plus<vertex_property_map_value_t <Distances>>>
372- requires vertex_property_map_for<Distances, G> && //
373- convertible_to<range_value_t <Sources>, vertex_id_t <G>> && //
374- is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
375+ template <
376+ adjacency_list G,
377+ input_range Sources,
378+ class Distances ,
379+ class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
380+ class Visitor = empty_visitor,
381+ class Compare = less<vertex_property_map_value_t <Distances>>,
382+ class Combine = plus<vertex_property_map_value_t <Distances>>>
383+ requires vertex_property_map_for<Distances, G> && //
384+ convertible_to<range_value_t <Sources>, vertex_id_t <G>> && //
385+ is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
375386 basic_edge_weight_function<G, WF, vertex_property_map_value_t <Distances>, Compare, Combine>
376387constexpr void dijkstra_shortest_distances (
377388 G&& g,
378389 const Sources& sources,
379390 Distances& distances,
380- WF&& weight = [](const auto &,
381- const edge_t <G>& uv) { return vertex_property_map_value_t <Distances>(1 ); }, // default weight(g, uv) -> 1
382- Visitor&& visitor = empty_visitor(),
383- Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
384- Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
391+ WF&& weight =
392+ [](const auto &, const edge_t <G>& uv) {
393+ return vertex_property_map_value_t <Distances>(1 );
394+ }, // default weight(g, uv) -> 1
395+ Visitor&& visitor = empty_visitor(),
396+ Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
397+ Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
385398 dijkstra_shortest_paths (g, sources, distances, _null_predecessors, forward<WF>(weight), forward<Visitor>(visitor),
386399 forward<Compare>(compare), forward<Combine>(combine));
387400}
@@ -395,24 +408,27 @@ constexpr void dijkstra_shortest_distances(
395408 *
396409 * @see dijkstra_shortest_distances(G&&, const Sources&, Distances&, WF&&, Visitor&&, Compare&&, Combine&&)
397410 */
398- template <adjacency_list G,
399- class Distances ,
400- class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
401- class Visitor = empty_visitor,
402- class Compare = less<vertex_property_map_value_t <Distances>>,
403- class Combine = plus<vertex_property_map_value_t <Distances>>>
404- requires vertex_property_map_for<Distances, G> && //
405- is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
411+ template <
412+ adjacency_list G,
413+ class Distances ,
414+ class WF = function<vertex_property_map_value_t <Distances>(const std::remove_reference_t <G>&, const edge_t <G>&)>,
415+ class Visitor = empty_visitor,
416+ class Compare = less<vertex_property_map_value_t <Distances>>,
417+ class Combine = plus<vertex_property_map_value_t <Distances>>>
418+ requires vertex_property_map_for<Distances, G> && //
419+ is_arithmetic_v<vertex_property_map_value_t <Distances>> && //
406420 basic_edge_weight_function<G, WF, vertex_property_map_value_t <Distances>, Compare, Combine>
407421constexpr void dijkstra_shortest_distances (
408- G&& g,
409- const vertex_id_t <G>& source,
410- Distances& distances,
411- WF&& weight = [](const auto &,
412- const edge_t <G>& uv) { return vertex_property_map_value_t <Distances>(1 ); }, // default weight(g, uv) -> 1
413- Visitor&& visitor = empty_visitor(),
414- Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
415- Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
422+ G&& g,
423+ const vertex_id_t <G>& source,
424+ Distances& distances,
425+ WF&& weight =
426+ [](const auto &, const edge_t <G>& uv) {
427+ return vertex_property_map_value_t <Distances>(1 );
428+ }, // default weight(g, uv) -> 1
429+ Visitor&& visitor = empty_visitor(),
430+ Compare&& compare = less<vertex_property_map_value_t <Distances>>(),
431+ Combine&& combine = plus<vertex_property_map_value_t <Distances>>()) {
416432 dijkstra_shortest_paths (g, subrange (&source, (&source + 1 )), distances, _null_predecessors, forward<WF>(weight),
417433 forward<Visitor>(visitor), forward<Compare>(compare), forward<Combine>(combine));
418434}
0 commit comments