def intensional_proposal(best, A, B): matches = tipward(best, A, B) result = {} incoming = index_by_target(matches) # Suppose `node` x comes from the A checklist, and there is a split # such that x matches multiple nodes y1, y2 in the B checklist. # Modify the relation for all approximate-match nodes. for y in incoming: # Many x's, one y arts = incoming[y] # Canonical. back.cod will be among the incoming, by construction. back = matches.get(y) # back : y -> x if not back: continue x0 = back.cod # Back match y -> x -> y revarts = incoming[x0] if len(arts) > 1: # multiple x's if len(revarts) > 1: art.proclaim(result, art.set_relation(back, rel.eq)) dribble.log("** Tangle:\n %s\n %s" % ("\n ".join(map(art.express, arts)), ("\n ".join(map(art.express, revarts))))) art.proclaim(result, art.set_relation(back, rel.eq)) else: # OK. We're going to just throw away all non-sibling matches. rent = cl.get_parent(x0) sibs = [ar for ar in arts if cl.get_parent(ar.dom) == rent] # e.g. ar: x2 -> y # Don't even try to do anything with N->M node tangles. if len(sibs) == 1: art.proclaim(result, art.set_relation(back, rel.eq)) else: for sib in sibs: ar = art.change_relation(sib, rel.lt, "merge", "split") if sib.dom == x0: art.proclaim(result, ar) # gt else: art.half_proclaim(result, ar) art.half_proclaim( result, art.bridge(y, rent, rel.lt, "split", "merge")) # Report! dribble.log( "# Split/lump %s < %s < %s" % (" + ".join(map(lambda e: cl.get_unique(e.dom), sibs)), cl.get_unique(y), cl.get_unique(rent))) elif len(revarts) > 1: # multiple y's pass else: # n.b. arts[0] is reverse of back art.proclaim(result, art.set_relation(back, rel.eq)) return result
def merged_parent(merged, al): (x, y) = merged # False if node is inconsistent if y: q = cl.get_parent(y) if x: p = cl.get_parent(x) else: p = partner(y, al) # cannot be =, must be < # If p takes us back to q, then parent should be p, else q scan = p while scan: z = partner(scan, al) if z: if z == q: return inject_A(p, al) else: return inject_B(q, al) scan = cl.get_parent(scan) return inject_B(q, al) else: assert x q = partner(x, al) if q: return inject_B(q, al) else: return inject_A(cl.get_parent(x), al)
def taxon_report(mnode, indent): nodiff = None different = mnode in any_descendant_differs id = id_table[mnode] (x, y) = mnode re = None dif = None z = None note = None if x and y: op = "SHARED" ar = al.get(x) comparison = changes.differences(x, y, all_props) # (drop, change, add) if not changes.same(comparison): props = changes.unpack(comparison) dif = ("; ".join(map(lambda x:x.pet_name, props))) px = cl.get_parent(x) qx = al.get(px) if qx and qx.cod != cl.get_parent(y): #note = ("moved from %s" % cl.get_taxon_id(px)) note = "moved" if not different: childs = children.get(mnode, []) if len(childs) > 0: nodiff = "subtree=" else: nodiff = "shared tip" elif x: op = "A ONLY" ar = al.get(x) if ar: z = ar.cod # Equivalence, usually, but sometimes not if ar.relation == rel.eq: note = "lump" # ??? is this right? elif ar.relation == rel.matches: note = "near miss" elif ar.relation == rel.conflict: note = "conflict" elif ar.relation == rel.refines: note = "loss of resolution" else: # y op = "B ONLY" ar = al.get(y) if ar: z = ar.cod if ar.relation == rel.eq: note = "split" elif ar.relation == rel.conflict: note = "reorganization" elif ar.relation == rel.refines: note = "increased resolution" report_one_articulation(id, op, nodiff, dif, x, y, z, ar, note, writer, indent) return different
def luup(x, y): if x == cl.forest_tnu or y == cl.forest_tnu: return assert cl.get_checklist(x) != cl.get_checklist(y) if in_chain(x, y0) and in_chain(y, x0): bar = best.get(x) if bar and find_in_chain(bar.cod, y, x0): if bar.cod == y: art.proclaim(draft, art.change_relation(bar, rel.eq, "extensional")) luup(cl.get_parent(x), cl.get_parent(y)) else: art.proclaim(draft, art.extensional(y, x, rel.lt, "presumed 0")) luup(x, cl.get_parent(y)) else: bar = best.get(y) if bar and find_in_chain(bar.cod, x, y0): if bar.cod == y: art.proclaim(draft, bar) luup(cl.get_parent(x), cl.get_parent(y)) else: art.proclaim(draft, art.extensional(x, y, rel.lt, "presumed 1")) luup(cl.get_parent(x), y) else: # neither x nor y matches by name art.proclaim(draft, art.extensional(x, y, rel.eq, "presumed mutual")) luup(cl.get_parent(x), cl.get_parent(y))
def luup(x, y): if x == cl.forest_tnu or y == cl.forest_tnu: return assert cl.get_checklist(x) != cl.get_checklist(y) if in_chain(x, y0) and in_chain(y, x0): bar = best.get(x) if bar and find_in_chain(bar.cod, y, x0): if bar.cod == y: art.proclaim(proposal, art.change_relation(bar, rel.eq, "extensional")) luup(cl.get_parent(x), cl.get_parent(y)) else: art.proclaim(proposal, art.extensional(y, x, rel.lt, "refines", "refined by")) luup(x, cl.get_parent(y)) else: bar = best.get(y) if bar and find_in_chain(bar.cod, x, y0): if bar.cod == y: art.proclaim(proposal, bar) luup(cl.get_parent(x), cl.get_parent(y)) else: art.proclaim(proposal, art.extensional(x, y, rel.lt, "refines*", "refined by*")) luup(cl.get_parent(x), y) else: # neither x nor y matches by name art.proclaim(proposal, art.extensional(x, y, rel.eq, "similar=")) luup(cl.get_parent(x), cl.get_parent(y))
def find_in_chain(b, y, x0): if y == cl.forest_tnu: return False elif in_chain(y, x0): if b == y: return True else: return find_in_chain(b, cl.get_parent(y), x0) else: return False
def compatible_ancestor(x): p = cl.get_parent(x) if p in retract: return compatible_ancestor(p) return x