def __init__(self, regex): """Initializes the NFA from the specified regular expression. :param regex: the regular expression """ self.regex = regex m = len(regex) self.m = m ops = Stack() graph = Digraph(m + 1) for i in range(0, m): lp = i if regex[i] == "(" or regex[i] == "|": ops.push(i) elif regex[i] == ")": or_ = ops.pop() # 2-way or operator if regex[or_] == "|": lp = ops.pop() graph.add_edge(lp, or_ + 1) graph.add_edge(or_, i) elif regex[or_] == "(": lp = or_ else: assert False if i < m - 1 and regex[i + 1] == "*": graph.add_edge(lp, i + 1) graph.add_edge(i + 1, lp) if regex[i] == "(" or regex[i] == "*" or regex[i] == ")": graph.add_edge(i, i + 1) if ops.size() != 0: raise ValueError("Invalid regular expression") self.graph = graph
def __init__(self, filename, delimiter): """ Initializes a digraph from a file using the specified delimiter. Each line in the file contains the name of a vertex, followed by a list of the names of the vertices adjacent to that vertex, separated by the delimiter. :param filename: the name of the file :param delimiter: the delimiter between fields """ self._st = BinarySearchST() # string -> index # First pass builds the index by reading strings to associate # distinct strings with an index stream = InStream(filename) while not stream.isEmpty(): a = stream.readLine().split(delimiter) for i in range(len(a)): if not self._st.contains(a[i]): self._st.put(a[i], self._st.size()) stdio.writef("Done reading %s\n", filename) # inverted index to get keys in an array self._keys = [None] * self._st.size() # index -> string for name in self._st.keys(): self._keys[self._st.get(name)] = name # second pass builds the graph by connecting first vertex on each # line to all others self._graph = Digraph(self._st.size()) # the underlying graph stream = InStream(filename) while stream.hasNextLine(): a = stream.readLine().split(delimiter) v = self._st.get(a[0]) for i in range(1, len(a)): w = self._st.get(a[i]) self._graph.add_edge(v, w)
def main(): """Unit tests the DirectedDFS data type.""" G = Digraph.from_stream(InStream(None)) sources = Bag() for i in range(1, len(sys.argv)): s = int(sys.argv[i]) sources.add(s) dfs = DirectedDFS(G, *sources) print("Reachable vertices:") for v in range(0, G.V()): if dfs.is_marked(v): print(v, end=" ") print()
def main(args): stream = InStream(args[0]) G = Digraph.from_stream(stream) scc = KosarajuSharirSCC(G) # number of connected components m = scc.count() print("{} strong components".format(m)) # compute list of vertices in each strong component components = [Queue() for i in range(m)] for v in range(G.V()): components[scc.id(v)].enqueue(v) # print results for i in range(m): for v in components[i]: print(str(v), end=" ") print()
def main(args): stream = InStream(args[0]) G = Digraph.from_stream(stream) tc = TransitiveClosure(G) # print header print(" ", end="") for v in range(G.V()): print("{x:3d}".format(x=v), end="") print() print("--------------------------------------------") # print transitive closure for v in range(G.V()): print("{x:3d}: ".format(x=v), end="") for w in range(G.V()): if tc.reachable(v, w): print(" T", end="") else: print(" ", end="") print()
class SymbolDigraph: """ The SymbolDigraph class representsclass represents a digraph, where the vertex names are arbitrary strings. By providing mappings between vertex names and integers, it serves as a wrapper around the Digraph data type, which assumes the vertex names are integers between 0 and V - 1. It also supports initializing a symbol digraph from a file. This implementation uses an ST to map from strings to integers, an array to map from integers to strings, and a Digraph to store the underlying graph. The index_of and contains operations take time proportional to log V, where V is the number of vertices. The name_of operation takes constant time. """ def __init__(self, filename, delimiter): """ Initializes a digraph from a file using the specified delimiter. Each line in the file contains the name of a vertex, followed by a list of the names of the vertices adjacent to that vertex, separated by the delimiter. :param filename: the name of the file :param delimiter: the delimiter between fields """ self._st = BinarySearchST() # string -> index # First pass builds the index by reading strings to associate # distinct strings with an index stream = InStream(filename) while not stream.isEmpty(): a = stream.readLine().split(delimiter) for i in range(len(a)): if not self._st.contains(a[i]): self._st.put(a[i], self._st.size()) stdio.writef("Done reading %s\n", filename) # inverted index to get keys in an array self._keys = [None] * self._st.size() # index -> string for name in self._st.keys(): self._keys[self._st.get(name)] = name # second pass builds the graph by connecting first vertex on each # line to all others self._graph = Digraph(self._st.size()) # the underlying graph stream = InStream(filename) while stream.hasNextLine(): a = stream.readLine().split(delimiter) v = self._st.get(a[0]) for i in range(1, len(a)): w = self._st.get(a[i]) self._graph.add_edge(v, w) def contains(self, s): """ Does the graph contain the vertex named s? :param s: the name of a vertex :return:s true if s is the name of a vertex, and false otherwise """ return self._st.contains(s) def index_of(self, s): """ Returns the integer associated with the vertex named s. :param s: the name of a vertex :returns: the integer (between 0 and V - 1) associated with the vertex named s """ return self._st.get(s) def name_of(self, v): """ Returns the name of the vertex associated with the integer v. @param v the integer corresponding to a vertex (between 0 and V - 1) @throws IllegalArgumentException unless 0 <= v < V @return the name of the vertex associated with the integer v """ self._validateVertex(v) return self._keys[v] def digraph(self): return self._graph def _validateVertex(self, v): # throw an IllegalArgumentException unless 0 <= v < V V = self._graph.V() if v < 0 or v >= V: raise ValueError("vertex {} is not between 0 and {}".format( v, V - 1))
i = 0 for v in self._order: self._rank[v] = i i += 1 def has_order(self): return self._order is not None def order(self): return self._order def rank(self, v): if self.has_order(): return self._rank[v] else: return -1 if __name__ == '__main__': graph = Digraph(5) graph.add_edge(0, 1) graph.add_edge(0, 3) graph.add_edge(2, 3) graph.add_edge(4, 0) graph.add_edge(2, 4) # cycles = DirectedCycle(graph) topo = Topological(graph) print(topo.has_order()) print(topo.order())
self._on_stack[v] = False def has_cycle(self): """Does the digraph have a directed cycle? :returns: true if there is a cycle, false otherwise """ return self._cycle is not None def cycle(self): """Returns a directed cycle if the digraph has a directed cycle, and null otherwise. :returns: a directed cycle (as an iterable) if the digraph has a directed cycle, and null otherwise """ return self._cycle if __name__ == "__main__": # Create stream from file or the standard input, # depending on whether a file name was passed. stream = sys.argv[1] if len(sys.argv) > 1 else None d = Digraph.from_stream(InStream(stream)) cyc = DirectedCycle(d) print(cyc.cycle())