def get_splits(initial_distance_matrix, split_function, update_function, on_label_split=None): """ This is the most external of the functions in this module. Get the set of splits implied by the tree that would be reconstructed. @param initial_distance_matrix: a distance matrix @param split_function: takes a distance matrix and returns an index split @param update_function: takes a distance matrix and an index subset and returns a distance matrix @param on_label_split: notifies the caller of the label split induced by an index split @return: a set of splits """ n = len(initial_distance_matrix) # keep a stack of (label_set_per_vertex, distance_matrix) pairs initial_state = ([set([i]) for i in range(n)], initial_distance_matrix) stack = [initial_state] # process the stack in a depth first manner, building the split set label_split_set = set() while stack: label_sets, D = stack.pop() # if the matrix is small then we are done if len(D) < 4: continue # split the indices using the specified function try: index_split = split_function(D) # convert the index split to a label split label_split = index_split_to_label_split(index_split, label_sets) # notify the caller if a callback is requested if on_label_split: on_label_split(label_split) # add the split to the master set of label splits label_split_set.add(label_split) # for large matrices create the new label sets and the new conformant distance matrices a, b = index_split for index_selection, index_complement in ((a, b), (b, a)): if len(index_complement) > 2: next_label_sets = SchurAlgebra.vmerge( label_sets, index_selection) next_D = update_function(D, index_selection) next_state = (next_label_sets, next_D) stack.append(next_state) except DegenerateSplitException, e: # we cannot recover from a degenerate split unless there are more than four indices if len(D) <= 4: continue # with more than four indices we can fall back to partial splits index_set = set([e.index]) # get the next label sets next_label_sets = SchurAlgebra.vdelete(label_sets, index_set) # get the next conformant distance matrix by schur complementing out the offending index L = Euclid.edm_to_laplacian(D) L_small = SchurAlgebra.mschur(L, index_set) next_D = Euclid.laplacian_to_edm(L_small) next_state = (next_label_sets, next_D) stack.append(next_state)
def get_splits(initial_distance_matrix, split_function, update_function, on_label_split=None): """ This is the most external of the functions in this module. Get the set of splits implied by the tree that would be reconstructed. @param initial_distance_matrix: a distance matrix @param split_function: takes a distance matrix and returns an index split @param update_function: takes a distance matrix and an index subset and returns a distance matrix @param on_label_split: notifies the caller of the label split induced by an index split @return: a set of splits """ n = len(initial_distance_matrix) # keep a stack of (label_set_per_vertex, distance_matrix) pairs initial_state = ([set([i]) for i in range(n)], initial_distance_matrix) stack = [initial_state] # process the stack in a depth first manner, building the split set label_split_set = set() while stack: label_sets, D = stack.pop() # if the matrix is small then we are done if len(D) < 4: continue # split the indices using the specified function try: index_split = split_function(D) # convert the index split to a label split label_split = index_split_to_label_split(index_split, label_sets) # notify the caller if a callback is requested if on_label_split: on_label_split(label_split) # add the split to the master set of label splits label_split_set.add(label_split) # for large matrices create the new label sets and the new conformant distance matrices a, b = index_split for index_selection, index_complement in ((a, b), (b, a)): if len(index_complement) > 2: next_label_sets = SchurAlgebra.vmerge(label_sets, index_selection) next_D = update_function(D, index_selection) next_state = (next_label_sets, next_D) stack.append(next_state) except DegenerateSplitException, e: # we cannot recover from a degenerate split unless there are more than four indices if len(D) <= 4: continue # with more than four indices we can fall back to partial splits index_set = set([e.index]) # get the next label sets next_label_sets = SchurAlgebra.vdelete(label_sets, index_set) # get the next conformant distance matrix by schur complementing out the offending index L = Euclid.edm_to_laplacian(D) L_small = SchurAlgebra.mschur(L, index_set) next_D = Euclid.laplacian_to_edm(L_small) next_state = (next_label_sets, next_D) stack.append(next_state)
def get_subtree_messages(D, eigensplit, ordered_tip_names): """ @param D: the matrix of pairwise distances among tips of the tree @param eigensplit: the split induced by the fiedler vector @param ordered_tip_names: names of the tips of the tree conformant to v and D @return: a multi-line string """ out = StringIO() n = len(D) ordered_label_sets = [set([i]) for i in range(n)] all_labels = set(range(n)) for i, child in enumerate(eigensplit): complement = all_labels - child D_child = MatrixUtil.get_principal_submatrix(D, list(sorted(child))) child_label_sets = SchurAlgebra.vdelete(ordered_label_sets, complement) v_child = BuildTreeTopology.edm_to_fiedler(D_child) print >> out, 'the Fiedler split of Schur complements of subtree', i + 1 for label_set, value in zip(child_label_sets, v_child): s = label_set_to_string(label_set, ordered_tip_names) print >> out, s, ':', value print >> out return out.getvalue().strip()
def get_subtree_messages(D, eigensplit, ordered_tip_names): """ @param D: the matrix of pairwise distances among tips of the tree @param eigensplit: the split induced by the fiedler vector @param ordered_tip_names: names of the tips of the tree conformant to v and D @return: a multi-line string """ out = StringIO() n = len(D) ordered_label_sets = [set([i]) for i in range(n)] all_labels = set(range(n)) for i, child in enumerate(eigensplit): complement = all_labels - child D_child = MatrixUtil.get_principal_submatrix(D, list(sorted(child))) child_label_sets = SchurAlgebra.vdelete(ordered_label_sets, complement) v_child = BuildTreeTopology.edm_to_fiedler(D_child) print >> out, 'the Fiedler split of Schur complements of subtree', i+1 for label_set, value in zip(child_label_sets, v_child): s = label_set_to_string(label_set, ordered_tip_names) print >> out, s, ':', value print >> out return out.getvalue().strip()