CGRA-ME
GraphAlgorithms_Paths.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 
20 template<typename VertexDataMap, typename Visitor = DoNothingGraphVisitor<VertexID>, typename SourceList = std::vector<VertexID>>
21 TracebackResult singleTraceback(
22  const SourceList& sources,
23  const VertexID& sink,
24  const VertexDataMap& vertex_data,
25  Visitor&& visitor = {}
26 ) const {
27  using std::end;
28 
29  auto nodes_in_path = makeVertexSet();
30  std::vector<VertexID> path;
31  bool success = true;
32 
33  bool done = false;
34  bool left_source = false;
35  auto traceback_curr = sink;
36  while (success && not done) {
37  success = false;
38  visitor.onExamine(traceback_curr);
39  path.push_back(traceback_curr);
40  if (left_source) {
41  nodes_in_path.insert(traceback_curr); // properly handle when sink \in sources
42  }
43  if (sources.find(traceback_curr) != end(sources) && left_source) {
44  success = true;
45  done = true;
46  } else {
47  const auto& data_search = vertex_data.find(traceback_curr);
48  if (data_search != end(vertex_data)) {
49  auto& found_data = data_search->second;
50  for (auto& fanin : found_data.fanin) {
51  if (not visitor.shouldIgnore(fanin) && nodes_in_path.find(fanin) == end(nodes_in_path)) {
52  traceback_curr = fanin;
53  success = true;
54  break;
55  }
56  }
57  if (not success && not found_data.fanin.empty()) {
58  traceback_curr = found_data.fanin.front();
59  success = true;
60  }
61  if (success && nodes_in_path.find(traceback_curr) != end(nodes_in_path)) {
62  success = false;
63  }
64  }
65  }
66  left_source = true;
67  }
68 
69  std::reverse(begin(path), end(path));
70 
71  return {path, success};
72 }
73 
74 
96 template<typename Graph, typename IsTarget, typename AcceptPath = AlwaysTrue,
97  typename Visitor = DoNothingGraphVisitor<VertexID>, typename InitialList = std::vector<VertexID>>
99  std::ptrdiff_t max_paths,
100  Graph&& graph,
101  const InitialList& initial_list,
102  IsTarget&& is_target,
103  Visitor&& visitor = {},
104  AcceptPath&& acceptPath = {}
105 ) const {
106  struct VertexData {
107  int expansion_count = 0;
108  bool operator==(const VertexData& rhs) const { return this->expansion_count == rhs.expansion_count; }
109  };
110 
111  auto vdata = makeVertexMap<VertexData>();
112 
113  PathList result;
114 
115  // the "wavefront" of paths
116  std::set<std::pair<std::ptrdiff_t, VertexPath>> paths_to_explore;
117  // any paths skipped because of max-expansion.
118  // Used to re-seed the wavefront if a path is not accepted.
119  std::set<std::pair<std::ptrdiff_t, VertexPath>> paths_skipped;
120 
121  int skipped_paths = 0;
122 
123  const auto cost_and_add_path = [&](const auto& base_path, const auto& new_vertex) {
124  auto new_path = base_path;
125  new_path.push_back(new_vertex);
126  auto new_path_cost = new_path.size();
127  paths_to_explore.emplace(new_path_cost, std::move(new_path));
128  };
129 
130  // do the first wave of expansion, so we never have size-1 paths
131  for (const auto& vertex : initial_list) {
132  if (visitor.shouldIgnore(vertex)) {
133  visitor.onSkippedEdge(vertex, vertex); continue; }
134 
135  visitor.onExamine(vertex);
136  for (const auto& fanout : graph.fanout(vertex)) {
137  if (visitor.shouldIgnore(fanout) || visitor.shouldIgnoreEdge(vertex,fanout)) {
138  visitor.onSkippedEdge(vertex, fanout); continue; }
139 
140  visitor.onExamineEdge(vertex,fanout);
141  cost_and_add_path(VertexPath{vertex}, fanout);
142  }
143  }
144 
145  while (!paths_to_explore.empty() && ((std::ptrdiff_t)result.size() + skipped_paths) != max_paths) {
146  // get shortest path & remove it
147  auto cost_and_path_mutable = std::move(*paths_to_explore.begin());
148  const auto& p = cost_and_path_mutable.second; // all access will be const
149  paths_to_explore.erase(begin(paths_to_explore));
150 
151  const auto& tip = p.back();
152 
153  if (visitor.shouldIgnore(tip)) {
154  visitor.onSkipped(tip);
155  continue;
156  }
157 
158  if (vdata[tip].expansion_count == max_paths) {
159  visitor.onSkipped(tip);
160  // save for later, in case a path is not accepted
161  paths_skipped.insert(std::move(cost_and_path_mutable));
162  continue;
163  }
164 
165  visitor.onExamine(tip);
166 
167  // increase expansion number of tip
168  vdata[tip].expansion_count += 1;
169 
170  // if we still want to expand the target, then add paths with fanout to explore queue
171  for (const auto& fanout : graph.fanout(tip)) {
172  if (
173  not visitor.shouldIgnore(fanout)
174  && not visitor.shouldIgnoreEdge(tip,fanout)
175  && p.front() != p.back() // don't expand loops
176  && find(std::next(begin(p)), end(p), fanout) == end(p) // no repeats, except the first
177  ) {
178  cost_and_add_path(p, fanout);
179 
180  visitor.onExamineEdge(tip, fanout);
181  } else {
182  visitor.onSkippedEdge(tip, fanout);
183  }
184  }
185 
186  // if tip is target, add to result set
187  if (is_target(tip)) {
188  if (acceptPath(p)) {
189  result.emplace_back(std::move(cost_and_path_mutable.second));
190  } else {
191  max_paths += 1; // make sure search continues
192  skipped_paths += 1; // remember we skipped one
193  // reconsider any skipped paths
194  std::move(paths_skipped.begin(), paths_skipped.end(),
195  std::inserter(paths_to_explore, paths_to_explore.end()));
196  paths_skipped.clear();
197  }
198  }
199  }
200 
201  return result;
202 }
203 
204 template<typename Graph, typename IsTarget, typename Visitor = DoNothingGraphVisitor<VertexID>, typename InitialList = std::vector<VertexID>>
206  std::ptrdiff_t max_paths,
207  Graph&& graph,
208  const InitialList& initial_list,
209  IsTarget&& is_target,
210  Visitor&& visitor
211 ) const {
212  auto initial_path = findNShortestPaths(1, graph, initial_list, is_target, visitor).at(0);
213  std::set<std::pair<int,VertexPath>> potential_paths {};
214 
215  PathList result;
216  if (max_paths == 0) { return result; }
217  result.push_back(initial_path);
218  for (int k = 1; k != max_paths; ++k) {
219  const auto& prev_path = result.back();
220 
221  for (int i = 0; i < (std::ptrdiff_t)prev_path.size() - 1; ++i) {
222  const auto pp_spurNode = std::next(prev_path.begin(), i);
223 
224  struct V : ForwardingVisitor<Visitor> {
225  using Base = ForwardingVisitor<Visitor>;
226  VertexSet<> vertices_to_ignore = {};
227  EdgeSet edges_to_ignore = {};
228 
229  V(typename Base::VisitorPtr fwd) : Base(fwd) { }
230 
231  bool shouldIgnore(const VertexID& v) {
232  return Base::shouldIgnore(v)
233  || vertices_to_ignore.find(v) != end(vertices_to_ignore);
234  }
235  bool shouldIgnoreEdge(const VertexID& v1, const VertexID& v2) {
236  return Base::shouldIgnoreEdge(v1,v2)
237  || edges_to_ignore.find(std::make_pair(v1, v2)) != end(edges_to_ignore);
238  }
239  } v (&visitor);
240 
241  for (const auto& p : result) {
242  if (std::mismatch(
243  prev_path.begin(), std::next(pp_spurNode),
244  p.begin(), p.end()
245  ).first == std::next(pp_spurNode)
246  ) {
247  v.edges_to_ignore.emplace(p.at(i), p.at(i+1));
248  }
249  }
250  for (auto it = prev_path.begin(); it != pp_spurNode; ++it) {
251  v.vertices_to_ignore.insert(*it);
252  }
253 
254  const auto spurpath_search = findNShortestPaths(1, graph, {*pp_spurNode}, is_target, v);
255  if (spurpath_search.size() == 0) {
256  continue;
257  }
258  const auto& spur_path = spurpath_search.at(0);
259 
260  VertexPath totalPath;
261  std::copy(prev_path.begin(), pp_spurNode, std::back_inserter(totalPath));
262  std::copy(spur_path.begin(), spur_path.end(), std::back_inserter(totalPath));
263 
264  potential_paths.emplace(totalPath.size(), totalPath);
265  }
266 
267  if (potential_paths.empty()) {
268  break;
269  }
270 
271  auto best_path_it = potential_paths.begin();
272  result.push_back(best_path_it->second);
273  potential_paths.erase(best_path_it);
274  }
275 
276 
277  return result;
278 }
ForwardingVisitor
Definition: GraphAlgorithmHelpers.h:110
ForwardingVisitor::shouldIgnore
bool shouldIgnore(const VertexID &v)
Definition: GraphAlgorithmHelpers.h:129
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
singleTraceback
TracebackResult singleTraceback(const SourceList &sources, const VertexID &sink, const VertexDataMap &vertex_data, Visitor &&visitor={}) const
Definition: GraphAlgorithms_Paths.inl:21
AlwaysTrue
Definition: Functional.h:92
ForwardingVisitor::shouldIgnoreEdge
bool shouldIgnoreEdge(const VertexID1 &v1, const VertexID2 &v2)
Definition: GraphAlgorithmHelpers.h:132
findNShortestSimplePaths
PathList findNShortestSimplePaths(std::ptrdiff_t max_paths, Graph &&graph, const InitialList &initial_list, IsTarget &&is_target, Visitor &&visitor) const
Definition: GraphAlgorithms_Paths.inl:205
findNShortestPaths
PathList findNShortestPaths(std::ptrdiff_t max_paths, Graph &&graph, const InitialList &initial_list, IsTarget &&is_target, Visitor &&visitor={}, AcceptPath &&acceptPath={}) const
Definition: GraphAlgorithms_Paths.inl:98
operator==
bool operator==(const OpGraph &lhs, const OpGraph &rhs)
Definition: OpGraph.cpp:1159
DoNothingGraphVisitor
Definition: GraphAlgorithmHelpers.h:49
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
MappingStatus::success
@ success