CGRA-ME
GraphAlgorithms_Searching.inl
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
15 template<typename Graph, typename InitialList, typename Visitor = DoNothingGraphVisitor<VertexID>>
17  Graph&& graph,
18  const InitialList& initial_list,
19  Visitor&& visitor = {}
20 ) const {
21 
22  struct VertexData {
23  bool put_in_queue = false;
24  };
25 
26  auto data = makeVertexMap<VertexData>();
27 
28  std::list<VertexID> to_visit;
29  for (const auto& vertex : initial_list) {
30  to_visit.push_back(vertex);
31  data[vertex].put_in_queue = true;
32  }
33 
34  while (!to_visit.empty() && !visitor.shouldStop()) {
35  const auto explore_curr = to_visit.front();
36  to_visit.pop_front();
37 
38  if (visitor.shouldIgnore(explore_curr)) {
39  visitor.onSkipped(explore_curr);
40  continue;
41  }
42 
43  visitor.onExamine(explore_curr);
44  for (const auto& fanout : graph.fanout(explore_curr)) {
45  auto& fanout_data = data[fanout];
46  if (!fanout_data.put_in_queue && !visitor.shouldIgnore(fanout)) {
47  fanout_data.put_in_queue = true;
48  to_visit.push_back(fanout);
49  visitor.onExamineEdge(explore_curr, fanout);
50  } else {
51  visitor.onSkippedEdge(explore_curr, fanout);
52  }
53  }
54  }
55 
56  return data;
57 }
58 
63 template<typename Graph, typename InitialList, typename VertexCoster, typename Visitor = DoNothingGraphVisitor<VertexID>>
65  Graph&& graph,
66  const InitialList& initial_list,
67  VertexCoster&& vertex_coster,
68  Visitor&& visitor = {}
69 ) const {
70  using Cost = decltype(vertex_coster(std::declval<VertexID>()));
71 
72  struct VertexData {
73  std::array<VertexID,1> fanin;
74  Cost lowest_known_cost;
75  bool operator==(const VertexData& rhs) const {
76  return this->lowest_known_cost == rhs.lowest_known_cost && this->fanin == rhs.fanin; }
77  // bool explored = false;
78  };
79 
80  // store cost in priority queue so we can have duplicates
81  struct VertexAndCost {
82  VertexID vid;
83  Cost cost_to_here;
84 
85  bool operator<(const VertexAndCost& rhs) const {
86  return cost_to_here > rhs.cost_to_here;
87  }
88  };
89 
90  auto data = makeVertexMap<VertexData>();
91  std::priority_queue<VertexAndCost> to_visit;
92 
93  for (const auto& vertex : initial_list) {
94  if (visitor.shouldIgnore(vertex)) {
95  visitor.onSkipped(vertex);
96  } else {
97  to_visit.push({vertex, 0});
98  data.insert({vertex, {{vertex}, 0}});
99  }
100  }
101 
102  while (!to_visit.empty() && !visitor.shouldStop()) {
103  const auto queue_top = to_visit.top();
104  const auto& explore_curr = queue_top.vid;
105  to_visit.pop();
106 
107  // nodes may be insereted in the queue more than once
108  // but we don't care, because the cost will be higher?
109  // auto& explored = data.at(explore_curr).explored;
110  // if (explored) {
111  if (visitor.shouldIgnore(explore_curr) || queue_top.cost_to_here > data.at(explore_curr).lowest_known_cost) {
112  visitor.onSkipped(explore_curr);
113  continue;
114  }
115  // explored = true;
116 
117  visitor.onExamine(explore_curr);
118  for (const auto& fanout : graph.fanout(explore_curr)) {
119  if (visitor.shouldIgnore(fanout) || visitor.shouldIgnoreEdge(explore_curr, fanout)) {
120  visitor.onSkippedEdge(explore_curr, fanout);
121  continue; // don't even add the vertex data
122  }
123  const auto cost = queue_top.cost_to_here + vertex_coster(fanout);
124  auto fanout_data_insert = data.insert({fanout, {{explore_curr}, cost}});
125  auto& fanout_data = fanout_data_insert.first->second;
126  bool worse = not fanout_data_insert.second && cost >= fanout_data.lowest_known_cost;
127  if (worse) {
128  visitor.onSkippedEdge(explore_curr, fanout);
129  } else {
130  // always insert -- duplicates will get ignored
131  fanout_data.lowest_known_cost = cost;
132  fanout_data.fanin = {explore_curr};
133  to_visit.push({fanout, cost});
134  visitor.onExamineEdge(explore_curr, fanout);
135  }
136  }
137  }
138 
139  return data;
140 }
141 
174 template<typename Graph, typename IsTarget, typename Visitor = DoNothingGraphVisitor<VertexID>, typename InitialList = std::vector<VertexID>>
176  Graph&& graph,
177  const InitialList& initial_list,
178  IsTarget&& is_target,
179  Visitor&& visitor = {}
180 ) const {
181 
182  struct VertexData {
183  std::vector<VertexID> fanin = {};
184  };
185 
186  struct ExploreData {
187  VertexID parent;
188  VertexID fanout;
189  };
190 
191  struct WaveData {
192  std::vector<ExploreData> next_wave = {};
193  void clear() {
194  next_wave.clear();
195  }
196  };
197 
198  auto data = makeVertexMap<VertexData>();
199 
200  // the following are cleared and reused each outer loop
201  std::vector<ExploreData> explorations_to_new_nodes;
202  auto in_next_wave = makeVertexSet();
203  std::vector<WaveData> waveData(num_threads);
204  std::vector<VertexID> curr_wave = {};
205 
206  for (const auto& vertex : initial_list) {
207  curr_wave.push_back(vertex);
208  data[vertex];
209  }
210 
211  while(true) {
212  const auto expand_wave_code = [&](int ithread) {
213  const auto& num_data_per_thread = 1 + ((curr_wave.size()-1)/num_threads); // rounds up
214  const auto& my_curr_wave_begin_index = ithread*num_data_per_thread;
215  const auto& my_curr_wave_end_index = (ithread + 1)*num_data_per_thread + 1;
216  const auto& my_curr_wave = make_iterator_range(
217  std::next(begin(curr_wave), std::min(curr_wave.size(), my_curr_wave_begin_index)),
218  std::next(begin(curr_wave), std::min(curr_wave.size(), my_curr_wave_end_index))
219  );
220  auto& my_next_wave = waveData.at(ithread).next_wave;
221 
222  for (const auto& id : my_curr_wave) {
223  if (visitor.shouldIgnore(id)) {
224  visitor.onSkipped(id);
225  continue;
226  }
227  visitor.onExamine(id);
228 
229  for (const auto& fanout : graph.fanout(id)) {
230  if (not visitor.shouldIgnore(fanout) && not visitor.shouldIgnoreEdge(id, fanout)) {
231  my_next_wave.emplace_back(ExploreData{id, fanout});
232  } else {
233  visitor.onSkippedEdge(id, fanout);
234  }
235  }
236  }
237  };
238 
239  if (num_threads == 1) {
240  expand_wave_code(0);
241  } else {
242  std::vector<std::thread> threads;
243 
244  for (int ithread = 0; ithread < num_threads; ++ithread) {
245  threads.emplace_back(expand_wave_code, ithread);
246  }
247 
248  for (auto& thread : threads) {
249  thread.join();
250  }
251  }
252 
253  bool found_target = false;
254  explorations_to_new_nodes.clear();
255  in_next_wave.clear();
256  curr_wave.clear();
257  for (auto& waveDatum : waveData) {
258  for (auto& exploreData : waveDatum.next_wave) {
259  // If not yet explored and not in next wave, add it
260  // Node: edges & fanout are already ignored in `expand_wave_code`
261  if (data.find(exploreData.fanout) == end(data)
262  && in_next_wave.emplace(exploreData.fanout).second
263  ) {
264  curr_wave.push_back(exploreData.fanout);
265  visitor.onExamineEdge(exploreData.parent, exploreData.fanout);
266  } else {
267  visitor.onSkippedEdge(exploreData.parent, exploreData.fanout);
268  }
269 
270  if (is_target(exploreData.fanout)) {
271  found_target = true;
272  }
273 
274  }
275  }
276 
277  // Couldn't modify `data` in the above loop, so do it here.
278  // Also, recall that this function returns a fanin graph with *all* discovered edges.
279  for (auto& waveDatum : waveData) {
280  for (auto& exploreData : waveDatum.next_wave) {
281  data[exploreData.fanout].fanin.emplace_back(exploreData.parent);
282  }
283  waveDatum.clear();
284  }
285 
286  visitor.onWaveEnd();
287  if (found_target || curr_wave.empty() || visitor.shouldStop()) {
288  break;
289  }
290  }
291 
292  return data;
293 }
294 
319 template<typename Graph, typename Source, typename IsTarget, typename Visitor = DoNothingGraphVisitor<VertexID>>
321  Graph&& graph,
322  const Source& source,
323  IsTarget&& is_target,
324  Visitor&& visitor = {}
325 ) const {
326  struct VertexData {
327  std::array<VertexID,1> fanin;
328  bool expanded = false;
329  };
330 
331  auto data = makeVertexMap<VertexData>();
332 
333  struct ExploreData {
334  VertexID driver;
335  VertexID fanout;
336  };
337 
338  std::vector<ExploreData> edges_to_visit;
339  edges_to_visit.emplace_back(ExploreData{source, source});
340  data.emplace(source, VertexData{{source}});
341 
342  while (not edges_to_visit.empty() && not visitor.shouldStop()) {
343  const auto edata = std::move(edges_to_visit.back());
344  edges_to_visit.pop_back();
345  const auto& v = edata.fanout;
346  auto& data_for_v = data.emplace(v, VertexData{{edata.driver}}).first->second;
347 
348  if (
349  data_for_v.expanded
350  || visitor.shouldIgnore(v)
351  || visitor.shouldIgnoreEdge(edata.driver, v)
352  ) {
353  visitor.onSkipped(v);
354  continue;
355  }
356 
357  data_for_v.fanin.at(0) = edata.driver; // in case already exists
358  data_for_v.expanded = true;
359  visitor.onExamine(v);
360 
361  if (is_target(v)) {
362  break;
363  }
364 
365  const auto insertion_point = edges_to_visit.size();
366  for (const auto& fanout : graph.fanout(v)) {
367  const auto fanout_data_search = data.find(fanout);
368  if (
369  not visitor.shouldIgnore(fanout)
370  && not visitor.shouldIgnoreEdge(v, fanout)
371  && ( fanout_data_search == end(data) || fanout_data_search->second.expanded )
372  ) {
373  visitor.onExamineEdge(v, fanout);
374  edges_to_visit.push_back(ExploreData{v, fanout});
375  } else {
376  visitor.onSkippedEdge(v, fanout);
377  }
378  }
379 
380  // reverse the list, so that we visit in lexicographical order
381  std::reverse(begin(edges_to_visit) + insertion_point, end(edges_to_visit));
382  }
383 
384  return data;
385 }
dijkstraVisit
auto dijkstraVisit(Graph &&graph, const InitialList &initial_list, VertexCoster &&vertex_coster, Visitor &&visitor={}) const
Definition: GraphAlgorithms_Searching.inl:64
wavedBreadthFirstVisit
auto wavedBreadthFirstVisit(Graph &&graph, const InitialList &initial_list, IsTarget &&is_target, Visitor &&visitor={}) const
Definition: GraphAlgorithms_Searching.inl:175
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
breadthFirstVisit
auto breadthFirstVisit(Graph &&graph, const InitialList &initial_list, Visitor &&visitor={}) const
Definition: GraphAlgorithms_Searching.inl:16
make_iterator_range
auto make_iterator_range(BIter &&b, EIter &&e)
Definition: Collections.h:48
operator==
bool operator==(const OpGraph &lhs, const OpGraph &rhs)
Definition: OpGraph.cpp:1159
operator<
bool operator<(const OpGraph::EdgeDescriptor &lhs, const OpGraph::EdgeDescriptor &rhs)
Definition: OpGraph.h:533
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
depthFirstVisit
auto depthFirstVisit(Graph &&graph, const Source &source, IsTarget &&is_target, Visitor &&visitor={}) const
Definition: GraphAlgorithms_Searching.inl:320
if
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0) set(CMAKE_CXX_FLAGS "$
Definition: CMakeLists.txt:7