Beispiel #1
0
    def main():
        """
        Main event dispatcher.
        Returns True if cycle should be reported, False or None otherwise.
        Appends recursive search of contracted graph to action stack.
        """
        if degree_two:
            return handle_degree_two()

        # At this point, we are going to branch, and if the time is really
        # exponential in the size of the remaining graph we can afford some
        # more expensive pruning steps first.

        # If graph is Hamiltonian it must be biconnected
        if not isBiconnected(G):
            return None

        # If graph is Hamiltonian, unforced edges must have a perfect matching.
        # We jump-start the matching algorithm with our previously computed
        # matching (or as much of it as fits the current graph) since that is
        # likely to be near-perfect.
        unforced = dict([(v, {}) for v in G])
        for v in G:
            for w in G[v]:
                if w not in forced_in_current[v]:
                    unforced[v][w] = True
        for v in previous_matching.keys():
            if v not in unforced or previous_matching[v] not in unforced[v]:
                del previous_matching[v]
        M = matching(unforced, previous_matching)
        previous_matching.clear()
        previous_matching.update(M)
        if len(M) != len(G):
            return None

        # Here with a degree three graph in which the forced edges
        # form a matching.  Pick an unforced edge adjacent to a
        # forced one, if possible, else pick any unforced edge,
        # and branch on the chosen edge.
        if forced_vertices:
            v = arbitrary_item(forced_vertices)
        else:
            v = arbitrary_item(G)
        w = [x for x in G[v] if x not in forced_in_current[v]][0]

        def continuation():
            """Here after searching first recursive subgraph."""
            if force(v, w):
                actions.append(main)

        actions.append(continuation)
        if safely_remove(v, w):
            actions.append(main)
Beispiel #2
0
    def __init__(self,D):
        # refine partition of states by reversed neighborhoods
        N = D.reverse()
        P = PartitionRefinement(D.states())
        P.refine([s for s in D.states() if D.isfinal(s)])
        unrefined = Sequence(P,key=id)
        while unrefined:
            part = arbitrary_item(unrefined)
            unrefined.remove(part)
            for symbol in D.alphabet:
                neighbors = Set()
                for state in part:
                    neighbors |= N.transition(state,symbol)
                for new,old in P.refine(neighbors):
                    if old in unrefined or len(new) < len(old):
                        unrefined.append(new)
                    else:
                        unrefined.append(old)

        # convert partition to DFA
        P.freeze()
        self.partition = P
        self.initial = P[D.initial]
        self.alphabet = D.alphabet
        self.DFA = D
Beispiel #3
0
    def check(self, G, N):
        """Make sure G has N Hamiltonian cycles."""
        count = 0
        for C in HamiltonianCycles(G):
            # Count the cycle.
            count += 1

            # Check that it's a degree-two undirected subgraph.
            for v in C:
                self.assertEqual(len(C[v]), 2)
                for w in C[v]:
                    assert v in G and w in G[v] and v in C[w]

            # Check that it connects all vertices.
            nreached = 0
            x = arbitrary_item(G)
            a, b = x, x
            while True:
                nreached += 1
                a, b = b, [z for z in C[b] if z != a][0]
                if b == x:
                    break
            self.assertEqual(nreached, len(G))

        # Did we find enough cycles?
        self.assertEqual(count, N)
Beispiel #4
0
 def states(self):
     visited = Set()
     unvisited = Set(self.initial)
     while unvisited:
         state = arbitrary_item(unvisited)
         yield state
         unvisited.remove(state)
         visited.add(state)
         for symbol in self.alphabet:
             unvisited |= self.transition(state,symbol) - visited
Beispiel #5
0
def LexBFS(G):
    """Find lexicographic breadth-first-search traversal order of a graph.
    G should be represented in such a way that "for v in G" loops through
    the vertices, and "G[v]" produces a sequence of the neighbors of v; for
    instance, G may be a dictionary mapping each vertex to its neighbor set.
    Running time is O(n+m) and additional space usage over G is O(n).
    """
    P = PartitionRefinement(G)
    S = Sequence(P, key=id)
    while S:
        set = S[0]
        v = arbitrary_item(set)
        yield v
        P.remove(v)
        if not set:
            S.remove(set)
        for new,old in P.refine(G[v]):
            S.insertBefore(old,new)
def greedyMatching(G, initialMatching=None):
    """Near-linear-time greedy heuristic for creating high-cardinality matching.
    If there is any vertex with one unmatched neighbor, we match it.
    Otherwise, if there is a vertex with two unmatched neighbors, we contract
    it away and store the contraction on a stack for later matching.
    If neither of these two cases applies, we match an arbitrary edge.
    """

    # Copy initial matching so we can use it nondestructively
    matching = {}
    if initialMatching:
        for x in initialMatching:
            matching[x] = initialMatching[x]

    # Copy graph to new subgraph of available edges
    # Representation: nested dictionary rep->rep->pair
    # where the reps are representative vertices for merged clusters
    # and the pair is an unmatched original pair of vertices
    avail = {}
    has_edge = False
    for v in G:
        if v not in matching:
            avail[v] = {}
            for w in G[v]:
                if w not in matching:
                    avail[v][w] = (v,w)
                    has_edge = True
            if not avail[v]:
                del avail[v]
    if not has_edge:
        return matching

    # make sets of degree one and degree two vertices
    deg1 = Set([v for v in avail if len(avail[v]) == 1])
    deg2 = Set([v for v in avail if len(avail[v]) == 2])
    d2edges = []
    def updateDegree(v):
        """Cluster degree changed, update sets."""
        if v in deg1:
            deg1.remove(v)
        elif v in deg2:
            deg2.remove(v)
        if len(avail[v]) == 0:
            del avail[v]
        elif len(avail[v]) == 1:
            deg1.add(v)
        elif len(avail[v]) == 2:
            deg2.add(v)

    def addMatch(v,w):
        """Add edge connecting two given cluster reps, update avail."""
        p,q = avail[v][w]
        matching[p] = q
        matching[q] = p
        for x in avail[v].keys():
            if x != w:
                del avail[x][v]
                updateDegree(x)
        for x in avail[w].keys():
            if x != v:
                del avail[x][w]
                updateDegree(x)
        avail[v] = avail[w] = {}
        updateDegree(v)
        updateDegree(w)

    def contract(v):
        """Handle degree two vertex."""
        u,w = avail[v]  # find reps for two neighbors
        d2edges.extend([avail[v][u],avail[v][w]])
        del avail[u][v]
        del avail[w][v]
        if len(avail[u]) > len(avail[w]):
            u,w = w,u   # swap to preserve near-linear time bound
        for x in avail[u].keys():
            del avail[x][u]
            if x in avail[w]:
                updateDegree(x)
            elif x != w:
                avail[x][w] = avail[w][x] = avail[u][x]
        avail[u] = avail[v] = {}
        updateDegree(u)
        updateDegree(v)
        updateDegree(w)

    # loop adding edges or contracting deg2 clusters
    while avail:
        if deg1:
            v = arbitrary_item(deg1)
            w = arbitrary_item(avail[v])
            addMatch(v,w)
        elif deg2:
            v = arbitrary_item(deg2)
            contract(v)
        else:
            v = arbitrary_item(avail)
            w = arbitrary_item(avail[v])
            addMatch(v,w)

    # at this point the edges listed in d2edges form a matchable tree
    # repeat the degree one part of the algorithm only on those edges
    avail = {}
    d2edges = [(u,v) for u,v in d2edges if u not in matching and v not in matching]
    for u,v in d2edges:
        avail[u] = {}
        avail[v] = {}
    for u,v in d2edges:
        avail[u][v] = avail[v][u] = (u,v)
    deg1 = Set([v for v in avail if len(avail[v]) == 1])
    while deg1:
        v = arbitrary_item(deg1)
        w = arbitrary_item(avail[v])
        addMatch(v,w)

    return matching
Beispiel #7
0
 def isfinal(self,state):
     rep = arbitrary_item(state)
     return self.DFA.isfinal(rep)
Beispiel #8
0
 def transition(self,state,symbol):
     rep = arbitrary_item(state)
     return self.partition[self.DFA.transition(rep,symbol)]