| 201 | |
| 202 | # See note "On Finding Cycles" at the bottom. |
| 203 | def _find_cycle(self): |
| 204 | n2i = self._node2info |
| 205 | stack = [] |
| 206 | itstack = [] |
| 207 | seen = set() |
| 208 | node2stacki = {} |
| 209 | |
| 210 | for node in n2i: |
| 211 | if node in seen: |
| 212 | continue |
| 213 | |
| 214 | while True: |
| 215 | if node in seen: |
| 216 | if node in node2stacki: |
| 217 | return stack[node2stacki[node] :] + [node] |
| 218 | # else go on to get next successor |
| 219 | else: |
| 220 | seen.add(node) |
| 221 | itstack.append(iter(n2i[node].successors).__next__) |
| 222 | node2stacki[node] = len(stack) |
| 223 | stack.append(node) |
| 224 | |
| 225 | # Backtrack to the topmost stack entry with |
| 226 | # at least another successor. |
| 227 | while stack: |
| 228 | try: |
| 229 | node = itstack[-1]() |
| 230 | break # resume at top of "while True:" |
| 231 | except StopIteration: |
| 232 | # no more successors; pop the stack |
| 233 | # and continue looking up |
| 234 | del node2stacki[stack.pop()] |
| 235 | itstack.pop() |
| 236 | else: |
| 237 | # stack is empty; look for a fresh node to |
| 238 | # start over from (a node not yet in seen) |
| 239 | break |
| 240 | return None |
| 241 | |
| 242 | def static_order(self): |
| 243 | """Returns an iterable of nodes in a topological order. |