Esempio n. 1
0
    def extractTransition(self, line):
        """Given a line in a dpda description, return a new Transition object described by that line.

        Overrides the same method in TuringMachine. We need to
        override because the format is slightly different for dpdas,
        compared to Turing machines.

        Args:

            line (str): a line in a dpda description

        Returns:

            Transition: a new Transition object

        """
        (label, stackWriteStr, sourceState, destState) = \
                self.splitTransition(line)
        if TuringMachine.actionSeparator in stackWriteStr:
            raise WcbcException('transition ' + line + \
                                ' specifies a direction, which is illegal in a pda')
        if TuringMachine.actionSeparator not in label:
            raise WcbcException('transition ' + line + \
                                ' needs both a label and a stack symbol, which can be ' + \
                                Nfa.epsilonStr)
        (label, stackLabel) = [x.strip() for x in \
                                 label.split(TuringMachine.actionSeparator)]
        if label == Nfa.epsilonStr:
            direction = TuringMachine.stayDir
        else:
            direction = TuringMachine.rightDir

        return PdaTransition(sourceState, destState, label, \
                             stackLabel, stackWriteStr, direction)
Esempio n. 2
0
    def addEdge(self, edge, weight = 1):
        """Add an edge to the graph.

        An exception is thrown if the edge is already present. An
        exception is also thrown if the edge contains a node that is
        not in the graph.

        Args:

            edge (Edge): the edge to be added

            weight (int): the weight of the edge to be added

        """
        node1, node2 = edge.nodes
        if self.containsEdge(edge):
            raise WcbcException('edge ' + str(edge) + ' already in graph')
        if not node1 in self:
            raise WcbcException('node ' + node1 + ' not in graph')
        if not node2 in self:
            raise WcbcException('node ' + node2 + ' not in graph')

        self.nodes[node1][node2] = weight
        if not self.directed:
            self.nodes[node2][node1] = weight
        self.isolatedNodes = None # force recomputation later, when needed
Esempio n. 3
0
    def readDescription(self, graphString):
        """Read the given ASCII description of a graph, storing information about the nodes and edges.

        This is intended to be a private method called by
        __init__(). It will update self.nodes, which should be an
        empty dictionary when this method is called.

        Args:

            graphString (str): a description of the graph as an ASCII
                string, as described in the textbook. Examples include
                'a,b b,c c,a' and 'a,b,4 b,c,3'.

        """
        edgeDescriptions = [x.strip() for x in graphString.split()]
        for edgeDescription in edgeDescriptions:
            if len(edgeDescription)>0:
                components = edgeDescription.split(',')
                if len(components)==1:
                    # isolated node with no edges (yet)
                    (sourceStr, destStr, weightStr) = (components[0], None, None)
                elif self.weighted:
                    if len(components)!=3:
                        raise WcbcException('expected 3 components in edge description ' \
                                            + edgeDescription + \
                                            'for weighted graph')
                    (sourceStr, destStr, weightStr) = edgeDescription.split(',')
                    weight = int(weightStr)
                else:
                    if len(components)!=2:
                        raise WcbcException('expected 2 components in edge description ' \
                                            + edgeDescription + \
                                            'for unweighted graph')
                    (sourceStr, destStr) = edgeDescription.split(',')
                    weight = 1

                if len(sourceStr)==0 or (destStr and len(destStr)==0): 
                    raise WcbcException('encountered node name of length zero')
                
                if not sourceStr in self.nodes: 
                    self.nodes[sourceStr] = dict()
                source = self.nodes[sourceStr]
                if destStr!=None:
                    if not destStr in self.nodes:
                        # we haven't seen this node before -- create it
                        self.nodes[destStr] = dict()
                    if destStr in source:
                        raise WcbcException('duplicate edge ' + str([sourceStr, destStr]))
                    source[destStr] = weight
                    if not self.directed:
                        dest = self.nodes[destStr]
                        if sourceStr in dest and sourceStr!=destStr:
                            raise WcbcException('duplicate edge ' + str([destStr, sourceStr]))
                        dest[sourceStr] = weight
Esempio n. 4
0
    def cycleLength(self, cycle):
        """Return the "length" of the given cycle (i.e. total weight of its edges)

        For unweighted graphs, the length of the cycle is the number of
        edges in it. For weighted graphs, the "length" is the total
        weight of its edges. If the given cycle is not in fact a cycle
        in the current graph, an exception is raised.

        See the important note in the documentation for isCycle(): the
        given cycle parameter should not explicitly contain the final
        edge back to the start of the cycle; it will be added
        implicitly.

        Args:

            cycle (Path): the sequence p of nodes to be investigated

        Returns:

            int: the total weight of the edges in the cycle

        """
        if not self.isCycle(cycle):
            raise WcbcException(str(cycle) + ' is not a cycle in the graph ' + str(self))
        if len(cycle)==0:
            return 0
        pathLen = self.pathLength(cycle)
        finalEdge = Edge([cycle.end(), cycle.start()])
        return pathLen + self.getWeight(finalEdge)
Esempio n. 5
0
def fird(inString):
    split = inString.split()

    if len(split) != 3:
        raise WcbcException("input must be composed of 3 numbers")

    M, a, b = int(split[0]), int(split[1]), int(split[2])

    if a > b:
        raise WcbcException("a must be equal to or smaller than b")

    for i in range(max(a, 2), min(b + 1, M)):
        if M % i == 0:
            return "yes"

    return "no"
Esempio n. 6
0
    def end(self):
        """Return the final node in the path.

        Returns: 

           str: the final node in the path.

        """
        if len(self.nodes)==0:
            raise WcbcException('can\'t find end of empty path')
        return self.nodes[-1]
Esempio n. 7
0
    def start(self):
        """Return the initial node in the path.

        Returns: 

           str: the initial node in the path.

        """
        if len(self.nodes)==0:
            raise WcbcException('can\'t find start of empty path')
        return self.nodes[0]
Esempio n. 8
0
    def __init__(self, nodes):
        """Initialize Path object.
        
        Args:

            nodes (list of str): a list containing the names of the nodes in the path
        """
        if isinstance(nodes, str):
            raise WcbcException('Path constructor parameter must be a list, not a string')
        for node in nodes:
            if not isinstance(node, str):
                raise WcbcException('Path node', str(node), 'isn\'t a string')
            if len(node)==0:
                raise WcbcException('Encountered empty node name')

        self.nodes = tuple(nodes)
        """Tuple of the nodes in the path, where each node is a string."""

        self.nodeSet = None
        """A set of str that is constructed lazily (if and when needed). 
        It will contain the nodes in the path"""
                
        self.edgeSet = None
        """Set of Edge objects in the path. 
Esempio n. 9
0
    def addNode(self, node):
        """Add the given node to the graph.

        The node is added to the graph as an isolated node with no
        incoming or outgoing edges.

        Args:

            node (str): The node to be added.

        """
        if node in self.nodes:
            raise WcbcException('Tried to add existing node ' + node)
        self.nodes[node] = dict()
        self.isolatedNodes = None # force recomputation later, when needed
Esempio n. 10
0
    def getWeight(self, edge):
        """Return the weight of the given edge.

        An exception is thrown if the edge is not present.

        Args:

            edge (Edge): the edge to be searched for

        Returns:

            int: The weight of the given edge.

        """
        if not self.containsEdge(edge):
            raise WcbcException('edge ' + str(edge) + ' not in graph')
        node1, node2 = edge.nodes
        return self.nodes[node1][node2]
Esempio n. 11
0
    def removeEdge(self, edge):
        """Remove an edge from the graph.

        An exception is thrown if the edge is not already
        present. This implicitly requires that both nodes in the edge
        are also present.

        Args:

            edge (Edge): the edge to be removed

        """
        node1, node2 = edge.nodes
        if not self.containsEdge(edge):
            raise WcbcException('edge ' + str(edge) + ' not in graph')

        if node2 in self.nodes[node1]: del self.nodes[node1][node2]  
        if not self.directed:
            if node1 in self.nodes[node2]: del self.nodes[node2][node1] 
        self.isolatedNodes = None # force recomputation later, when needed
Esempio n. 12
0
def tryAllPrefixExtensions(graph, prefix, prefixDistance):
    if len(graph) == len(prefix):
        raise WcbcException(
            'tryAllPrefixExtensions() received a path that includes every node'
        )
    lastNode = prefix.end()
    bestCycle = None
    bestDistance = None
    for nextNode in graph.neighbors(lastNode):
        if nextNode not in prefix:
            extendedPrefix = prefix.extend(nextNode)
            extendedPrefixDistance = prefixDistance + graph.getWeight(
                Edge([lastNode, nextNode]))
            (cycle,
             distance) = shortestCycleWithPrefix(graph, extendedPrefix,
                                                 extendedPrefixDistance)
            if cycle != None:
                if bestDistance == None or distance < bestDistance:
                    bestDistance = distance
                    bestCycle = cycle
    return (bestCycle, bestDistance)
Esempio n. 13
0
    def weightedNeighbors(self, node):
        """Return a dictionary of the neighbors of a given node with weights as keys.

        The neighbors of node n are defined to be all nodes that are
        at the end of outgoing edges from n.

        Args:

            node (str): The node n whose neighbors will be returned.

        Returns:

            dictionary mapping str to int: Each key in the dictionary
                is a neighbor m of n, i.e. there is an edge from n to
                m. The value corresponding to key m is the weight of
                the edge n to m.

        """
        if not node in self:
            raise WcbcException('node ' + node + ' not in graph')
        return self.nodes[node]
Esempio n. 14
0
    def rotateToFront(self, node):
        """Cyclically permute the nodes in the path so that a given node is at
the start of the path.

        Args:

            node (str): The node which should be at the start of the
            path. An exception will be thrown if it is not currently
            in the path.

        Returns:

            Path: A new Path object, cyclically permuted so the given
            node is at the start of the path.

        """
        if not node in self.nodes:
            raise WcbcException('node ' + str(node) + ' is not in the path ' + str(self))
        ind = self.nodes.index(node)
        newNodes = self.nodes[ind:] + self.nodes[:ind]
        return Path(newNodes)
Esempio n. 15
0
    def pathLength(self, path):
        """Return the "length" of the given path (i.e. total weight of its edges)

        For unweighted graphs, the length of the path is the number of
        edges in it. For weighted graphs, the "length" is the total
        weight of its edges. If the given path is not in fact a path
        in the current graph, an exception is raised.

        Args:

            path (Path): the sequence p of nodes to be investigated

        Returns:

            int: the total weight of the edges in the path

        """
        if not self.isPath(path):
            raise WcbcException(str(path) + ' is not a path in the graph ' + str(self))
        length = 0
        for edge in path:
            length += self.getWeight(edge)
        return length
Esempio n. 16
0
    def neighbors(self, node):
        """Return a set-like view of the neighbors of a given node.

        The neighbors of node n are defined to be all nodes that are
        at the end of outgoing edges from n.

        Args:

            node (str): The node whose neighbors will be returned.

        Returns:

            dictionary view of str: The returned object is a
                dictionary view (see Python documentation on
                "dictionary view objects"). Iterating over this view
                will yield all nodes at the end of outgoing edges from
                the given parameter node.

        """
        
        if not node in self:
            raise WcbcException('node ' + node + ' not in graph')
        return self.nodes[node].keys()