def add_node(dyad, parent_node): """Make a cost-scored node from a target pair dyad. Use memoized cost lookups for speed""" matches = [x for x in parent_node.children if x.name == dyad] if not any(matches): n = Node(dyad) n.cost = get_cost(dyad) n.parent = parent_node else: n = matches[0] return n
def make_tree(): """Iteratively build a tree of unique, valid tetrads. A valid tetrad has 4 target dyads whose elements obey the relationship {(a, c), (a, d), (b, c), (b, d)} """ # memoized cache of previously-added valid tetrads to prevent duplication. valid_tetrads = set() root = Node('root') root.cost = 0 # bush_root is A and C for parent in dyad_pairs: # all children are A and D br_children = [ d for d in dyads if parent[0] == d[0] # is a and parent[1] != d[1] ] # is not A. for child in br_children: # all grandchildren are B and C grandchildren = [ d for d in dyads if d[0] != parent[0] # not a and d[0] != child[1] # not d and d[1] == parent[1] ] # is c for grandchild in grandchildren: # all greatgrandchildren are B and D greatgrandchildren = [ d for d in dyads if d[0] == grandchild[0] and d[1] == child[1] ] for greatgrandchild in greatgrandchildren: tetrad = make_tetrad(parent, child, grandchild, greatgrandchild) if is_valid(tetrad) and tetrad not in valid_tetrads: valid_tetrads.add(tetrad) parent_node = add_node(parent, root) child_node = add_node(child, parent_node) grandchild_node = add_node(grandchild, child_node) greatgrandchild_node = add_node( greatgrandchild, grandchild_node) print(f'processed bush with root {parent}') print( f'took {(datetime.now() -start).total_seconds()} to generate full tree before pruning' ) return root