Example #1
0
def make_tree(graph, source, edge_weight = None):
    parent = ydict(backend=graph)
    distance = ydict(backend=graph)
    queue = ydeque(backend=graph)
    queue_members = ydict(backend=graph)

    queue.append(source)
    queue_members[source] = True
    distance[source] = 0
    curr_pass = 0
    curr_last = source

    num_vertices = sum(1 for v in graph.vertices())

    while queue:
        v = queue.popleft()
        del queue_members[v]
        for e in graph.edges(source = v):
            w = other_vertex(e, v)
            dw, dv, e_weight = distance.get(w), distance[v], edge_weight[e]
            if dw is None or dv + e_weight < dw:
                distance[w] = dv + e_weight
                parent[w] = e
                if w not in queue_members:
                    queue.append(w)
                    queue_members[w] = True
        if v == curr_last and queue:
            curr_pass += 1
            curr_last = queue[-1]
        if curr_pass >= num_vertices:
            raise NegativeCycleError
    return parent
Example #2
0
def make_tree(graph, source, edge_weight = None):
    parent = ydict(backend=graph)
    heap = yheap(backend=graph)
    distance = ydict(backend=graph)
    
    u, distance[u] = source, 0
    while True:
        for e in graph.edges(source = u):
            if edge_weight[e] < 0:
                raise NegativeEdgeWeightError(e)
            v = other_vertex(e,u)
            distance_to_v = distance.get(v)
            relaxed_length = distance[u] + edge_weight[e]
            if distance_to_v is None or relaxed_length < distance_to_v:
                parent[v] = e
                distance[v] = relaxed_length
                if v in heap:
                    heap.modifykey(v, relaxed_length)
                else:
                    heap.insert(v, relaxed_length)

        try:
            u = heap.deletemin()
        except:
            return parent
Example #3
0
def connected_component_signature(g):
    components = connected_components.compile(g)
    component_size = ydict(g)
    for v in g.vertices():
        c = components(v)
        component_size[c] = component_size.setdefault(c,0) + 1
    return ydict(g, ((v, component_size[components(v)]) for v in g.vertices()))
Example #4
0
def reachability_signature(g, reach):
    sig = ydict(backend=g)
    for v in g.vertices():
        sig[v] = ydeque(sig, [1])
    for i in range(reach):
        for u in g.vertices():
            val = sum(sig[v][i] for x,v in g.edges(source=u))
            sig[u].append(val)
    return ydict(g, ((k,v[-1]) for k,v in sig.iteritems()))
Example #5
0
    def __init__(self, graph):
        self.description = 'depth-first search topological sort'
        finished_vertices = ydict(backend=graph)
        generator = depth_first_generator(graph)

        # Bootstrap the depth-first search generator with all vertices
        # of indegree 0. If there are no such vertices, raise an exception.
        found_starting_vertex = False
        for v in graph.vertices():
            try:
                graph.edges(target=v).next()
            except StopIteration:
                generator.bootstrap(v)
                found_starting_vertex = True
        if not found_starting_vertex:
            raise NoIndegreeZeroVertices

        # Topological ordering is now the reverse of the postorder. But
        # a topological ordering still might not be possible if there are
        # cycles, so we'll check for those here and raise an exception
        # if there is one.
        self.topological_order = ydeque(backend=graph)
        # TODO: don't use the generator directly here, use a visitor
        for e in generator.events():
            if e['type'] == 'VERTEX' and e['state'] == 'FINISHED':
                self.topological_order.append(e['vertex'])
            elif e['type'] == 'EDGE' and e['target_state'] == 'DISCOVERED':
                raise CycleExists
Example #6
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
Example #7
0
 def __call__(self, width=None, height=None):
     if width is None:
         width = 400
     if height is None:
         height = 400
         p = ydict(memory_usage=self.graph.MemoryUsage)
         p = fruchterman_reingold_drawing(self.graph, position = p, 
                                          min_x = 10, max_x = width + 10, 
                                          min_y = 10, max_y = height + 10,
                                          iterations = 500, temp = 100, 
                                          cool = lambda t : max(0, t - 0.1))
         p = fruchterman_reingold_drawing(self.graph, position = p, 
                                          min_x = 10, max_x = width + 10, 
                                          min_y = 10, max_y = height + 10,
                                          iterations = 100, temp = 20, 
                                          cool = lambda t : max(0, t - 1))
         return p
Example #8
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))))
Example #9
0
def is_a_partial_isomorphism(g1, g2, iso):
    """
    Precondition: len(g1.vertices()) == len(g2.vertices()) and
                  len(g1.edges()) == len(g2.edges())
    """
    g2_edges_mapped = ydict(backend=g1)
    for u,v in g1.edges():
        is_a_partial_iso = False
        try:
            u_image, v_image = iso[u], iso[v]
        except KeyError:
            continue
        chosen_edge = None
        for edge in g2.edges(source=u_image, target=v_image):
            if g2_edges_mapped.get(edge) is None:
                g2_edges_mapped[edge] = True
                chosen_edge = edge
                break
        if chosen_edge is None:
            return False
    return True
Example #10
0
def function_inverse(f, backend):
    inverse = ydict(backend=backend)
    for key, value in f.iteritems():
        inverse.setdefault(value,ydeque(backend=inverse)).append(key)
    return inverse
Example #11
0
def canonical_form(g, test_funcs):
    result_dicts = [func(g) for func in test_funcs]
    return ydict(g, ((v,tuple(d[v] for d in result_dicts)) 
                     for v in g.vertices()))
Example #12
0
 def __init__(self, agg):
     TraversalVisitor.__init__(self)
     self.properties = agg
     self.value = ydict(backend=agg)
Example #13
0
 def __init__(self, graph):
     self.__vertex_state = ydict(backend=graph)
     self.graph = graph
Example #14
0
 def __init__(self, graph, edge_weight):
     self.__graph = graph
     self.__edge_weight = edge_weight
     self.__priority_queue = yheap(backend=graph)
     self.__vertex_state = ydict(backend=graph)
Example #15
0
 def __init__(self, graph, vertex_heuristic):
     self.__graph = graph
     self.__h = vertex_heuristic
     self.__priority_queue = yheap(backend=graph)
     self.__vertex_state = ydict(backend=graph)