File: DijkstraShortestPathWithSiblings.h

package info (click to toggle)
polymake 4.14-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 35,888 kB
  • sloc: cpp: 168,933; perl: 43,407; javascript: 31,575; ansic: 3,007; java: 2,654; python: 632; sh: 268; xml: 117; makefile: 61
file content (211 lines) | stat: -rw-r--r-- 7,769 bytes parent folder | download | duplicates (2)
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
/* Copyright (c) 1997-2024
   Ewgenij Gawrilow, Michael Joswig, and the polymake team
   Technische Universität Berlin, Germany
   https://polymake.org

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
--------------------------------------------------------------------------------
*/

#pragma once

#include "polymake/graph/DijkstraShortestPathBase.h"

namespace polymake {
namespace graph {

class DijkstraShortestPathWithSiblings
   : public DijkstraShortestPathBase {
public:
   using base_layer = DijkstraShortestPathBase;

   template <typename FullLabel>
   struct Label : public base_layer::Label<FullLabel> {
      using base_t = base_layer::Label<FullLabel>;
      using base_layer::Label<FullLabel>::Label;

      //! another label on the same node merged into this one and not propagated further
      FullLabel* sibling = nullptr;
      //! label has been updated when absorbing a sibling
      bool is_updated = false;
   };

   struct LabelComparatorWithUpdates : public LabelCostComparator {
      template <typename FullLabel>
      pm::cmp_value operator() (const FullLabel& l1, const FullLabel& l2) const
      {
         const pm::cmp_value cmp_cost = operations::cmp::operator()(l1.get_min_cost(), l2.get_min_cost());
         if (cmp_cost != pm::cmp_eq) return cmp_cost;
         // an updated label should appear first at the heap top
         return l1.is_updated == l2.is_updated ? pm::cmp_eq : l1.is_updated ? pm::cmp_lt : pm::cmp_gt;
      }
   };

   template <typename Top>
   class Data : public base_layer::template Data<Top> {
   public:
      using base_t = typename base_layer::template Data<Top>;
      using typename base_t::label_t;
      using label_comparator_t = typename Top::label_comparator_t;

      using base_layer::template Data<Top>::Data;

      label_t* rotate_siblings(Int node)
      {
         label_t* old_first_label = this->labels_on_node[node];
         label_t* first_sibling = old_first_label->sibling;
         old_first_label->sibling = nullptr;
         label_t* next_sibling = first_sibling;
         while (next_sibling->sibling) next_sibling = next_sibling->sibling;
         next_sibling->sibling = old_first_label;
         this->labels_on_node[node] = first_sibling;
         return first_sibling;
      }
   };

   template <typename Top>
   class Algo : public base_layer::template Algo<Top> {
   public:
      using base_t = typename base_layer::template Algo<Top>;
      using typename base_t::graph_t;
      using typename base_t::label_t;
      using typename base_t::data_t;

      void propagate(label_t* const pred_label, const Int cur_node, const Int edge_id) const
      {
         label_t* cur_label = this->data.labels_on_node[cur_node];
         label_t* new_label = this->top().construct_label(pred_label, cur_node, edge_id);

         if (cur_label) {
            switch (this->top().compare_labels(new_label, cur_label)) {
            case DijkstraLabelCmp::discard_new:
               this->data.reclaim_label(new_label);
               return;
            case DijkstraLabelCmp::discard_old_and_siblings:
               this->top().drop_label(cur_label);
               this->top().erase_label(cur_label);
               break;
            case DijkstraLabelCmp::replace_old:
               this->top().drop_label(cur_label);
               new_label->sibling = cur_label;
               break;
            case DijkstraLabelCmp::discard_old_keep_siblings:
               this->top().drop_label(cur_label);
               new_label->sibling = cur_label->sibling;
               base_t::erase_label(cur_label);
               break;
            case DijkstraLabelCmp::keep_new_update_old:
               this->top().add_sibling(cur_label, new_label, pred_label);
               if (cur_label->heap_pos < 0) {
                  cur_label->is_updated = true;
                  this->data.heap.push(cur_label);
               }
               return;
            case DijkstraLabelCmp::keep_new_as_sibling:
               this->top().add_sibling(cur_label, new_label, pred_label);
               return;
            case DijkstraLabelCmp::propagate_both:
               throw std::runtime_error("DijkstraShortestPathWithSiblings: independent labels not supported yet");
            }
         }
         this->top().push_new_label(new_label, pred_label);
      }

      bool process_popped(label_t* const pred_label, const bool backward) const
      {
         if (pred_label->is_updated) {
            pred_label->is_updated = false;
            if (backward) {
               for (auto edge_it = entire(this->data.G.in_edges(pred_label->node)); !edge_it.at_end(); ++edge_it)
                  propagate_update(pred_label, edge_it.from_node(), *edge_it);
            } else {
               for (auto edge_it = entire(this->data.G.out_edges(pred_label->node)); !edge_it.at_end(); ++edge_it)
                  propagate_update(pred_label, edge_it.to_node(), *edge_it);
            }
            return false;
         }
         return true;
      }

      void add_sibling(label_t* cur_label, label_t* new_label, label_t* pred_label) const
      {
         new_label->set_predecessor(pred_label);
         new_label->refc = 1;
         new_label->sibling = cur_label->sibling;
         cur_label->sibling = new_label;
      }

      void update_siblings(label_t* label) const
      {
         remove_redundant_siblings(label, label, this->top().is_redundant_sibling_after_update());
      }

      void erase_label(label_t* label) const
      {
         do {
            label_t* sibling = label->sibling;
            base_t::erase_label(label);
            label = sibling;
         } while (label);
      }

      template <typename Predicate>
      void remove_redundant_siblings(label_t* const new_label, label_t* prev_sibling, const Predicate& is_redundant) const
      {
         label_t* cur_sibling = prev_sibling->sibling;
         while (cur_sibling) {
            label_t* next_sibling = cur_sibling->sibling;
            if (is_redundant(new_label, cur_sibling)) {
               base_t::erase_label(cur_sibling);
               prev_sibling->sibling = next_sibling;
            } else {
               prev_sibling = cur_sibling;
            }
            cur_sibling = next_sibling;
         }
      }

   protected:
      using base_layer::template Algo<Top>::Algo;

      void propagate_update(label_t* const pred_label, const Int cur_node, const Int edge_id) const
      {
         label_t* cur_label = this->data.labels_on_node[cur_node];

         // an update of pred_label can have an effect only when there is a descendant label at the current node
         for (label_t* any_label = cur_label; ; any_label = any_label->sibling) {
            if (any_label) {
               if (any_label->predecessor == pred_label) break;
            } else {
               return;
            }
         }

         if (this->top().update_label(pred_label, cur_label, edge_id)) {
            this->top().update_siblings(cur_label);
            if (cur_label->heap_pos < 0) {
               cur_label->is_updated = true;
               this->data.heap.push(cur_label);
            }
         }
      }

   };
};

} }


// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End: