Esempio n. 1
0
def forest_isomorphism(f1, f2):
    #TODO: do this at a higher level, since both iso testers need it
    if sum(1 for v in f1.vertices()) != sum(1 for v in f2.vertices()) or \
       sum(1 for e in f1.edges()) != sum(1 for e in f2.edges()):
        return None

    results = []
    for forest in (f1,f2):
        generator = depth_first_generator(forest)
        visitor = AggregateVisitor(backend=forest, 
                                   visitors={Depth:None}) 
        traverse(root_vertices=graph.vertices(),
                 visitor=visitor,
                 generator=depth_first_generator(forest))
        results.append(visitor.Depth)
    f1_depth, f2_depth = results

    f1_by_depths = ydict(backend=f1)
    f2_by_depths = ydict(backend=f2)
    max_depth = 0
    for forest, depth, index_by_depths in [(f1, f1_depth, f1_by_depths),
                                           (f2, f2_depth, f2_by_depths)]:
        for v in forest.vertices():
            d = depth[v]
            max_depth = max(d, max_depth)
            index_by_depths[d] = index_by_depths.setdefault(d, ydeque(backend=forest)).append(v)
            
    prev_f1_canonical_id = ydict(backend=f1)
    prev_f2_canonical_id = ydict(backend=f2)
    if len(f1_by_depths[max_depth]) != len(f2_by_depths[max_depth]):
        return
    for v in f1_by_depths[max_depth]:
        prev_f1_canonical_id[v] = 0
    for v in f2_by_depths[max_depth]:
        prev_f2_canonical_id[v] = 0

    for depth in xrange(max_depth - 1, -1, -1):
        f1_vertex_id = ydict(backend=f1)
        f2_vertex_id = ydict(backend=f2)
        if len(f1_by_depths[depth]) != len(f2_by_depths[depth]):
            return
        # don't do two-phase canonical id -> id transformation. instead, compute canonical ids
        # on the fly by storing a lexicographically sorted list of ids and binary searching for
        # existing ids each time
        for v in f1_by_depths[depth]:
            f1_vertex_id[v] = ydeque(backend=f2_vertex_id,
                                     ysorted(backend=f2_vertex_id,
                                             (prev_f1_canonical_id[w] for u,w in f1.edges(source=v))))
        for v in f2_by_depths[depth]:
            f2_vertex_id[v] = ydeque(backend=f2_vertex_id,
                                     ysorted(backend=f2_vertex_id,
                                             (prev_f2_canonical_id[w] for u,w in f2.edges(source=v))))
Esempio n. 2
0
def isomorphism(g1, g2):
    if sum(1 for v in g1.vertices()) != sum(1 for v in g2.vertices()) or \
       sum(1 for e in g1.edges()) != sum(1 for e in g2.edges()):
        return None

    test_funcs = [partial(reachability_signature, reach=1),
                  partial(reachability_signature, reach=2),
                  partial(reachability_signature, reach=4)]
    g1cf = canonical_form(g1, test_funcs)
    g2cf = canonical_form(g2, test_funcs)

    sorted_g1cf = ysorted(g1, g1cf.itervalues())
    sorted_g2cf = ysorted(g2, g2cf.itervalues())

    for x,y in izip(sorted_g1cf, sorted_g2cf):
        if x != y:
            return None

    g2_cform_inv = function_inverse(g2cf, g2)

    iso = ydict(backend=g1)

    contexts = ydeque(backend=g1)
    for v in g1.vertices():
        g2_inv_image = ydeque(backend=contexts)
        for image_element in g2_cform_inv[g1cf[v]]:
            g2_inv_image.append(image_element)
        contexts.append((v, g2_inv_image))
    index = 0

    while index >= 0 and index < len(contexts):
        vertex = contexts[index][0]
        if contexts[index][1]:
            v_prime = contexts[index][1].popleft()
            iso[vertex] = v_prime
            if is_a_partial_isomorphism(g1, g2, iso):
                index += 1
        else:
            if vertex in iso:
                del iso[vertex]
            g2_inv_image = ydeque(backend=contexts)
            for image_element in g2_cform_inv[g1cf[vertex]]:
                g2_inv_image.append(image_element)
                (index, vertex, str([x for x in g2_inv_image]))
            contexts[index] = (vertex, g2_inv_image)
            index -= 1

    if index < 0:
        return None
    else:
        return iso