#!/usr/bin/python3 """A dependency DAG.""" import logging logger = logging.Logger(__name__) class Node: def __init__(self, kids, function): self.kids = kids self.function = function self.asserted = False self.listeners = set() def val(self, listener=None): if listener is not None: self.listeners.add(listener) if not self.asserted: logger.debug("%s computing %s on %s", self, self.function, self.kids) self.assert_value(self.function(kid.val(self) for kid in self.kids)) return self.value def assert_value(self, value): if self.asserted: self.retract() self.value = value self.asserted = True def retract(self): if not self.asserted: return del self.value self.asserted = False for listener in self.listeners: listener.retract() self.listeners.clear() def sum_node(kids): return Node(kids, sum) def max_node(kids): return Node(kids, max) def input_node(): return Node([], throw) def throw(*args): raise UndefinedInput() class UndefinedInput(Exception): pass def main(): a = input_node() b = input_node() c = input_node() d = max_node([a, sum_node([b, c])]) a.assert_value(3) b.assert_value(4) c.assert_value(5) print(d.val()) a.assert_value(10) print(d.val()) e = d f = input_node() f.assert_value(-1) for ii in range(250): e = max_node([e, sum_node([e, f])]) print(e.val()) a.assert_value(11) print(e.val()) f.assert_value(1) print(e.val()) if __name__ == '__main__': main()