def topsort(pairlist): numpreds = OrderedDict() # elt -> # of predecessors successors = OrderedDict() # elt -> list of successors for first, second in pairlist: # make sure every elt is a key in numpreds if first not in numpreds: numpreds[first] = 0 if second not in numpreds: numpreds[second] = 0 # if they're the same, there's no real dependence if first == second: continue # since first < second, second gains a pred ... numpreds[second] = numpreds[second] + 1 # ... and first gains a succ if first in successors: successors[first].append(second) else: successors[first] = [second] # suck up everything without a predecessor answer = filter(lambda x, numpreds=numpreds: numpreds[x] == 0, numpreds.keys()) # for everything in answer, knock down the pred count on # its successors; note that answer grows *in* the loop for x in answer: assert numpreds[x] == 0 del numpreds[x] if x in successors: for y in successors[x]: numpreds[y] = numpreds[y] - 1 if numpreds[y] == 0: answer.append(y) # following "del" isn't needed; just makes # CycleError details easier to grasp del successors[x] if numpreds: # everything in numpreds has at least one predecessor -> # there's a cycle if __debug__: for x in numpreds.keys(): assert numpreds[x] > 0 raise CycleError(answer, numpreds, successors) return answer
def topsort_levels(pairlist): numpreds = OrderedDict() # elt -> # of predecessors successors = OrderedDict() # elt -> list of successors for first, second in pairlist: # make sure every elt is a key in numpreds if first not in numpreds: numpreds[first] = 0 if second not in numpreds: numpreds[second] = 0 # if they're the same, there's no real dependence if first == second: continue # since first < second, second gains a pred ... numpreds[second] = numpreds[second] + 1 # ... and first gains a succ if first in successors: successors[first].append(second) else: successors[first] = [second] answer = [] while 1: # Suck up everything without a predecessor. levparents = [x for x in numpreds.keys() if numpreds[x] == 0] if not levparents: break answer.append(levparents) for levparent in levparents: del numpreds[levparent] if levparent in successors: for levparentsucc in successors[levparent]: numpreds[levparentsucc] -= 1 del successors[levparent] if numpreds: # Everything in num_parents has at least one child -> # there's a cycle. raise CycleError(answer, numpreds, successors) return answer
def _numpreds_and_successors_from_pairlist(pairlist): numpreds = OrderedDict() # elt -> # of predecessors successors = OrderedDict() # elt -> list of successors for first, second in pairlist: # make sure every elt is a key in numpreds if first not in numpreds: numpreds[first] = 0 if second not in numpreds: numpreds[second] = 0 # if they're the same, there's no real dependence if first == second: continue # since first < second, second gains a pred ... numpreds[second] = numpreds[second] + 1 # ... and first gains a succ if first in successors: successors[first].append(second) else: successors[first] = [second] return numpreds, successors
def get_preds(self): if self.preds is not None: return self.preds self.preds = preds = OrderedDict() remaining_elts = self.get_elements() for x in remaining_elts: preds[x] = [] succs = self.get_succs() for x in remaining_elts: if x in succs: for y in succs[x]: preds[y].append(x) if __debug__: for x in remaining_elts: assert len(preds[x]) > 0 return preds
def pick_a_cycle(self): remaining_elts = self.get_elements() # We know that everything in remaining_elts has a predecessor, # but don't know that everything in it has a successor. So # crawling forward over succs may hit a dead end. Instead we # crawl backward over the preds until we hit a duplicate, then # reverse the path. preds = self.get_preds() from random import choice x = choice(remaining_elts) answer = [] index = OrderedDict() in_answer = index.has_key while not in_answer(x): index[x] = len(answer) # index of x in answer answer.append(x) x = choice(preds[x]) answer.append(x) answer = answer[index[x]:] answer.reverse() return answer