LCOV - code coverage report
Current view: top level - src/foreign/RoutingKit/include/routingkit - contraction_hierarchy.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 0.0 % 144 0
Test Date: 2026-09-23 15:43:02 Functions: 0.0 % 80 0

            Line data    Source code
       1              : #ifndef ROUTING_KIT_CONTRACTION_HIERARCHY_H
       2              : #define ROUTING_KIT_CONTRACTION_HIERARCHY_H
       3              : 
       4              : #include <routingkit/id_queue.h>
       5              : #include <routingkit/timestamp_flag.h>
       6              : #include <routingkit/bit_vector.h>
       7              : #include <routingkit/permutation.h>
       8              : 
       9              : #include <vector>
      10              : #include <string>
      11              : #include <functional>
      12              : #include <cassert>
      13              : #include <type_traits>
      14              : #include <limits.h>
      15              : 
      16              : namespace RoutingKit{
      17              : 
      18              : class ContractionHierarchy{
      19              : public:
      20              :         static const unsigned default_max_pop_count = 500;
      21              : 
      22              :         static ContractionHierarchy build(
      23              :                 unsigned node_count, std::vector<unsigned>tail, std::vector<unsigned>head, std::vector<unsigned>weight,
      24              :                 const std::function<void(std::string)>&log_message = std::function<void(std::string)>(), unsigned max_pop_count = default_max_pop_count
      25              :         );
      26              : 
      27              :         static ContractionHierarchy build_given_rank(
      28              :                 std::vector<unsigned>rank,
      29              :                 std::vector<unsigned>tail, std::vector<unsigned>head, std::vector<unsigned>weight,
      30              :                 const std::function<void(std::string)>&log_message = std::function<void(std::string)>(), unsigned max_pop_count = default_max_pop_count
      31              :         );
      32              : 
      33              :         static ContractionHierarchy build_given_order(
      34              :                 std::vector<unsigned>order,
      35              :                 std::vector<unsigned>tail, std::vector<unsigned>head, std::vector<unsigned>weight,
      36              :                 const std::function<void(std::string)>&log_message = std::function<void(std::string)>(), unsigned max_pop_count = default_max_pop_count
      37              :         );
      38              : 
      39              :         static ContractionHierarchy read(std::function<void(char*, unsigned long long)>data_source);
      40              :         static ContractionHierarchy read(std::function<void(char*, unsigned long long)>data_source, unsigned long long file_size);
      41              :         static ContractionHierarchy read(std::istream&in);
      42              :         static ContractionHierarchy read(std::istream&in, unsigned long long file_size);
      43              :         static ContractionHierarchy load_file(const std::string&file_name);
      44              : 
      45              :         void write(std::function<void(const char*, unsigned long long)>data_sink) const;
      46              :         void write(std::ostream&out) const;
      47              :         void save_file(const std::string&file_name) const;
      48              : 
      49              :         unsigned node_count()const{
      50            0 :                 return rank.size();
      51              :         }
      52              : 
      53              :         struct Side{
      54              :                 std::vector<unsigned>first_out;
      55              :                 std::vector<unsigned>head;
      56              :                 std::vector<unsigned>weight;
      57              : 
      58              :                 BitVector is_shortcut_an_original_arc;
      59              :                 std::vector<unsigned>shortcut_first_arc; // contains input arc ID if not shortcut
      60              :                 std::vector<unsigned>shortcut_second_arc;// contains input tail node ID if not shortcut
      61              :         };
      62              : 
      63              :         std::vector<unsigned>rank, order;
      64              :         Side forward, backward;
      65              : };
      66              : 
      67              : void check_contraction_hierarchy_for_errors(const ContractionHierarchy&ch);
      68              : 
      69              : template<class Weight>
      70              : struct ContractionHierarchyExtraWeight{
      71              : 
      72            0 :         ContractionHierarchyExtraWeight(){}
      73              : 
      74              :         template<class InputWeightContainer, class LinkFunction>
      75              :         ContractionHierarchyExtraWeight(const ContractionHierarchy&ch, const InputWeightContainer&extra_weight, const LinkFunction&link){ reset(ch, extra_weight, link); }
      76              : 
      77              :         template<class InputWeightContainer, class LinkFunction>
      78              :         ContractionHierarchyExtraWeight& reset(const ContractionHierarchy&ch, const InputWeightContainer&extra_weight, const LinkFunction&link);
      79              : 
      80              :         std::vector<Weight>forward_weight, backward_weight;
      81              : };
      82              : 
      83              : namespace detail{
      84              :         template<class T>
      85              :         using ReturnTypeWhenPassedIntOf = typename std::remove_const<typename std::remove_reference<decltype(std::declval<T>()(1))>::type>::type;
      86              : 
      87              :         template<class T>
      88              :         using ValueTypeOfContainer = typename std::remove_const<typename std::remove_reference<decltype(std::declval<T>()[1])>::type>::type;
      89              : 
      90              :         template<class T>
      91              :         struct GetExtraWeightTypeHelper{
      92              :                 typedef ValueTypeOfContainer<T> type;
      93              :         };
      94              : 
      95              :         template<class T>
      96              :         struct GetExtraWeightTypeHelper<ContractionHierarchyExtraWeight<T>>{
      97              :                 typedef T type;
      98              :         };
      99              : 
     100              :         template<class T>
     101              :         using GetExtraWeightType = typename GetExtraWeightTypeHelper<T>::type;
     102              : }
     103              : 
     104              : class ContractionHierarchyQuery{
     105              : public:
     106              :         ContractionHierarchyQuery():ch(0){}
     107              :         explicit ContractionHierarchyQuery(const ContractionHierarchy&ch);
     108              : 
     109              :         ContractionHierarchyQuery&reset();
     110              :         ContractionHierarchyQuery&reset(const ContractionHierarchy&ch);
     111              : 
     112              :         ContractionHierarchyQuery&add_source(unsigned s, unsigned dist_to_s = 0);
     113              :         ContractionHierarchyQuery&add_target(unsigned t, unsigned dist_to_t = 0);
     114              : 
     115              :         ContractionHierarchyQuery&run();
     116              : 
     117              :         unsigned get_used_source();
     118              :         unsigned get_used_target();
     119              : 
     120              :         unsigned get_distance();
     121              :         std::vector<unsigned>get_node_path();
     122              :         std::vector<unsigned>get_arc_path();
     123              : 
     124              :         template<class ExtraWeight, class LinkFunction>
     125              :         detail::GetExtraWeightType<ExtraWeight> get_extra_weight_distance(const ExtraWeight&extra_weight, const LinkFunction&link);
     126              : 
     127              :         ContractionHierarchyQuery& reset_source();
     128              :         ContractionHierarchyQuery& pin_targets(const std::vector<unsigned>&);
     129              :         unsigned get_pinned_target_count();
     130              :         ContractionHierarchyQuery& run_to_pinned_targets();
     131              : 
     132              :         ContractionHierarchyQuery& get_distances_to_targets(unsigned*dist);
     133              :         std::vector<unsigned> get_distances_to_targets();
     134              : 
     135              :         ContractionHierarchyQuery& reset_target();
     136              :         ContractionHierarchyQuery& pin_sources(const std::vector<unsigned>&);
     137              :         unsigned get_pinned_source_count();
     138              :         ContractionHierarchyQuery& run_to_pinned_sources();
     139              : 
     140              :         ContractionHierarchyQuery& get_distances_to_sources(unsigned*dist);
     141              :         std::vector<unsigned> get_distances_to_sources();
     142              : 
     143              :         // TODO: Mirror these functions in CCH
     144              : 
     145              :         ContractionHierarchyQuery& get_used_sources_to_targets(unsigned*dist);
     146              :         std::vector<unsigned> get_used_sources_to_targets();
     147              : 
     148              :         ContractionHierarchyQuery& get_used_targets_to_sources(unsigned*dist);
     149              :         std::vector<unsigned> get_used_targets_to_sources();
     150              : 
     151              :         // The get_extra_weight_distances function follow a pattern.
     152              :         // The usage pattern is
     153              :         //
     154              :         //    get_extra_weight_distances_to_[target|source](extra_weight, link, [, tmp, [dist]])
     155              :         //
     156              :         // There get_extra_weight_distances_to_target is used if targets were pinned, whereas
     157              :         // get_extra_weight_distances_to_source is for pinned sources.
     158              :         //
     159              :         // There are four additional parameters. Their meaning are:
     160              :         //
     161              :         // * extra_weight: The extra weight according to which the path length should be computed.
     162              :         //   This can be a ContractionHierarchyExtraWeight<T> or a container<T>. The former is faster.
     163              :         //   container<T> is a placeholder for anything that has an operator[] that provides read-only
     164              :         //   access to the arc weight. For every arc a, the expression extra_weight[a] should
     165              :         //   give the extra weight. Using ContractionHierarchyExtraWeight<T> is faster.
     166              :         //   Typical types for container<T> are const vector<T> and const T*.
     167              :         //
     168              :         // * The extra weight does not have to be a scalar value. It can be an arbitrary structure.
     169              :         //   However, the algorithm needs to know how to concatenate the weights of two arcs.
     170              :         //   The link parameter is a functor that tells it how to do it.
     171              :         //   For travel time, the link parameter is the addition. If some of your
     172              :         //   values are inf_weight, normal addition can run into overflow problems. RoutingKit therefore
     173              :         //   provides the SaturatedWeightAddition functor that correctly handles overflows for unsigned and int weights.
     174              :         //
     175              :         //   The link function will never be provided a default constructed object, i.e.,
     176              :         //   it does not exploit that link(T(),foo) == foo.
     177              :         //
     178              :         // * tmp is a container<T>. Its size must be at least node_count. The content of
     179              :         //   the first node_count elements in undefined after this function is completed.
     180              :         //   If the parameter is omitted, a temporary buffer is allocated. If the function
     181              :         //   is called multiple times, it can be faster to only allocate one buffer.
     182              :         //
     183              :         // * dist is a container<T>. Its size is the number of pinned sources or targets.
     184              :         //   the output is written to it. If it is omited, a vector<T> is allocated and
     185              :         //   returned by the function.
     186              :         //
     187              :         //   If the source and the target nodes are equal, the extra weight length is
     188              :         //   default constructed T. If there is no path, the extra weight length is also
     189              :         //   default constructed T. For integers default constructed means 0.
     190              :         //
     191              :         // If both tmp and dist are present, the function is guarenteed to not allocate or free any memory.
     192              :         // If tmp and dist are present, and link is guarenteed to not throw, the function is guarenteed to not throw.
     193              : 
     194              :         template<class ExtraWeight, class LinkFunction>                                          std::vector<detail::GetExtraWeightType<ExtraWeight>> get_extra_weight_distances_to_targets(const ExtraWeight&extra_weight, const LinkFunction&link);
     195              :         template<class ExtraWeight, class LinkFunction, class TmpContainer>                      std::vector<detail::GetExtraWeightType<ExtraWeight>> get_extra_weight_distances_to_targets(const ExtraWeight&extra_weight, const LinkFunction&link, TmpContainer&tmp);
     196              :         template<class ExtraWeight, class LinkFunction, class TmpContainer, class DistContainer> ContractionHierarchyQuery&                           get_extra_weight_distances_to_targets(const ExtraWeight&extra_weight, const LinkFunction&link, TmpContainer&tmp, DistContainer&dist);
     197              :         template<class ExtraWeight, class LinkFunction>                                          std::vector<detail::GetExtraWeightType<ExtraWeight>> get_extra_weight_distances_to_sources(const ExtraWeight&extra_weight, const LinkFunction&link);
     198              :         template<class ExtraWeight, class LinkFunction, class TmpContainer>                      std::vector<detail::GetExtraWeightType<ExtraWeight>> get_extra_weight_distances_to_sources(const ExtraWeight&extra_weight, const LinkFunction&link, TmpContainer&tmp);
     199              :         template<class ExtraWeight, class LinkFunction, class TmpContainer, class DistContainer> ContractionHierarchyQuery&                           get_extra_weight_distances_to_sources(const ExtraWeight&extra_weight, const LinkFunction&link, TmpContainer&tmp, DistContainer&dist);
     200              : 
     201              : //private:
     202              :         const ContractionHierarchy*ch;
     203              : 
     204              :         TimestampFlags was_forward_pushed, was_backward_pushed;
     205              :         MinIDQueue forward_queue, backward_queue;
     206              :         std::vector<unsigned>forward_tentative_distance, backward_tentative_distance;
     207              :         std::vector<unsigned>forward_predecessor_node, backward_predecessor_node;
     208              :         std::vector<unsigned>forward_predecessor_arc, backward_predecessor_arc;
     209              :         unsigned shortest_path_meeting_node;
     210              :         unsigned many_to_many_source_or_target_count;
     211              : 
     212              :         enum class InternalState:unsigned{
     213              :                 initialized,
     214              :                 run,
     215              :                 source_pinned,
     216              :                 source_run,
     217              :                 target_pinned,
     218              :                 target_run
     219              :         }state;
     220              : };
     221              : 
     222              : struct SaturatedWeightAddition{
     223              :         unsigned operator()(unsigned l, unsigned r)const;
     224              :         int operator()(int l, int r)const;
     225              : };
     226              : 
     227              : // ------ Template & inline implementations; no more interface descriptions beyond this line -------
     228              : 
     229              : inline
     230              : unsigned ContractionHierarchyQuery::get_pinned_target_count(){
     231              :         assert(state == ContractionHierarchyQuery::InternalState::target_run || state == ContractionHierarchyQuery::InternalState::target_pinned);
     232              :         return many_to_many_source_or_target_count;
     233              : }
     234              : 
     235              : inline
     236              : unsigned ContractionHierarchyQuery::get_pinned_source_count(){
     237              :         assert(state == ContractionHierarchyQuery::InternalState::source_run || state == ContractionHierarchyQuery::InternalState::source_pinned);
     238              :         return many_to_many_source_or_target_count;
     239              : }
     240              : 
     241              : template<class ExtraWeight, class LinkFunction>
     242              : std::vector<detail::GetExtraWeightType<ExtraWeight>> ContractionHierarchyQuery::get_extra_weight_distances_to_targets(
     243              :         const ExtraWeight&extra_weight,
     244              :         const LinkFunction&link
     245              : ){
     246              :         std::vector<detail::GetExtraWeightType<ExtraWeight>>tmp(ch->node_count()), dist(get_pinned_target_count());
     247              :         get_extra_weight_distances_to_targets(extra_weight, link, tmp, dist);
     248              :         return dist; // NVRO
     249              : }
     250              : 
     251              : template<class ExtraWeight, class LinkFunction, class TmpContainer>
     252              : std::vector<detail::GetExtraWeightType<ExtraWeight>> ContractionHierarchyQuery::get_extra_weight_distances_to_targets(
     253              :         const ExtraWeight&extra_weight,
     254              :         const LinkFunction&link,
     255              :         TmpContainer&tmp
     256              : ){
     257              :         std::vector<detail::GetExtraWeightType<ExtraWeight>>dist(get_pinned_target_count());
     258              :         get_extra_weight_distances_to_targets(extra_weight, link, tmp, dist);
     259              :         return dist; // NVRO
     260              : }
     261              : 
     262              : 
     263              : template<class ExtraWeight, class LinkFunction>
     264              : std::vector<detail::GetExtraWeightType<ExtraWeight>> ContractionHierarchyQuery::get_extra_weight_distances_to_sources(
     265              :         const ExtraWeight&extra_weight,
     266              :         const LinkFunction&link
     267              : ){
     268              :         std::vector<detail::GetExtraWeightType<ExtraWeight>>tmp(ch->node_count()), dist(get_pinned_source_count());
     269              :         get_extra_weight_distances_to_sources(extra_weight, link, tmp, dist);
     270              :         return dist; // NVRO
     271              : }
     272              : 
     273              : template<class ExtraWeight, class LinkFunction, class TmpContainer>
     274              : std::vector<detail::GetExtraWeightType<ExtraWeight>> ContractionHierarchyQuery::get_extra_weight_distances_to_sources(
     275              :         const ExtraWeight&extra_weight,
     276              :         const LinkFunction&link,
     277              :         TmpContainer&tmp
     278              : ){
     279              :         std::vector<detail::GetExtraWeightType<ExtraWeight>>dist(get_pinned_source_count());
     280              :         get_extra_weight_distances_to_sources(extra_weight, link, tmp, dist);
     281              :         return dist; // NVRO
     282              : }
     283              : 
     284              : inline
     285              : unsigned SaturatedWeightAddition::operator()(unsigned l, unsigned r)const{
     286              :         assert(l <= inf_weight && "unsigned weight must not be larger than inf_weight");
     287              :         assert(r <= inf_weight && "unsigned weight must not be larger than inf_weight");
     288            0 :         if(l >= inf_weight-r)
     289              :                 return inf_weight;
     290              :         else
     291            0 :                 return l+r;
     292              : }
     293              : 
     294              : inline
     295              : int SaturatedWeightAddition::operator()(int l, int r)const{
     296              :         static_assert(inf_weight == INT_MAX, "this function assumes that inf_weight is INT_MAX");
     297            0 :         if(l > 0){
     298            0 :                 if (r > INT_MAX - l){
     299              :                         return INT_MAX;
     300              :                 }
     301            0 :         }else if(r < INT_MIN - l){
     302              :                 return INT_MIN;
     303              :         }
     304              : 
     305            0 :     return l + r;
     306              : }
     307              : 
     308              : namespace detail{
     309              :         template<class LinkFunction>
     310              :         struct InverseLinkFunction{
     311              :                 explicit InverseLinkFunction(const LinkFunction&link):link(link){}
     312              : 
     313              :                 template<class L, class R>
     314              :                 auto operator()(L&&l, R&&r)const
     315              :                         -> decltype(std::declval<LinkFunction>()(std::forward<R>(r), std::forward<L>(l)))
     316              :                 {
     317            0 :                         return link(std::forward<R>(r), std::forward<L>(l));
     318              :                 }
     319              : 
     320              :                 const LinkFunction&link;
     321              :         };
     322              : 
     323              :         template<class LinkFunction>
     324              :         InverseLinkFunction<LinkFunction>inverse_link_function(const LinkFunction&link){
     325              :                 return InverseLinkFunction<LinkFunction>(link);
     326              :         }
     327              : 
     328              :         template<class InputWeightContainer, class LinkFunction>
     329              :         struct ShortcutWeights{
     330              :                 typedef typename std::remove_reference<decltype(std::declval<InputWeightContainer>()[0])>::type Weight;
     331              : 
     332              :                 const InputWeightContainer&input_weight;
     333              :                 const LinkFunction&link;
     334              : 
     335              :                 const ContractionHierarchy&ch;
     336              : 
     337            0 :                 ShortcutWeights(const InputWeightContainer&input_weight, const LinkFunction&link, const ContractionHierarchy&ch):
     338            0 :                         input_weight(input_weight), link(link), ch(ch){}
     339              : 
     340            0 :                 Weight get_forward_weight(unsigned a)const{
     341              :                         assert(a < ch.forward.is_shortcut_an_original_arc.size());
     342            0 :                         if(ch.forward.is_shortcut_an_original_arc.is_set(a)){
     343            0 :                                 return input_weight[ch.forward.shortcut_first_arc[a]];
     344              :                         }else{
     345            0 :                                 return link(get_backward_weight(ch.forward.shortcut_first_arc[a]), get_forward_weight(ch.forward.shortcut_second_arc[a]));
     346              :                         }
     347              :                 }
     348              : 
     349            0 :                 Weight get_backward_weight(unsigned a)const{
     350              :                         assert(a < ch.backward.is_shortcut_an_original_arc.size());
     351            0 :                         if(ch.backward.is_shortcut_an_original_arc.is_set(a)){
     352            0 :                                 return input_weight[ch.backward.shortcut_first_arc[a]];
     353              :                         }else{
     354            0 :                                 return link(get_backward_weight(ch.backward.shortcut_first_arc[a]), get_forward_weight(ch.backward.shortcut_second_arc[a]));
     355              :                         }
     356              :                 }
     357              :         };
     358              : 
     359              :         template<class WeightT, class LinkFunction>
     360              :         struct ShortcutWeights<ContractionHierarchyExtraWeight<WeightT>, LinkFunction>{
     361              : 
     362              :                 typedef WeightT Weight;
     363              : 
     364              :                 const ContractionHierarchyExtraWeight<WeightT>&extra_weight;
     365              : 
     366              :                 explicit ShortcutWeights(const ContractionHierarchyExtraWeight<WeightT>&extra_weight, const LinkFunction&, const ContractionHierarchy&):
     367              :                         extra_weight(extra_weight){}
     368              : 
     369              :                 const Weight&get_forward_weight(unsigned a)const{
     370            0 :                         return extra_weight.forward_weight[a];
     371              :                 }
     372              : 
     373              :                 const Weight&get_backward_weight(unsigned a)const{
     374            0 :                         return extra_weight.backward_weight[a];
     375              :                 }
     376              :         };
     377              : 
     378              :         template<class ExtraWeight, class LinkFunction>
     379              :         ShortcutWeights<ExtraWeight, LinkFunction> make_shortcut_weights(const ExtraWeight&extra_weight, const LinkFunction&link, const ContractionHierarchy&ch){
     380              :                 return ShortcutWeights<ExtraWeight, LinkFunction>{extra_weight, link, ch};
     381              :         }
     382              : 
     383              :         template<class ShortcutWeights>
     384              :         struct InvertShorcutWeights{
     385              :                 typedef typename ShortcutWeights::Weight Weight;
     386              : 
     387              :                 const ShortcutWeights&shortcut_weights;
     388              : 
     389              :                 explicit InvertShorcutWeights(const ShortcutWeights&shortcut_weights):shortcut_weights(shortcut_weights){}
     390              : 
     391              :                 auto get_forward_weight(unsigned a)const->decltype(std::declval<ShortcutWeights>().get_backward_weight(a)){
     392            0 :                         return shortcut_weights.get_backward_weight(a);
     393              :                 }
     394              : 
     395              :                 auto get_backward_weight(unsigned a)const->decltype(std::declval<ShortcutWeights>().get_forward_weight(a)){
     396            0 :                         return shortcut_weights.get_forward_weight(a);
     397              :                 }
     398              :         };
     399              : 
     400              :         template<class ShortcutWeights>
     401              :         InvertShorcutWeights<ShortcutWeights>inverse_shortcut_weights(const ShortcutWeights&shortcut_weights){
     402              :                 return InvertShorcutWeights<ShortcutWeights>(shortcut_weights);
     403              :         }
     404              : 
     405              :         template<class GetForwardWeight, class LinkFunction>
     406            0 :         ReturnTypeWhenPassedIntOf<GetForwardWeight> get_extra_weight_up_distance(
     407              :                 unsigned shortest_path_meeting_node,
     408              :                 const std::vector<unsigned>&forward_predecessor_node,
     409              :                 const std::vector<unsigned>&forward_predecessor_arc,
     410              :                 const GetForwardWeight&get_forward_extra_weight,
     411              :                 const LinkFunction&link
     412              :         ){
     413              :                 using Weight = ReturnTypeWhenPassedIntOf<GetForwardWeight>;
     414              : 
     415              :                 unsigned x = shortest_path_meeting_node;
     416              :                 assert(forward_predecessor_node[x] != invalid_id);
     417            0 :                 Weight ret = get_forward_extra_weight(forward_predecessor_arc[x]);
     418            0 :                 x = forward_predecessor_node[x];
     419              : 
     420            0 :                 while(forward_predecessor_node[x] != invalid_id){
     421            0 :                         ret = link(get_forward_extra_weight(forward_predecessor_arc[x]), ret);
     422            0 :                         x = forward_predecessor_node[x];
     423              :                 }
     424            0 :                 return ret;
     425              :         }
     426              : 
     427              : 
     428              :         template<class ShortcutWeights, class LinkFunction>
     429            0 :         typename ShortcutWeights::Weight internal_get_extra_weight_distance(
     430              :                 const ShortcutWeights&shortcut_weights,
     431              :                 const LinkFunction&link,
     432              :                 unsigned shortest_path_meeting_node,
     433              :                 const std::vector<unsigned>&forward_predecessor_node,
     434              :                 const std::vector<unsigned>&forward_predecessor_arc,
     435              :                 const std::vector<unsigned>&backward_predecessor_node,
     436              :                 const std::vector<unsigned>&backward_predecessor_arc
     437              :         ){
     438              :                 using Weight = typename ShortcutWeights::Weight;
     439              : 
     440            0 :                 if(shortest_path_meeting_node == invalid_id)
     441              :                         return Weight{};
     442              : 
     443              : 
     444            0 :                 auto inverted_link = detail::inverse_link_function(link);
     445              : 
     446            0 :                 bool has_up_part = forward_predecessor_node[shortest_path_meeting_node] != invalid_id;
     447            0 :                 bool has_down_part = backward_predecessor_node[shortest_path_meeting_node] != invalid_id;
     448              : 
     449              :                 // This if-then-else chain avoids the need for a neutral element with respect to link
     450              : 
     451            0 :                 if(!has_up_part && !has_down_part) {
     452              :                         return Weight{};
     453            0 :                 } else if(has_up_part && has_down_part) {
     454            0 :                         return link(
     455              :                                 detail::get_extra_weight_up_distance(
     456              :                                         shortest_path_meeting_node,
     457              :                                         forward_predecessor_node,
     458              :                                         forward_predecessor_arc,
     459            0 :                                         [&](unsigned a)->decltype(shortcut_weights.get_forward_weight(a)){return shortcut_weights.get_forward_weight(a);},
     460              :                                         link
     461              :                                 ),
     462              :                                 detail::get_extra_weight_up_distance(
     463              :                                         shortest_path_meeting_node,
     464              :                                         backward_predecessor_node,
     465              :                                         backward_predecessor_arc,
     466            0 :                                         [&](unsigned a)->decltype(shortcut_weights.get_backward_weight(a)){return shortcut_weights.get_backward_weight(a);},
     467              :                                         inverted_link
     468              :                                 )
     469              :                         );
     470            0 :                 } else if(has_up_part) {
     471            0 :                         return detail::get_extra_weight_up_distance(
     472              :                                 shortest_path_meeting_node,
     473              :                                 forward_predecessor_node,
     474              :                                 forward_predecessor_arc,
     475            0 :                                 [&](unsigned a)->decltype(shortcut_weights.get_forward_weight(a)){return shortcut_weights.get_forward_weight(a);},
     476              :                                 link
     477              :                         );
     478              :                 } else {
     479            0 :                         return detail::get_extra_weight_up_distance(
     480              :                                 shortest_path_meeting_node,
     481              :                                 backward_predecessor_node,
     482              :                                 backward_predecessor_arc,
     483            0 :                                 [&](unsigned a)->decltype(shortcut_weights.get_backward_weight(a)){return shortcut_weights.get_backward_weight(a);},
     484              :                                 inverted_link
     485              :                         );
     486              :                 }
     487              :         }
     488              : 
     489              : }
     490              : 
     491              : template<class ExtraWeight, class LinkFunction>
     492            0 : detail::GetExtraWeightType<ExtraWeight> ContractionHierarchyQuery::get_extra_weight_distance(
     493              :         const ExtraWeight&extra_weight,
     494              :         const LinkFunction&link){
     495              :         assert(ch && "query object must have an attached CH");
     496              :         assert(state == ContractionHierarchyQuery::InternalState::run);
     497              : 
     498            0 :         auto shortcut_weight = detail::make_shortcut_weights(extra_weight, link, *ch);
     499              : 
     500            0 :         return detail::internal_get_extra_weight_distance(
     501              :                 shortcut_weight, link,
     502              :                 shortest_path_meeting_node,
     503            0 :                 forward_predecessor_node, forward_predecessor_arc,
     504            0 :                 backward_predecessor_node, backward_predecessor_arc
     505            0 :         );
     506              : }
     507              : 
     508              : template<class Weight> template<class InputWeightContainer, class LinkFunction>
     509            0 : ContractionHierarchyExtraWeight<Weight>& ContractionHierarchyExtraWeight<Weight>::reset(const ContractionHierarchy&ch, const InputWeightContainer&input_extra_weight, const LinkFunction&link){
     510              :         const unsigned node_count = ch.node_count();
     511              : 
     512            0 :         forward_weight.resize(ch.forward.weight.size());
     513            0 :         backward_weight.resize(ch.backward.weight.size());
     514              : 
     515            0 :         for(unsigned x=0; x<node_count; ++x){
     516            0 :                 for(unsigned xy=ch.forward.first_out[x]; xy<ch.forward.first_out[x+1]; ++xy){
     517            0 :                         if(ch.forward.is_shortcut_an_original_arc.is_set(xy)){
     518            0 :                                 forward_weight[xy] = input_extra_weight[ch.forward.shortcut_first_arc[xy]];
     519              :                         } else {
     520            0 :                                 forward_weight[xy] = link(
     521            0 :                                         backward_weight[ch.forward.shortcut_first_arc[xy]],
     522            0 :                                         forward_weight[ch.forward.shortcut_second_arc[xy]]
     523              :                                 );
     524              :                         }
     525              :                 }
     526            0 :                 for(unsigned xy=ch.backward.first_out[x]; xy<ch.backward.first_out[x+1]; ++xy){
     527            0 :                         if(ch.backward.is_shortcut_an_original_arc.is_set(xy)){
     528            0 :                                 backward_weight[xy] = input_extra_weight[ch.backward.shortcut_first_arc[xy]];
     529              :                         } else {
     530            0 :                                 backward_weight[xy] = link(
     531            0 :                                         backward_weight[ch.backward.shortcut_first_arc[xy]],
     532            0 :                                         forward_weight[ch.backward.shortcut_second_arc[xy]]
     533              :                                 );
     534              :                         }
     535              :                 }
     536              :         }
     537            0 :         return *this;
     538              : }
     539              : 
     540              : 
     541              : namespace detail{
     542              :         template<class LinkFunction, class ExtraWeight, class TmpContainer, class DistContainer>
     543            0 :         void extract_distances_to_targets(
     544              :                 const std::vector<unsigned>&target_list,
     545              :                 unsigned target_count,
     546              : 
     547              :                 const TimestampFlags&has_forward_predecessor,
     548              :                 const std::vector<unsigned>&forward_predecessor_node,
     549              :                 const std::vector<unsigned>&predecessor_arc,
     550              : 
     551              :                 const ExtraWeight&extra_weight,
     552              :                 const std::vector<unsigned>&forward_first_out,
     553              :                 const std::vector<unsigned>&forward_head,
     554              :                 const std::vector<unsigned>&backward_first_out,
     555              :                 const std::vector<unsigned>&backward_head,
     556              : 
     557              :                 TmpContainer&source_to_node_distance,
     558              :                 TimestampFlags&has_source_to_node_distance,
     559              : 
     560              :                 DistContainer&output,
     561              : 
     562              :                 std::vector<unsigned>&stack,
     563              : 
     564              :                 const LinkFunction&link
     565              :         ){
     566              :                 using Weight = typename ExtraWeight::Weight;
     567              : 
     568              :                 has_source_to_node_distance.reset_all();
     569              : 
     570            0 :                 unsigned nodes_on_stack_with_forward_precessor_count = 0;
     571            0 :                 unsigned stack_size = 0;
     572              : 
     573            0 :                 auto push = [&](unsigned x){
     574              :                         assert(stack_size < stack.size());
     575            0 :                         stack[stack_size++] = x;
     576              :                 };
     577              : 
     578            0 :                 auto pop = [&]{
     579              :                         assert(stack_size != 0);
     580            0 :                         return stack[--stack_size];
     581              :                 };
     582              : 
     583            0 :                 auto single_forward_step_expand_distance_to_node = [&](unsigned x){
     584              :                         assert(!has_source_to_node_distance.is_set(x));
     585              :                         assert(has_forward_predecessor.is_set(x));
     586              :                         assert(forward_predecessor_node[x] != invalid_id);
     587              : 
     588            0 :                         unsigned a = predecessor_arc[x];
     589            0 :                         unsigned p = forward_predecessor_node[x];
     590              : 
     591            0 :                         if(has_source_to_node_distance.is_set(p))
     592            0 :                                 source_to_node_distance[x] = link(source_to_node_distance[p], extra_weight.get_forward_weight(a));
     593              :                         else
     594            0 :                                 source_to_node_distance[x] = extra_weight.get_forward_weight(a); // p is source
     595            0 :                         has_source_to_node_distance.set(x);
     596              :                 };
     597              : 
     598            0 :                 auto single_backward_step_expand_distance_to_node = [&](unsigned x){
     599              :                         assert(!has_source_to_node_distance.is_set(x));
     600              :                         assert(!has_forward_predecessor.is_set(x));
     601              : 
     602            0 :                         unsigned a = predecessor_arc[x];
     603            0 :                         unsigned p = backward_head[a];
     604              : 
     605            0 :                         if(has_source_to_node_distance.is_set(p))
     606            0 :                                 source_to_node_distance[x] = link(source_to_node_distance[p], extra_weight.get_backward_weight(a));
     607              :                         else
     608            0 :                                 source_to_node_distance[x] = extra_weight.get_backward_weight(a); // p is source
     609              : 
     610            0 :                         has_source_to_node_distance.set(x);
     611              :                 };
     612              : 
     613            0 :                 auto push_non_reached_nodes = [&](unsigned x){
     614              :                         assert(!has_source_to_node_distance.is_set(x));
     615            0 :                         while(!has_forward_predecessor.is_set(x)){
     616            0 :                                 push(x);
     617            0 :                                 unsigned y = backward_head[predecessor_arc[x]];
     618              :                                 assert(y > x);
     619              :                                 x = y;
     620            0 :                                 if(has_source_to_node_distance.is_set(x))
     621              :                                         return;
     622              :                         }
     623            0 :                         while(forward_predecessor_node[x] != invalid_id){
     624              :                                 assert(has_forward_predecessor.is_set(x));
     625            0 :                                 push(x);
     626            0 :                                 ++nodes_on_stack_with_forward_precessor_count;
     627            0 :                                 unsigned y = forward_predecessor_node[x];
     628              :                                 assert(y < x);
     629              :                                 x = y;
     630            0 :                                 if(has_source_to_node_distance.is_set(x))
     631              :                                         return;
     632              :                         }
     633            0 :                         source_to_node_distance[x] = Weight{}; // x is source node
     634              :                 };
     635              : 
     636            0 :                 auto expand_distances_from_source_to_node = [&](unsigned x){
     637            0 :                         if(!has_source_to_node_distance.is_set(x)){
     638            0 :                                 push_non_reached_nodes(x);
     639            0 :                                 while(stack_size != 0){
     640            0 :                                         unsigned y = pop();
     641            0 :                                         if(nodes_on_stack_with_forward_precessor_count != 0){
     642            0 :                                                 --nodes_on_stack_with_forward_precessor_count;
     643            0 :                                                 single_forward_step_expand_distance_to_node(y);
     644              :                                         }else{
     645            0 :                                                 single_backward_step_expand_distance_to_node(y);
     646              :                                         }
     647              :                                 }
     648              :                         }
     649              :                 };
     650              : 
     651            0 :                 for(unsigned i=0; i<target_count; ++i){
     652            0 :                         unsigned t = target_list[i];
     653              :                         assert(t != invalid_id);
     654              : 
     655            0 :                         if(!has_forward_predecessor.is_set(t) && predecessor_arc[t] == invalid_id){
     656            0 :                                 output[i] = Weight{}; // t is not reachable
     657              :                         }else{
     658            0 :                                 expand_distances_from_source_to_node(t);
     659            0 :                                 output[i] = source_to_node_distance[t];
     660              :                         }
     661              :                 }
     662            0 :         }
     663              : }
     664              : 
     665              : template<class ExtraWeight, class LinkFunction, class TmpContainer, class DistContainer>
     666            0 : ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets(
     667              :         const ExtraWeight&extra_weight,
     668              :         const LinkFunction&link,
     669              :         TmpContainer&tmp,
     670              :         DistContainer&dist
     671              : ){
     672              :         assert(state == ContractionHierarchyQuery::InternalState::target_run);
     673              : 
     674            0 :         auto shortcut_weight = detail::make_shortcut_weights(extra_weight, link, *ch);
     675              : 
     676            0 :         detail::extract_distances_to_targets(
     677            0 :                 backward_predecessor_node, many_to_many_source_or_target_count,
     678              : 
     679            0 :                 was_forward_pushed,
     680            0 :                 forward_predecessor_node, forward_predecessor_arc,
     681              : 
     682              :                 shortcut_weight,
     683            0 :                 ch->forward.first_out,
     684            0 :                 ch->forward.head,
     685            0 :                 ch->backward.first_out,
     686            0 :                 ch->backward.head,
     687              : 
     688              :                 tmp,
     689            0 :                 was_backward_pushed,
     690              : 
     691              :                 dist,
     692              : 
     693            0 :                 backward_predecessor_arc,
     694              : 
     695              :                 link
     696              :         );
     697              : 
     698            0 :         return *this;
     699              : }
     700              : 
     701              : template<class ExtraWeight, class LinkFunction, class TmpContainer, class DistContainer>
     702            0 : ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources(
     703              :         const ExtraWeight&extra_weight,
     704              :         const LinkFunction&link,
     705              :         TmpContainer&tmp,
     706              :         DistContainer&dist
     707              : ){
     708              :         assert(state == ContractionHierarchyQuery::InternalState::source_run);
     709              : 
     710            0 :         auto inverted_link = detail::inverse_link_function(link);
     711              : 
     712            0 :         auto shortcut_weight = detail::make_shortcut_weights(extra_weight, link, *ch);
     713            0 :         auto inverted_shortcut_weight = detail::inverse_shortcut_weights(shortcut_weight);
     714              : 
     715            0 :         detail::extract_distances_to_targets(
     716            0 :                 forward_predecessor_node, many_to_many_source_or_target_count,
     717              : 
     718            0 :                 was_backward_pushed,
     719            0 :                 backward_predecessor_node, backward_predecessor_arc,
     720              : 
     721              :                 inverted_shortcut_weight,
     722            0 :                 ch->backward.first_out,
     723            0 :                 ch->backward.head,
     724            0 :                 ch->forward.first_out,
     725            0 :                 ch->forward.head,
     726              : 
     727              :                 tmp,
     728            0 :                 was_forward_pushed,
     729              : 
     730              :                 dist,
     731              : 
     732            0 :                 forward_predecessor_arc,
     733              : 
     734              :                 inverted_link
     735              :         );
     736              : 
     737            0 :         return *this;
     738              : }
     739              : 
     740              : extern template struct ContractionHierarchyExtraWeight<unsigned>;
     741              : extern template struct ContractionHierarchyExtraWeight<int>;
     742              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<std::vector<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const std::vector<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
     743              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<std::vector<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const std::vector<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
     744              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<std::vector<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const std::vector<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
     745              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<std::vector<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const std::vector<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
     746              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<ContractionHierarchyExtraWeight<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const ContractionHierarchyExtraWeight<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
     747              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<ContractionHierarchyExtraWeight<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const ContractionHierarchyExtraWeight<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
     748              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<ContractionHierarchyExtraWeight<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const ContractionHierarchyExtraWeight<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
     749              : extern template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<ContractionHierarchyExtraWeight<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const ContractionHierarchyExtraWeight<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
     750              : extern template ContractionHierarchyExtraWeight<unsigned>& ContractionHierarchyExtraWeight<unsigned>::reset<std::vector<unsigned>, SaturatedWeightAddition>(const ContractionHierarchy&ch, const std::vector<unsigned>&, const SaturatedWeightAddition&);
     751              : extern template ContractionHierarchyExtraWeight<int>& ContractionHierarchyExtraWeight<int>::reset<std::vector<int>, SaturatedWeightAddition>(const ContractionHierarchy&ch, const std::vector<int>&, const SaturatedWeightAddition&);
     752              : extern template unsigned ContractionHierarchyQuery::get_extra_weight_distance<std::vector<unsigned>,SaturatedWeightAddition>(const std::vector<unsigned>&, const SaturatedWeightAddition&);
     753              : extern template int ContractionHierarchyQuery::get_extra_weight_distance<std::vector<int>,SaturatedWeightAddition>(const std::vector<int>&, const SaturatedWeightAddition&);
     754              : extern template unsigned ContractionHierarchyQuery::get_extra_weight_distance<ContractionHierarchyExtraWeight<unsigned>,SaturatedWeightAddition>(const ContractionHierarchyExtraWeight<unsigned>&, const SaturatedWeightAddition&);
     755              : extern template int ContractionHierarchyQuery::get_extra_weight_distance<ContractionHierarchyExtraWeight<int>,SaturatedWeightAddition>(const ContractionHierarchyExtraWeight<int>&, const SaturatedWeightAddition&);
     756              : 
     757              : } // namespace RoutingKit
     758              : 
     759              : #endif
        

Generated by: LCOV version 2.0-1