Instruction:
Can you implement a function in Python 3 that
returns list of identities transitively derived from all identity.

Response:
def derived_from_all(self, identities: List[QualName]) -> MutableSet[QualName]:
        """Return list of identities transitively derived from all `identity`."""
        if not identities:
            return set()
        res = self.derived_from(identities[0])
        for id in identities[1:]:
            res &= self.derived_from(id)
        return res


Instruction:
Can you tell what is the following Python 3 function doing
def if_features(self, stmt: Statement, mid: ModuleId) -> bool:
        iffs = stmt.find_all("if-feature")
        if not iffs:
            return True
        for i in iffs:
            if not FeatureExprParser(i.argument, self, mid).parse():
                return False
        return True

Response: Evaluate if - feature substatements on a statement.


Instruction:
Can you generate the documentation for the following Python 3 function
def parse(self) -> bool:
        self.skip_ws()
        res = self._feature_disj()
        self.skip_ws()
        if not self.at_end():
            raise InvalidFeatureExpression(self)
        return res

Response: Parse and evaluate a complete if - feature expression.


Instruction:
Can you generate the documentation for the following Python 3 function
def char(self, c: str) -> None:
        if self.peek() == c:
            self.offset += 1
        else:
            raise UnexpectedInput(self, f"char '{c}'")

Response: Parse the specified character.


Instruction:
Write a Python 3 script for
running a DFA and return the final state.

Response:
def dfa(self, ttab: TransitionTable, init: int = 0) -> int:
        """Run a DFA and return the final (negative) state.

        Args:
            ttab: Transition table (with possible side-effects).
            init: Initial state.

        Raises:
            EndOfInput: If past the end of `self.input`.
        """
        state = init
        while True:
            disp = ttab[state]
            ch = self.peek()
            state = disp.get(ch, disp[""])()
            if state < 0:
                return state
            self.offset += 1


Instruction:
Can you write a function in Python 3 where it
returns line and column coordinates.

Response:
def line_column(self) -> Tuple[int, int]:
        """Return line and column coordinates."""
        ln = self.input.count("\n", 0, self.offset)
        c = (self.offset if ln == 0 else
             self.offset - self.input.rfind("\n", 0, self.offset) - 1)
        return (ln + 1, c)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def match_regex(self, regex: Pattern, required: bool = False,
                    meaning: str = "") -> str:
        """Parse input based on a regular expression .

        Args:
            regex: Compiled regular expression object.
            required: Should the exception be raised on unexpected input?
            meaning: Meaning of `regex` (for use in error messages).

        Raises:
            UnexpectedInput: If no syntactically correct keyword is found.
        """
        mo = regex.match(self.input, self.offset)
        if mo:
            self.offset = mo.end()
            return mo.group()
        if required:
            raise UnexpectedInput(self, meaning)

Response: Parse input based on a regular expression.


Instruction:
Here you have a function in Python 3, explain what it does
def one_of(self, chset: str) -> str:
        res = self.peek()
        if res in chset:
            self.offset += 1
            return res
        raise UnexpectedInput(self, "one of " + chset)

Response: Parse one character form the specified set.


Instruction:
Can you generate the documentation for the following Python 3 function
def peek(self) -> str:
        try:
            return self.input[self.offset]
        except IndexError:
            raise EndOfInput(self)

Response: Return the next character without advancing offset.


Instruction:
Create a Python 3 function to
parse identifier with an optional colon - separated prefix.

Response:
def prefixed_name(self) -> Tuple[YangIdentifier, Optional[YangIdentifier]]:
        """Parse identifier with an optional colon-separated prefix."""
        i1 = self.yang_identifier()
        try:
            next = self.peek()
        except EndOfInput:
            return (i1, None)
        if next != ":":
            return (i1, None)
        self.offset += 1
        return (self.yang_identifier(), i1)


Instruction:
Implement a function in Python 3 to
return the remaining part of the input string.

Response:
def remaining(self) -> str:
        """Return the remaining part of the input string."""
        res = self.input[self.offset:]
        self.offset = len(self.input)
        return res


Instruction:
Given the following Python 3 function, write the documentation
def up_to(self, term: str) -> str:
        end = self.input.find(term, self.offset)
        if end < 0:
            raise EndOfInput(self)
        res = self.input[self.offset:end]
        self.offset = end + 1
        return res

Response: Parse and return the next occurrence of a string.


Instruction:
How would you explain what the following Python 3 function does
def restrict_with(self, expr: str, error_tag: str = None,
                      error_message: str = None) -> None:
        """Combine the receiver with new intervals.

        Args:
            expr: "range" or "length" expression.
            error_tag: error tag of the new expression.
            error_message: error message for the new expression.

        Raises:
            InvalidArgument: If parsing of `expr` fails.
        """
        def parse(x: str) -> Number:
            res = self.parser(x)
            if res is None:
                raise InvalidArgument(expr)
            return res

        def simpl(rng: List[Number]) -> List[Number]:
            return ([rng[0]] if rng[0] == rng[1] else rng)

        def to_num(xs): return [parse(x) for x in xs]
        lo = self.intervals[0][0]
        hi = self.intervals[-1][-1]
        ran = []
        for p in [p.strip() for p in expr.split("|")]:
            r = [i.strip() for i in p.split("..")]
            if len(r) > 2:
                raise InvalidArgument(expr)
            ran.append(r)
        if ran[0][0] != "min":
            lo = parse(ran[0][0])
        if ran[-1][-1] != "max":
            hi = parse(ran[-1][-1])
        self.intervals = (
            [simpl([lo, hi])] if len(ran) == 1 else (
                [simpl([lo, parse(ran[0][-1])])] +
                [to_num(r) for r in ran[1:-1]] +
                [simpl([parse(ran[-1][0]), hi])]))
        if error_tag:
            self.error_tag = error_tag
        if error_message:
            self.error_message = error_message

Response: Combine the receiver with new intervals.


Instruction:
Make a summary of the following Python 3 code
def add_child(self, n, parent, **attrs):
        '''
        API: add_child(self, n, parent, **attrs)
        Description:
            Adds child n to node parent and return Node n.
        Pre:
            Node with name parent should exist.
        Input:
            n: Child node name.
            parent: Parent node name.
            attrs: Attributes of node being added.
        Post:
            Updates Graph related graph data attributes.
        Return:
            Returns n Node instance.
        '''
        attrs['level'] = self.get_node(parent).get_attr('level') + 1
        attrs['parent'] = parent
        self.add_node(n, **attrs)
        self.add_edge(parent, n)
        return self.get_node(n)

Response: Adds a child node n to a parent node and returns n.


Instruction:
Can you tell what is the following Python 3 function doing
def dfs(self, root = None, display = None):
        '''
        API: dfs(self, root = None, display = None)
        Description:
            Searches tree starting from node named root using depth-first
            strategy if root argument is provided. Starts search from root node
            of the tree otherwise.
        Pre:
            Node indicated by root argument should exist.
        Input:
            root: Starting node name.
            display: Display argument.
        '''
        if root == None:
            root = self.root
        if display == None:
            display = self.attr['display']
        self.traverse(root, display, Stack())

Response: This function returns a tree of nodes with depth - first search.


Instruction:
Can you generate the documentation for the following Python 3 function
def traverse(self, root = None, display = None, q = Stack()):
        '''
        API: traverse(self, root = None, display = None, q = Stack())
        Description:
            Traverses tree starting from node named root. Used strategy (BFS,
            DFS) is controlled by argument q. It is a DFS if q is Queue(), BFS
            if q is Stack(). Starts search from root argument if it is given.
            Starts from root node of the tree otherwise.
        Pre:
            Node indicated by root argument should exist.
        Input:
            root: Starting node name.
            display: Display argument.
            q: Queue data structure instance. It is either a Stack() or
            Queue().
        '''
        if root == None:
            root = self.root
        if display == None:
            display = self.attr['display']
        if isinstance(q, Queue):
            addToQ = q.enqueue
            removeFromQ = q.dequeue
        elif isinstance(q, Stack):
            addToQ = q.push
            removeFromQ = q.pop
        addToQ(root)
        while not q.isEmpty():
            current = removeFromQ()
            #print current
            if display:
                self.display(highlight = [current])
            for n in self.get_children(current):
                addToQ(n)

Response: This function traverses the tree starting from the given root.


Instruction:
Write a Python 3 function that can
add a right child node n to parent.

Response:
def add_right_child(self, n, parent, **attrs):
        '''
        API: add_right_child(self, n, parent, **attrs)
        Description:
            Adds right child n to node parent.
        Pre:
            Right child of parent should not exist.
        Input:
            n: Node name.
            parent: Parent node name.
            attrs: Attributes of node n.
        '''
        if self.get_right_child(parent) is not None:
            msg = "Right child already exists for node " + str(parent)
            raise Exception(msg)
        attrs['direction'] = 'R'
        self.set_node_attr(parent, 'Rchild', n)
        self.add_child(n, parent, **attrs)


Instruction:
Can you tell what is the following Python 3 function doing
def add_left_child(self, n, parent, **attrs):
        '''
        API: add_left_child(self, n, parent, **attrs)
        Description:
            Adds left child n to node parent.
        Pre:
            Left child of parent should not exist.
        Input:
            n: Node name.
            parent: Parent node name.
            attrs: Attributes of node n.
        '''
        if self.get_left_child(parent) is not None:
            msg = "Right child already exists for node " + str(parent)
            raise Exception(msg)
        attrs['direction'] = 'L'
        self.set_node_attr(parent, 'Lchild', n)
        self.add_child(n, parent, **attrs)

Response: Adds a left child node n to parent.


Instruction:
Can you implement a function in Python 3 that
gets the right child of a node n.

Response:
def get_right_child(self, n):
        '''
        API: get_right_child(self, n)
        Description:
            Returns right child of node n. n can be Node() instance or string
            (name of node).
        Pre:
            Node n should be present in the tree.
        Input:
            n: Node name or Node() instance.
        Return:
            Returns name of the right child of n.
        '''
        if isinstance(n, Node):
            return n.get_attr('Rchild')
        return self.get_node_attr(n, 'Rchild')


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_left_child(self, n):
        '''
        API: get_left_child(self, n)
        Description:
            Returns left child of node n. n can be Node() instance or string
            (name of node).
        Pre:
            Node n should be present in the tree.
        Input:
            n: Node name or Node() instance.
        Return:
            Returns name of the left child of n.
        '''
        if isinstance(n, Node):
            return n.get_attr('Lchild')
        return self.get_node_attr(n, 'Lchild')

Response: Get the name of the left child of a node n.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def del_node(self, n):
        '''
        API: del_node(self, n)
        Description:
            Removes node n from tree.
        Pre:
            Node n should be present in the tree.
        Input:
            n: Node name.
        '''
        parent = self.get_node_attr(n, 'parent')
        if self.get_node_attr(n, 'direction') == 'R':
            self.set_node_attr(parent, 'Rchild', None)
        else:
            self.set_node_attr(parent, 'Lchild', None)
        Graph.del_node(self, n)

Response: This method deletes a node from the tree.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def print_nodes(self, order = 'in', priority = 'L', display = None,
                    root = None):
        '''
        API: print_nodes(self, order = 'in', priority = 'L', display = None,
                    root = None)
        Description:
            A recursive function that prints nodes to stdout starting from
            root.
        Input:
            order: Order of printing. Acceptable arguments are 'pre', 'in',
            'post'.
            priority: Priority of printing, acceptable arguments are 'L' and
            'R'.
            display: Display mode.
            root: Starting node.
        '''
        old_display = None
        if root == None:
            root = self.root.name
        if display == None:
            display = self.attr['display']
        else:
            old_display = self.attr['display']
            self.attr['display'] = display
        if priority == 'L':
            first_child = self.get_left_child
            second_child = self.get_right_child
        else:
            first_child = self.get_right_child
            second_child = self.get_left_child
        if order == 'pre':
            print(root)
        if first_child(root) is not None:
            if display:
                self.display(highlight = [root])
            self.print_nodes(order, priority, display, first_child(root))
        if order == 'in':
            print(root)
        if second_child(root) is not None:
            if display:
                self.display(highlight = [root])
            self.print_nodes(order, priority, display, second_child(root))
        if order == 'post':
            print(root)
        if display:
            self.display(highlight = [root])
        if old_display:
            self.attr['display'] = old_display

Response: A recursive function that prints nodes starting from a node.


Instruction:
Can you create a Python 3 function that
adds entry for one YANG module or submodule text.

Response:
def module_entry(yfile):
    """Add entry for one file containing YANG module text.

    Args:
        yfile (file): File containing a YANG module or submodule.
    """
    ytxt = yfile.read()
    mp = ModuleParser(ytxt)
    mst = mp.statement()
    submod = mst.keyword == "submodule"
    import_only = True
    rev = ""
    features = []
    includes = []
    rec = {}
    for sst in mst.substatements:
        if not rev and sst.keyword == "revision":
            rev = sst.argument
        elif import_only and sst.keyword in data_kws:
            import_only = False
        elif sst.keyword == "feature":
            features.append(sst.argument)
        elif submod:
            continue
        elif sst.keyword == "namespace":
            rec["namespace"] = sst.argument
        elif sst.keyword == "include":
            rd = sst.find1("revision-date")
            includes.append((sst.argument, rd.argument if rd else None))
    rec["import-only"] = import_only
    rec["features"] = features
    if submod:
        rec["revision"] = rev
        submodmap[mst.argument] = rec
    else:
        rec["includes"] = includes
        modmap[(mst.argument, rev)] = rec


Instruction:
Can you tell what is the following Python 3 function doing
def nullable(self, ctype: ContentType) -> bool:
        return (not self.check_when() or self.pattern.nullable(ctype))

Response: Override the superclass method.


Instruction:
How would you explain what the following Python 3 function does
def deriv(self, x: str, ctype: ContentType) -> SchemaPattern:
        return (self.pattern.deriv(x, ctype) if self.check_when() else
                NotAllowed())

Response: Return the derivative of the receiver.


Instruction:
Can you generate the documentation for the following Python 3 function
def deriv(self, x: str, ctype: ContentType) -> SchemaPattern:
        return (Empty() if
                self.name == x and self._active(ctype)
                else NotAllowed())

Response: Return the derivative of the receiver.


Instruction:
Given the following Python 3 function, write the documentation
def nullable(self, ctype: ContentType) -> bool:
        return self.left.nullable(ctype) or self.right.nullable(ctype)

Response: Override the superclass method.


Instruction:
Explain what the following Python 3 code does
def deriv(self, x: str, ctype: ContentType) -> SchemaPattern:
        return Alternative.combine(self.left.deriv(x, ctype),
                                   self.right.deriv(x, ctype))

Response: Return the derivative of the receiver.


Instruction:
Given the following Python 3 function, write the documentation
def from_file(cls, name: str, mod_path: Tuple[str] = (".",),
                  description: str = None) -> "DataModel":
        """Initialize the data model from a file with YANG library data.

        Args:
            name: Name of a file with YANG library data.
            mod_path: Tuple of directories where to look for YANG modules.
            description:  Optional description of the data model.

        Returns:
            The data model instance.

        Raises:
            The same exceptions as the class constructor above.
        """
        with open(name, encoding="utf-8") as infile:
            yltxt = infile.read()
        return cls(yltxt, mod_path, description)

Response: Initialize the data model from a YANG library data file.


Instruction:
Create a Python 3 function to
compute unique id of YANG modules comprising the data model.

Response:
def module_set_id(self) -> str:
        """Compute unique id of YANG modules comprising the data model.

        Returns:
            String consisting of hexadecimal digits.
        """
        fnames = sorted(["@".join(m) for m in self.schema_data.modules])
        return hashlib.sha1("".join(fnames).encode("ascii")).hexdigest()


Instruction:
Write a Python 3 function for
creating an instance node from a raw data tree.

Response:
def from_raw(self, robj: RawObject) -> RootNode:
        """Create an instance node from a raw data tree.

        Args:
            robj: Dictionary representing a raw data tree.

        Returns:
            Root instance node.
        """
        cooked = self.schema.from_raw(robj)
        return RootNode(cooked, self.schema, cooked.timestamp)


Instruction:
Write a Python 3 script to
return the schema node addressed by a schema path.

Response:
def get_schema_node(self, path: SchemaPath) -> Optional[SchemaNode]:
        """Return the schema node addressed by a schema path.

        Args:
            path: Schema path.

        Returns:
            Schema node if found in the schema, or ``None``.

        Raises:
            InvalidSchemaPath: If the schema path is invalid.
        """
        return self.schema.get_schema_descendant(
            self.schema_data.path2route(path))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_data_node(self, path: DataPath) -> Optional[DataNode]:
        addr = self.schema_data.path2route(path)
        node = self.schema
        for p in addr:
            node = node.get_data_child(*p)
            if node is None:
                return None
        return node

Response: Return the data node addressed by a data path.


Instruction:
Can you tell what is the following Python 3 function doing
def ascii_tree(self, no_types: bool = False, val_count: bool = False) -> str:
        return self.schema._ascii_tree("", no_types, val_count)

Response: Generate an ASCII art representation of the schema tree.


Instruction:
Can you create a Python 3 function that
generates schema digest (to be used primarily by clients). Returns: Condensed information about the schema in JSON format.

Response:
def schema_digest(self) -> str:
        """Generate schema digest (to be used primarily by clients).

        Returns:
            Condensed information about the schema in JSON format.
        """
        res = self.schema._node_digest()
        res["config"] = True
        return json.dumps(res)


Instruction:
Explain what the following Python 3 code does
def needs_quotes(s):
    # If the name is a reserved keyword it will need quotes but pydot
    # can't tell when it's being used as a keyword or when it's simply
    # a name. Hence the user needs to supply the quotes when an element
    # would use a reserved keyword as name. This function will return
    # false indicating that a keyword string, if provided as-is, won't
    # need quotes.
    if s in DOT_KEYWORDS:
        return False
    chars = [ord(c) for c in s if ord(c)>0x7f or ord(c)==0]
    if chars and not ID_RE_DBL_QUOTED.match(s) and not ID_RE_HTML.match(s):
        return True
    for test_re in [ID_RE_ALPHA_NUMS, ID_RE_NUM, ID_RE_DBL_QUOTED, ID_RE_HTML, ID_RE_ALPHA_NUMS_WITH_PORTS]:
        if test_re.match(s):
            return False
    m = ID_RE_WITH_PORT.match(s)
    if m:
        return needs_quotes(m.group(1)) or needs_quotes(m.group(2))
    return True

Response: Checks whether a string is a dot language ID.


Instruction:
Can you write a function in Python 3 where it
returns string representation of the object in dot language.

Response:
def to_string(self):
        '''
        API: to_string(self)
        Description:
        Returns string representation of node in dot language.
        Return:
            String representation of node.
        '''
        node = list()
        node.append(quote_if_necessary(str(self.name)))
        node.append(' [')
        flag = False
        for a in self.attr:
            flag = True
            node.append(a)
            node.append('=')
            node.append(quote_if_necessary(str(self.attr[a])))
            node.append(', ')
        if flag is True:
            node = node[:-1]
        node.append(']')
        return ''.join(node)


Instruction:
Can you tell what is the following Python 3 function doing
def add_node(self, name, **attr):
        '''
        API: add_node(self, name, **attr)
        Description:
        Adds node to the graph.
        Pre:
            Graph should not contain a node with this name. We do not allow
            multiple nodes with the same name.
        Input:
            name: Name of the node.
            attr: Node attributes.
        Post:
            self.neighbors, self.nodes and self.in_neighbors are updated.
        Return:
            Node (a Node class instance) added to the graph.
        '''
        if name in self.neighbors:
            raise MultipleNodeException
        self.neighbors[name] = list()
        if self.graph_type is DIRECTED_GRAPH:
            self.in_neighbors[name] = list()
        self.nodes[name] = Node(name, **attr)
        return self.nodes[name]

Response: Adds a node to the graph.


Instruction:
Can you write a function in Python 3 where it
adds an edge to the current node and sets edge attributes.

Response:
def add_edge(self, name1, name2, **attr):
        '''
        API: add_edge(self, name1, name2, **attr)
        Description:
        Adds edge to the graph. Sets edge attributes using attr argument.
        Input:
            name1: Name of the source node (if directed).
            name2: Name of the sink node (if directed).
            attr: Edge attributes.
        Pre:
            Graph should not already contain this edge. We do not allow
            multiple edges with same source and sink nodes.
        Post:
            self.edge_attr is updated.
            self.neighbors, self.nodes and self.in_neighbors are updated if
            graph was missing at least one of the nodes.
        '''
        if (name1, name2) in self.edge_attr:
            raise MultipleEdgeException
        if self.graph_type is UNDIRECTED_GRAPH and (name2,name1) in self.edge_attr:
            raise MultipleEdgeException
        self.edge_attr[(name1,name2)] = copy.deepcopy(DEFAULT_EDGE_ATTRIBUTES)
        for a in attr:
            self.edge_attr[(name1,name2)][a] = attr[a]
        if name1 not in self.nodes:
            self.add_node(name1)
        if name2 not in self.nodes:
            self.add_node(name2)
        self.neighbors[name1].append(name2)
        if self.graph_type is UNDIRECTED_GRAPH:
            self.neighbors[name2].append(name1)
        else:
            self.in_neighbors[name2].append(name1)


Instruction:
Can you tell what is the following Python 3 function doing
def del_edge(self, e):
        '''
        API: del_edge(self, e)
        Description:
        Removes edge from graph.
        Input:
            e: Tuple that represents edge, in (source,sink) form.
        Pre:
            Graph should contain this edge.
        Post:
            self.edge_attr, self.neighbors and self.in_neighbors are updated.
        '''
        if self.graph_type is DIRECTED_GRAPH:
            try:
                del self.edge_attr[e]
            except KeyError:
                raise Exception('Edge %s does not exists!' %str(e))
            self.neighbors[e[0]].remove(e[1])
            self.in_neighbors[e[1]].remove(e[0])
        else:
            try:
                del self.edge_attr[e]
            except KeyError:
                try:
                    del self.edge_attr[(e[1],e[0])]
                except KeyError:
                    raise Exception('Edge %s does not exists!' %str(e))
            self.neighbors[e[0]].remove(e[1])
            self.neighbors[e[1]].remove(e[0])

Response: This method deletes an edge from the internal state.


Instruction:
Explain what the following Python 3 code does
def check_edge(self, name1, name2):
        '''
        API: check_edge(self, name1, name2)
        Description:
        Return True if edge exists, False otherwise.
        Input:
            name1: name of the source node.
            name2: name of the sink node.
        Return:
            Returns True if edge exists, False otherwise.
        '''
        if self.graph_type is DIRECTED_GRAPH:
            return (name1, name2) in self.edge_attr
        else:
            return ((name1, name2) in self.edge_attr or
                    (name2, name1) in self.edge_attr)

Response: Check if an edge exists in the current node.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_edge_attr(self, n, m, attr):
        '''
        API: get_edge_attr(self, n, m, attr)
        Description:
        Returns attribute attr of edge (n,m).
        Input:
            n: Source node name.
            m: Sink node name.
            attr: Attribute of edge.
        Pre:
            Graph should have this edge.
        Return:
            Value of edge attribute attr.
        '''
        if self.graph_type is DIRECTED_GRAPH:
            return self.edge_attr[(n,m)][attr]
        else:
            try:
                return self.edge_attr[(n,m)][attr]
            except KeyError:
                return self.edge_attr[(m,n)][attr]

Response: Get the value of an attribute of an edge.


Instruction:
Explain what the following Python 3 code does
def set_node_attr(self, name, attr, value):
        '''
        API: set_node_attr(self, name, attr)
        Description:
        Sets attr attribute of node named name to value.
        Input:
            name: Name of node.
            attr: Attribute of node to set.
        Pre:
            Graph should have this node.
        Post:
            Node attribute will be updated.
        '''
        self.get_node(name).set_attr(attr, value)

Response: Set node attribute of name to value.


Instruction:
Create a Python 3 function to
set edge attribute of a node.

Response:
def set_edge_attr(self, n, m, attr, value):
        '''
        API: set_edge_attr(self, n, m, attr, value)
        Description:
        Sets attr attribute of edge (n,m) to value.
        Input:
            n: Source node name.
            m: Sink node name.
            attr: Attribute of edge to set.
            value: New value of attribute.
        Pre:
            Graph should have this edge.
        Post:
            Edge attribute will be updated.
        '''
        if self.graph_type is DIRECTED_GRAPH:
            self.edge_attr[(n,m)][attr] = value
        else:
            try:
                self.edge_attr[(n,m)][attr] = value
            except KeyError:
                self.edge_attr[(m,n)][attr] = value


Instruction:
Make a summary of the following Python 3 code
def to_string(self):
        '''
        API: to_string(self)
        Description:
        This method is based on pydot Graph class with the same name.
        Returns a string representation of the graph in dot language.
        It will return the graph and all its subelements in string form.
        Return:
            String that represents graph in dot language.
        '''
        graph = list()
        processed_edges = {}
        graph.append('%s %s {\n' %(self.graph_type, self.name))
        for a in self.attr:
            if a not in GRAPH_ATTRIBUTES:
                continue
            val = self.attr[a]
            if val is not None:
                graph.append( '%s=%s' % (a, quote_if_necessary(val)) )
            else:
                graph.append(a)
            graph.append( ';\n' )
        # clusters
        for c in self.cluster:
            graph.append('subgraph cluster_%s {\n' %c)
            for a in self.cluster[c]['attrs']:
                if a=='label':
                    graph.append(a+'='+quote_if_necessary(self.cluster[c]['attrs'][a])+';\n')
                    continue
                graph.append(a+'='+self.cluster[c]['attrs'][a]+';\n')
            if len(self.cluster[c]['node_attrs'])!=0:
                graph.append('node [')
            for a in self.cluster[c]['node_attrs']:
                graph.append(a+'='+self.cluster[c]['node_attrs'][a])
                graph.append(',')
            if len(self.cluster[c]['node_attrs'])!=0:
                graph.pop()
                graph.append('];\n')
            # process cluster nodes
            for n in self.cluster[c]['node_list']:
                data = self.get_node(n).to_string()
                graph.append(data + ';\n')
            # process cluster edges
            for n in self.cluster[c]['node_list']:
                for m in self.cluster[c]['node_list']:
                    if self.check_edge(n,m):
                        data = self.edge_to_string((n,m))
                        graph.append(data + ';\n')
                        processed_edges[(n,m)]=None
            graph.append('}\n')
        # process remaining (non-cluster) nodes
        for n in self.neighbors:
            for c in self.cluster:
                if n in self.cluster[c]['node_list']:
                    break
            else:
                data = self.get_node(n).to_string()
                graph.append(data + ';\n')
        # process edges
        for e in self.edge_attr:
            if e in processed_edges:
                continue
            data = self.edge_to_string(e)
            graph.append(data + ';\n')
        graph.append( '}\n' )
        return ''.join(graph)

Response: This method returns a string representation of the object in dot language. It will return the graph and all its subelements in string form.


Instruction:
How would you explain what the following Python 3 function does
def label_components(self, display = None):
        '''
        API: label_components(self, display=None)
        Description:
        This method labels the nodes of an undirected graph with component
        numbers so that each node has the same label as all nodes in the
        same component. It will display the algortihm if display argument is
        provided.
        Input:
            display: display method.
        Pre:
            self.graph_type should be UNDIRECTED_GRAPH.
        Post:
            Nodes will have 'component' attribute that will have component
            number as value.
        '''
        if self.graph_type == DIRECTED_GRAPH:
            raise Exception("label_components only works for ",
                            "undirected graphs")
        self.num_components = 0
        for n in self.get_node_list():
            self.get_node(n).set_attr('component', None)
        for n in self.neighbors:
            self.get_node(n).set_attr('label', '-')
        for n in self.get_node_list():
            if self.get_node(n).get_attr('component') == None:
                self.search(n, display=display,
                            component=self.num_components, algo='DFS')
                self.num_components += 1

Response: This method labels the nodes of the undirected graph with the same label as all nodes in the undirected graph.


Instruction:
Given the following Python 3 function, write the documentation
def tarjan(self):
        '''
        API: tarjan(self)
        Description:
        Implements Tarjan's algorithm for determining strongly connected set of
        nodes.
        Pre:
            self.graph_type should be DIRECTED_GRAPH.
        Post:
            Nodes will have 'component' attribute that will have component
            number as value. Changes 'index' attribute of nodes.
        '''
        index = 0
        component = 0
        q = []
        for n in self.get_node_list():
            if self.get_node_attr(n, 'index') is None:
                index, component = self.strong_connect(q, n, index, component)

Response: This method is used to determine strongly connected set of nodes.


Instruction:
Can you tell what is the following Python 3 function doing
def strong_connect(self, q, node, index, component):
        '''
        API: strong_connect (self, q, node, index, component)
        Description:
        Used by tarjan method. This method should not be called directly by
        user.
        Input:
            q: Node list.
            node: Node that is being connected to nodes in q.
            index: Index used by tarjan method.
            component: Current component number.
        Pre:
            Should be called by tarjan and itself (recursive) only.
        Post:
            Nodes will have 'component' attribute that will have component
            number as value. Changes 'index' attribute of nodes.
        Return:
            Returns new index and component numbers.
        '''
        self.set_node_attr(node, 'index', index)
        self.set_node_attr(node, 'lowlink', index)
        index += 1
        q.append(node)
        for m in self.get_neighbors(node):
            if self.get_node_attr(m, 'index') is None:
                index, component = self.strong_connect(q, m, index, component)
                self.set_node_attr(node, 'lowlink',
                                   min([self.get_node_attr(node, 'lowlink'),
                                        self.get_node_attr(m, 'lowlink')]))
            elif m in q:
                self.set_node_attr(node, 'lowlink',
                                   min([self.get_node_attr(node, 'lowlink'),
                                        self.get_node_attr(m, 'index')]))
        if self.get_node_attr(node, 'lowlink') == self.get_node_attr(node, 'index'):
            m = q.pop()
            self.set_node_attr(m, 'component', component)
            while (node!=m):
                m = q.pop()
                self.set_node_attr(m, 'component', component)
            component += 1
            self.num_components = component

        return (index, component)

Response: This method will strongly connect a node to a set of nodes.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def dfs(self, root, disc_count = 0, finish_count = 1, component = None,
            transpose = False, display = None, pred = None):
        '''
        API: dfs(self, root, disc_count = 0, finish_count = 1, component=None,
            transpose=False)
        Description:
        Make a depth-first search starting from node with name root.
        Input:
            root: Starting node name.
            disc_count: Discovery time.
            finish_count: Finishing time.
            component: component number.
            transpose: Goes in the reverse direction along edges if transpose
            is True.
        Post:
            Nodes will have 'component' attribute that will have component
            number as value. Updates 'disc_time' and 'finish_time' attributes
            of nodes which represents discovery time and finishing time.
        Return:
            Returns a tuple that has discovery time and finish time of the
            last node in the following form (disc_time,finish_time).
        '''
        if pred == None:
            pred = {}
        if display == None:
            display = self.attr['display']
        else:
            self.set_display_mode(display)
        neighbors = self.neighbors
        if self.graph_type == DIRECTED_GRAPH and transpose:
            neighbors = self.in_neighbors
        self.get_node(root).set_attr('component', component)
        disc_count += 1
        self.get_node(root).set_attr('disc_time', disc_count)
        self.get_node(root).set_attr('label', str(disc_count)+',-')
        self.get_node(root).set_attr('color', 'blue')
        if root in pred:
            self.set_edge_attr(pred[root], root, 'color', 'green')
        self.display()
        if transpose:
            fTime = []
            for n in neighbors[root]:
                fTime.append((n,self.get_node(n).get_attr('finish_time')))
            neighbor_list = sorted(fTime, key=operator.itemgetter(1))
            neighbor_list = list(t[0] for t in neighbor_list)
            neighbor_list.reverse()
        else:
            neighbor_list = neighbors[root]
        for i in neighbor_list:
            if not transpose:
                if self.get_node(i).get_attr('disc_time') is None:
                    pred[i] = root
                    disc_count, finish_count = self.dfs(i, disc_count,
                                                        finish_count,
                                                        component, transpose,
                                                        pred = pred)
            else:
                if self.get_node(i).get_attr('component') is None:
                    disc_count, finish_count = self.dfs(i, disc_count,
                                                        finish_count,
                                                        component, transpose,
                                                        pred = pred)
        self.get_node(root).set_attr('finish_time', finish_count)
        d_time = self.get_node(root).get_attr('disc_time')
        label = '"' + str(d_time) + ',' + str(finish_count) + '"'
        self.get_node(root).set_attr('label', label)
        self.get_node(root).set_attr('color', 'green')
        self.display()
        finish_count += 1
        return disc_count, finish_count

Response: This function returns a depth - first search of the tree with the given root name.


Instruction:
Can you tell what is the following Python 3 function doing
def search(self, source, destination = None, display = None,
               component = None, q = None,
               algo = 'DFS', reverse = False, **kargs):
        '''
        API: search(self, source, destination = None, display = None,
               component = None, q = Stack(),
               algo = 'DFS', reverse = False, **kargs)
        Description:
        Generic search method. Changes behavior (dfs,bfs,dijkstra,prim)
        according to algo argument.
        if destination is not specified:
           This method determines all nodes reachable from "source" ie. creates
           precedence tree and returns it (dictionary).
        if destionation is given:
           If there exists a path from "source" to "destination" it will return
           list of the nodes is this path. If there is no such path, it will
           return the precedence tree constructed from source (dictionary).
        Optionally, it marks all nodes reachable from "source" with a component
        number. The variable "q" determines the order in which the nodes are
        searched.
        Input:
            source: Search starts from node with this name.
            destination: Destination node name.
            display: Display method.
            algo: Algortihm that specifies search. Available algortihms are
            'DFS', 'BFS', 'Dijkstra' and 'Prim'.
            reverse: Search goes in reverse arc directions if True.
            kargs: Additional keyword arguments.
        Post:
            Nodes will have 'component' attribute that will have component
            number as value (if component argument provided). Color attribute
            of nodes and edges may change.
        Return:
            Returns predecessor tree in dictionary form if destination is
            not specified, returns list of node names in the path from source
            to destionation if destionation is specified and there is a path.
            If there is no path returns predecessor tree in dictionary form.
            See description section.
        '''
        if display == None:
            display = self.attr['display']
        else:
            self.set_display_mode(display)
        if algo == 'DFS':
            if q is None:
                q = Stack()
            self.get_node(source).set_attr('component', component)
        elif algo == 'BFS' or algo == 'UnweightedSPT':
            if q is None:
                q = Queue()
            self.get_node(source).set_attr('component', component)
        elif algo == 'Dijkstra' or algo == 'Prim':
            if q is None:
                q = PriorityQueue()
        else:
            print("Unknown search algorithm...exiting")
            return
        neighbors = self.neighbors
        if self.graph_type == DIRECTED_GRAPH and reverse:
            neighbors = self.in_neighbors
        for i in self.get_node_list():
            self.get_node(i).set_attr('label', '-')
            self.get_node(i).attr.pop('priority', None)
            self.get_node(i).set_attr('distance', None)
            self.get_node(i).set_attr('color', 'black')
            for j in neighbors[i]:
                if reverse:
                    self.set_edge_attr(j, i, 'color', 'black')
                else:
                    self.set_edge_attr(i, j, 'color', 'black')
        self.display()
        pred = {}
        self.process_edge_search(None, source, pred, q, component, algo,
                                 **kargs)
        found = True
        if source != destination:
            found = False
        while not q.isEmpty() and not found:
            current = q.peek()
            if self.get_node(current).get_attr('color') == 'green':
                q.remove(current)
                continue
            self.process_node_search(current, q, **kargs)
            self.get_node(current).set_attr('color', 'blue')
            if current != source:
                if reverse:
                    self.set_edge_attr(current, pred[current], 'color', 'green')
                else:
                    self.set_edge_attr(pred[current], current, 'color', 'green')
            if current == destination:
                found = True
                break
            self.display()
            for n in neighbors[current]:
                if self.get_node(n).get_attr('color') != 'green':
                    if reverse:
                        self.set_edge_attr(n, current, 'color', 'yellow')
                    else:
                        self.set_edge_attr(current, n, 'color', 'yellow')
                    self.display()
                    self.process_edge_search(current, n, pred, q, component,
                                             algo, **kargs)
                    if reverse:
                        self.set_edge_attr(n, current, 'color', 'black')
                    else:
                        self.set_edge_attr(current, n, 'color', 'black')
            q.remove(current)
            self.get_node(current).set_attr('color', 'green')
            self.display()
        if found:
            path = [destination]
            current = destination
            while current != source:
                path.insert(0, pred[current])
                current = pred[current]
            return path
        if destination == None:
            return pred
        else:
            return None

Response: Search for a node in a node tree.


Instruction:
Make a summary of the following Python 3 code
def minimum_spanning_tree_prim(self, source, display = None,
                                   q = PriorityQueue()):
        '''
        API: minimum_spanning_tree_prim(self, source, display = None,
                                        q = PriorityQueue())
        Description:
        Determines a minimum spanning tree of all nodes reachable
        from source using Prim's Algorithm.
        Input:
            source: Name of source node.
            display: Display method.
            q: Data structure that holds nodes to be processed in a queue.
        Post:
            'color', 'distance', 'component' attribute of nodes and edges may
            change.
        Return:
            Returns predecessor tree in dictionary format.
        '''
        if display == None:
            display = self.attr['display']
        else:
            self.set_display_mode(display)
        if isinstance(q, PriorityQueue):
            addToQ = q.push
            removeFromQ = q.pop
            peek = q.peek
            isEmpty = q.isEmpty
        neighbors = self.get_neighbors
        pred = {}
        addToQ(source)
        done = False
        while not isEmpty() and not done:
            current = removeFromQ()
            self.set_node_attr(current, 'color', 'blue')
            if current != source:
                self.set_edge_attr(pred[current], current, 'color', 'green')
            self.display()
            for n in neighbors(current):
                if self.get_node_attr(n, 'color') != 'green':
                    self.set_edge_attr(current, n, 'color', 'yellow')
                    self.display()
                    new_estimate = self.get_edge_attr(current, n, 'cost')
                    if not n in pred or new_estimate < peek(n)[0]:
                        pred[n] = current
                        self.set_node_attr(n, 'color', 'red')
                        self.set_node_attr(n, 'label', new_estimate)
                        addToQ(n, new_estimate)
                        self.display()
                        self.set_node_attr(n, 'color', 'black')
                    self.set_edge_attr(current, n, 'color', 'black')
            self.set_node_attr(current, 'color', 'green')
            self.display()
        return pred

Response: This method returns a minimum spanning tree of all nodes reachable from source using Prim s Algorithm.


Instruction:
Given the following Python 3 function, write the documentation
def minimum_spanning_tree_kruskal(self, display = None, components = None):
        '''
        API: minimum_spanning_tree_kruskal(self, display = None,
                                           components = None)
        Description:
        Determines a minimum spanning tree using Kruskal's Algorithm.
        Input:
            display: Display method.
            component: component number.
        Post:
            'color' attribute of nodes and edges may change.
        Return:
            Returns list of edges where edges are tuples in (source,sink)
            format.
        '''
        if display == None:
            display = self.attr['display']
        else:
            self.set_display_mode(display)
        if components is None:
            components = DisjointSet(display = display, layout = 'dot',
                                     optimize = False)
        sorted_edge_list = sorted(self.get_edge_list(), key=self.get_edge_cost)
        edges = []
        for n in self.get_node_list():
            components.add([n])
        components.display()
        for e in sorted_edge_list:
            if len(edges) == len(self.get_node_list()) - 1:
                break
            self.set_edge_attr(e[0], e[1], 'color', 'yellow')
            self.display()
            if components.union(e[0], e[1]):
                self.set_edge_attr(e[0], e[1], 'color', 'green')
                self.display()
                edges.append(e)
            else:
                self.set_edge_attr(e[0], e[1], 'color', 'black')
                self.display()
            components.display()
        return edges

Response: This method returns a list of edges where edges are tuples of source and sink nodes.


Instruction:
Given the following Python 3 function, write the documentation
def relabel(self, i):
        '''
        API: relabel(self, i)
        Description:
        Used by max_flow_preflowpush() method for relabelling node i.
        Input:
            i: Node that is being relabelled.
        Post:
            'distance' attribute of node i is updated.
        '''
        min_distance = 2*len(self.get_node_list()) + 1
        for j in self.get_neighbors(i):
            if (self.get_node_attr(j, 'distance') < min_distance and
                (self.get_edge_attr(i, j, 'flow') <
                 self.get_edge_attr(i, j, 'capacity'))):
                min_distance = self.get_node_attr(j, 'distance')
        for j in self.get_in_neighbors(i):
            if (self.get_node_attr(j, 'distance') < min_distance and
                self.get_edge_attr(j, i, 'flow') > 0):
                min_distance = self.get_node_attr(j, 'distance')
        self.set_node_attr(i, 'distance', min_distance + 1)

Response: This method relabels the node i to the flow of the node i.


Instruction:
Explain what the following Python 3 code does
def show_flow(self):
        '''
        API: relabel(self, i)
        Description:
        Used by max_flow_preflowpush() method for display purposed.
        Post:
            'color' and 'label' attribute of edges/nodes are updated.
        '''
        for n in self.get_node_list():
            excess = self.get_node_attr(n, 'excess')
            distance = self.get_node_attr(n, 'distance')
            self.set_node_attr(n, 'label', str(excess)+'/'+str(distance))
            for neighbor in self.get_neighbors(n):
                capacity = self.get_edge_attr(n, neighbor, 'capacity')
                flow = self.get_edge_attr(n, neighbor, 'flow')
                if capacity == INF:
                    self.set_edge_attr(n, neighbor, 'label',
                                       'INF'+'/'+str(flow))
                else:
                    self.set_edge_attr(n, neighbor, 'label',
                                       str(capacity)+'/'+str(flow))
                if capacity == flow:
                    self.set_edge_attr(n, neighbor, 'color', 'red')
                elif flow > 0:
                    self.set_edge_attr(n, neighbor, 'color', 'green')
                else:
                    self.set_edge_attr(n, neighbor, 'color', 'black')
        self.display()

Response: This method shows the flow of the current node.


Instruction:
How would you implement a function in Python 3 that
creates and return a residual graph for the current node.

Response:
def create_residual_graph(self):
        '''
        API: create_residual_graph(self)
        Description:
        Creates and returns residual graph, which is a Graph instance
        itself.
        Pre:
            (1) Arcs should have 'flow', 'capacity' and 'cost' attribute
            (2) Graph should be a directed graph
        Return:
            Returns residual graph, which is a Graph instance.
        '''
        if self.graph_type is UNDIRECTED_GRAPH:
            raise Exception('residual graph is defined for directed graphs.')
        residual_g = Graph(type = DIRECTED_GRAPH)
        for e in self.get_edge_list():
            capacity_e = self.get_edge_attr(e[0], e[1], 'capacity')
            flow_e = self.get_edge_attr(e[0], e[1], 'flow')
            cost_e = self.get_edge_attr(e[0], e[1], 'cost')
            if flow_e > 0:
                residual_g.add_edge(e[1], e[0], cost=-1*cost_e,
                                    capacity=flow_e)
            if capacity_e - flow_e > 0:
                residual_g.add_edge(e[0], e[1], cost=cost_e,
                                    capacity=capacity_e-flow_e)
        return residual_g


Instruction:
Make a summary of the following Python 3 code
def find_feasible_flow(self):
        '''
        API:
            find_feasible_flow(self)
        Description:
            Solves feasible flow problem, stores solution in 'flow' attribute
            or arcs. This method is used to get an initial feasible flow for
            simplex and cycle canceling algorithms. Uses max_flow() method.
            Other max flow methods can also be used. Returns True if a feasible
            flow is found, returns False, if the problem is infeasible. When
            the problem is infeasible 'flow' attributes of arcs should be
            considered as junk.
        Pre:
            (1) 'capacity' attribute of arcs
            (2) 'demand' attribute of nodes
        Post:
            Keeps solution in 'flow' attribute of arcs.
        Return:
            Returns True if a feasible flow is found, returns False, if the
            problem is infeasible
        '''
        # establish a feasible flow in the network, to do this add nodes s and
        # t and solve a max flow problem.
        nl = self.get_node_list()
        for i in nl:
            b_i = self.get_node(i).get_attr('demand')
            if b_i > 0:
                # i is a supply node, add (s,i) arc
                self.add_edge('s', i, capacity=b_i)
            elif b_i < 0:
                # i is a demand node, add (i,t) arc
                self.add_edge(i, 't', capacity=-1*b_i)
        # solve max flow on this modified graph
        self.max_flow('s', 't', 'off')
        # check if all demand is satisfied, i.e. the min cost problem is
        # feasible or not
        for i in self.neighbors['s']:
            flow = self.get_edge_attr('s', i, 'flow')
            capacity = self.get_edge_attr('s', i, 'capacity')
            if flow != capacity:
                self.del_node('s')
                self.del_node('t')
                return False
        # remove node 's' and node 't'
        self.del_node('s')
        self.del_node('t')
        return True

Response: This method finds a feasible flow in the modified graph and returns True if it is feasible False otherwise.


Instruction:
How would you code a function in Python 3 to
write the current object to disk using the specified layout and format.

Response:
def write(self, basename = 'graph', layout = None, format='png'):
        '''
        API:
            write(self, basename = 'graph', layout = None, format='png')
        Description:
        Writes graph to dist using layout and format.
        Input:
            basename: name of the file that will be written.
            layout: Dot layout for generating graph image.
            format: Image format, all format supported by Dot are wellcome.
        Post:
            File will be written to disk.
        '''
        if layout == None:
            layout = self.get_layout()
        f = open(basename, "w+b")
        if format == 'dot':
            f.write(self.to_string())
        else:
            f.write(self.create(layout, format))
        f.close()


Instruction:
Explain what the following Python 3 code does
def create(self, layout, format, **args):
        '''
        API:
            create(self, layout, format, **args)
        Description:
            Returns postscript representation of graph.
        Input:
            layout: Dot layout for generating graph image.
            format: Image format, all format supported by Dot are wellcome.
        Return:
            Returns postscript representation of graph.
        '''
        tmp_fd, tmp_name = tempfile.mkstemp()
        tmp_file = os.fdopen(tmp_fd, 'w')
        tmp_file.write(self.to_string())
        # ne need for os.close(tmp_fd), since we have tmp_file.close(tmp_file)
        tmp_file.close()
        tmp_dir = os.path.dirname(tmp_name)
        try:
            p = subprocess.Popen([layout, '-T'+format, tmp_name],
                                 cwd=tmp_dir,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
        except OSError:
            print('''Graphviz executable not found.
Graphviz must be installed and in your search path.
Please visit http://www.graphviz.org/ for information on installation.
After installation, ensure that the PATH variable is properly set.''')
            return
        stdout_output, stderr_output = p.communicate()
        if p.returncode != 0 :
            raise Exception('Graphviz executable terminated with status: %d. stderr follows: %s' % (
                    p.returncode, stderr_output))
        elif stderr_output:
            print(stderr_output)
        return stdout_output

Response: A method to create a new node in Graphviz.


Instruction:
How would you implement a function in Python 3 that
displays the graph according to the arguments provided.

Response:
def display(self, highlight = None, basename = 'graph', format = 'png',
                pause = True):
        '''
        API:
            display(self, highlight = None, basename = 'graph', format = 'png',
                pause = True)
        Description:
            Displays graph according to the arguments provided.
            Current display modes: 'off', 'file', 'pygame', 'PIL', 'xdot',
            'svg'
            Current layout modes: Layouts provided by graphviz ('dot', 'fdp',
            'circo', etc.) and 'dot2tex'.
            Current formats: Formats provided by graphviz ('ps', 'pdf', 'png',
            etc.)
        Input:
            highlight: List of nodes to be highlighted.
            basename: File name. It will be used if display mode is 'file'.
            format: Image format, all format supported by Dot are wellcome.
            pause: If display is 'pygame' and pause is True pygame will pause
            and wait for user input before closing the display. It will close
            display window straightaway otherwise.
        Post:
            A display window will pop up or a file will be written depending
            on display mode.
        '''
        if self.attr['display'] == 'off':
            return
        if highlight != None:
            for n in highlight:
                if not isinstance(n, Node):
                    n = self.get_node(n)
                n.set_attr('color', 'red')
        if self.get_layout() == 'dot2tex':
            if self.attr['display'] != 'file':
                self.attr['display'] = 'file'
                print("Warning: Dot2tex layout can only be used with display mode 'file'")
                print("         Automatically changing setting")
        if self.attr['display'] == 'file':
            if self.get_layout() == 'dot2tex':
                try:
                    if DOT2TEX_INSTALLED:
                        if format != 'pdf' or format != 'ps':
                            print("Dot2tex only supports pdf and ps formats, falling back to pdf")
                            format = 'pdf'
                        self.set_layout('dot')
                        tex = dot2tex.dot2tex(self.to_string(), autosize=True, texmode = 'math', template = DOT2TEX_TEMPLATE)
                    else:
                        print("Error: Dot2tex not installed.")
                except:
                    try:
                        self.set_layout('dot')
                        self.write(basename+'.dot', self.get_layout(), 'dot')
                        sp = subprocess.Popen('dot2tex -t math ' + basename + '.dot', stdout = subprocess.PIPE,
                                              stderr = subprocess.STDOUT)
                        tex = sp.communicate()[0]
                    except:
                        print("There was an error running dot2tex.")
                f = open(basename+'.tex', 'w')
                f.write(tex)
                f.close()
                try:
                    subprocess.call(['latex', basename])
                    if format == 'ps':
                        subprocess.call(['dvips', basename])
                    elif format == 'pdf':
                        subprocess.call(['pdflatex', basename])
                    self.set_layout('dot2tex')
                except:
                    print("There was an error runing latex. Is it installed?")
            else:
                self.write(basename+'.'+format, self.get_layout(), format)
            return
        elif self.attr['display'] == 'pygame':
            output = self.create(self.get_layout(), format)
            if output is not None:
                im = io.StringIO(self.create(self.get_layout(), format))
                picture = pygame.image.load(im, format)
                screen = pygame.display.set_mode(picture.get_size())
                screen.blit(picture, picture.get_rect())
                pygame.display.flip()
                while pause:
                    e = pygame.event.poll()
                    if e.type == pygame.KEYDOWN:
                        break
                    if e.type == pygame.QUIT:
                        pause = False
                        pygame.display.quit()
                        # sys.exit() exits the whole program and I (aykut) guess it is
                        # not appropriate here.
                        #sys.exit()
            else:
                print('Error in displaying graph. Display disabled')
                self.set_display_mode('off')
        elif self.attr['display'] == 'PIL':
            im = io.StringIO(self.create(self.get_layout(), format))
            if PIL_INSTALLED:
                im2 = PIL_Image.open(im)
                im2.show()
            else:
                print('Error: PIL not installed. Display disabled.')
                self.attr['display'] = 'off'
        elif self.attr['display'] == 'xdot':
            if XDOT_INSTALLED:
                window = xdot.DotWindow()
                window.set_dotcode(self.to_string())
                window.connect('destroy', gtk.main_quit)
                gtk.main()
            else:
                print('Error: xdot not installed. Display disabled.')
                self.attr['display'] = 'off'
        elif self.attr['display'] == 'svg':
            if not ETREE_INSTALLED:
                print('Error: etree not installed (display mode: svg). Display disabled.')
                self.attr['display'] = 'off'
        else:
            print("Unknown display mode: ", end=' ')
            print(self.attr['display'])
        if highlight != None:
            for n in highlight:
                if not isinstance(n, Node):
                    n = self.get_node(n)
                n.set_attr('color', 'black')


Instruction:
Here you have a function in Python 3, explain what it does
def max_flow(self, source, sink, display = None, algo = 'DFS'):
        '''
        API: max_flow(self, source, sink, display=None)
        Description:
        Finds maximum flow from source to sink by a depth-first search based
        augmenting path algorithm.
        Pre:
            Assumes a directed graph in which each arc has a 'capacity'
            attribute and for which there does does not exist both arcs (i,j)
            and (j, i) for any pair of nodes i and j.
        Input:
            source: Source node name.
            sink: Sink node name.
            display: Display mode.
        Post:
            The 'flow" attribute of each arc gives a maximum flow.
        '''
        if display is not None:
            old_display =  self.attr['display']
            self.attr['display'] = display
        nl = self.get_node_list()
        # set flow of all edges to 0
        for e in self.edge_attr:
            self.edge_attr[e]['flow'] = 0
            if 'capacity' in self.edge_attr[e]:
                capacity = self.edge_attr[e]['capacity']
                self.edge_attr[e]['label'] = str(capacity)+'/0'
            else:
                self.edge_attr[e]['capacity'] = INF
                self.edge_attr[e]['label'] = 'INF/0'
        while True:
            # find an augmenting path from source to sink using DFS
            if algo == 'DFS':
                q = Stack()
            elif algo == 'BFS':
                q = Queue()
            q.push(source)
            pred = {source:None}
            explored = [source]
            for n in nl:
                self.get_node(n).set_attr('color', 'black')
            for e in self.edge_attr:
                if self.edge_attr[e]['flow'] == 0:
                    self.edge_attr[e]['color'] = 'black'
                elif self.edge_attr[e]['flow']==self.edge_attr[e]['capacity']:
                    self.edge_attr[e]['color'] = 'red'
                else:
                    self.edge_attr[e]['color'] = 'green'
            self.display()
            while not q.isEmpty():
                current = q.peek()
                q.remove(current)
                if current == sink:
                    break
                out_neighbor = self.neighbors[current]
                in_neighbor = self.in_neighbors[current]
                neighbor = out_neighbor+in_neighbor
                for m in neighbor:
                    if m in explored:
                        continue
                    self.get_node(m).set_attr('color', 'yellow')
                    if m in out_neighbor:
                        self.set_edge_attr(current, m, 'color', 'yellow')
                        available_capacity = (
                            self.get_edge_attr(current, m, 'capacity')-
                            self.get_edge_attr(current, m, 'flow'))
                    else:
                        self.set_edge_attr(m, current, 'color', 'yellow')
                        available_capacity=self.get_edge_attr(m, current, 'flow')
                    self.display()
                    if available_capacity > 0:
                        self.get_node(m).set_attr('color', 'blue')
                        if m in out_neighbor:
                            self.set_edge_attr(current, m, 'color', 'blue')
                        else:
                            self.set_edge_attr(m, current, 'color', 'blue')
                        explored.append(m)
                        pred[m] = current
                        q.push(m)
                    else:
                        self.get_node(m).set_attr('color', 'black')
                        if m in out_neighbor:
                            if (self.get_edge_attr(current, m, 'flow') ==
                                self.get_edge_attr(current, m, 'capacity')):
                                self.set_edge_attr(current, m, 'color', 'red')
                            elif self.get_edge_attr(current, m, 'flow') == 0:
                                self.set_edge_attr(current, m, 'color', 'black')
                            #else:
                            #    self.set_edge_attr(current, m, 'color', 'green')
                        else:
                            if (self.get_edge_attr(m, current, 'flow') ==
                                self.get_edge_attr(m, current, 'capacity')):
                                self.set_edge_attr(m, current, 'color', 'red')
                            elif self.get_edge_attr(m, current, 'flow') == 0:
                                self.set_edge_attr(m, current, 'color', 'black')
                            #else:
                            #    self.set_edge_attr(m, current, 'color', 'green')
                    self.display()
            # if no path with positive capacity from source sink exists, stop
            if sink not in pred:
                break
            # find capacity of the path
            current = sink
            min_capacity = 'infinite'
            while True:
                m = pred[current]
                if (m,current) in self.edge_attr:
                    arc_capacity = self.edge_attr[(m, current)]['capacity']
                    flow = self.edge_attr[(m, current)]['flow']
                    potential = arc_capacity-flow
                    if min_capacity == 'infinite':
                        min_capacity = potential
                    elif min_capacity > potential:
                        min_capacity = potential
                else:
                    potential = self.edge_attr[(current, m)]['flow']
                    if min_capacity == 'infinite':
                        min_capacity = potential
                    elif min_capacity > potential:
                        min_capacity = potential
                if m == source:
                    break
                current = m
            # update flows on the path
            current = sink
            while True:
                m = pred[current]
                if (m, current) in self.edge_attr:
                    flow = self.edge_attr[(m, current)]['flow']
                    capacity = self.edge_attr[(m, current)]['capacity']
                    new_flow = flow+min_capacity
                    self.edge_attr[(m, current)]['flow'] = new_flow
                    if capacity == INF:
                        self.edge_attr[(m, current)]['label'] = \
                            'INF' + '/'+str(new_flow)
                    else:
                        self.edge_attr[(m, current)]['label'] = \
                            str(capacity)+'/'+str(new_flow)
                    if new_flow==capacity:
                        self.edge_attr[(m, current)]['color'] = 'red'
                    else:
                        self.edge_attr[(m, current)]['color'] = 'green'
                    self.display()
                else:
                    flow = self.edge_attr[(current, m)]['flow']
                    capacity = self.edge_attr[(current, m)]['capacity']
                    new_flow = flow-min_capacity
                    self.edge_attr[(current, m)]['flow'] = new_flow
                    if capacity == INF:
                        self.edge_attr[(current, m)]['label'] = \
                            'INF' + '/'+str(new_flow)
                    else:
                        self.edge_attr[(current, m)]['label'] = \
                            str(capacity)+'/'+str(new_flow)
                    if new_flow==0:
                        self.edge_attr[(current, m)]['color'] = 'red'
                    else:
                        self.edge_attr[(current, m)]['color'] = 'green'
                    self.display()
                if m == source:
                    break
                current = m
        if display is not None:
            self.attr['display'] = old_display

Response: This method finds the maximum flow from source to sink using a depth - first search based on the edge attributes.


Instruction:
Can you tell what is the following Python 3 function doing
def get_negative_cycle(self):
        '''
        API:
            get_negative_cycle(self)
        Description:
            Finds and returns negative cost cycle using 'cost' attribute of
            arcs. Return value is a list of nodes representing cycle it is in
            the following form; n_1-n_2-...-n_k, when the cycle has k nodes.
        Pre:
            Arcs should have 'cost' attribute.
        Return:
            Returns a list of nodes in the cycle if a negative cycle exists,
            returns None otherwise.
        '''
        nl = self.get_node_list()
        i = nl[0]
        (valid, distance, nextn) = self.floyd_warshall()
        if not valid:
            cycle = self.floyd_warshall_get_cycle(distance, nextn)
            return cycle
        else:
            return None

Response: Returns a list of nodes in the cycle if a negative cycle exists returns None otherwise.


Instruction:
How would you explain what the following Python 3 function does
def floyd_warshall_get_path(self, distance, nextn, i, j):
        '''
        API:
            floyd_warshall_get_path(self, distance, nextn, i, j):
        Description:
            Finds shortest path between i and j using distance and nextn
            dictionaries.
        Pre:
            (1) distance and nextn are outputs of floyd_warshall method.
            (2) The graph does not have a negative cycle, , ie.
            distance[(i,i)] >=0 for all node i.
        Return:
            Returns the list of nodes on the path from i to j, ie. [i,...,j]
        '''
        if distance[(i,j)]=='infinity':
            return None
        k = nextn[(i,j)]
        path = self.floyd_warshall_get_path
        if i==k:
            return [i, j]
        else:
            return path(distance, nextn, i,k) + [k] + path(distance, nextn, k,j)

Response: This method returns the shortest path between i and j using distance and nextn dictionaries.


Instruction:
Make a summary of the following Python 3 code
def floyd_warshall_get_cycle(self, distance, nextn, element = None):
        '''
        API:
            floyd_warshall_get_cycle(self, distance, nextn, element = None)
        Description:
            Finds a negative cycle in the graph.
        Pre:
            (1) distance and nextn are outputs of floyd_warshall method.
            (2) The graph should have a negative cycle, , ie.
            distance[(i,i)] < 0 for some node i.
        Return:
            Returns the list of nodes on the cycle. Ex: [i,j,k,...,r], where
            (i,j), (j,k) and (r,i) are some edges in the cycle.
        '''
        nl = self.get_node_list()
        if element is None:
            for i in nl:
                if distance[(i,i)] < 0:
                    # graph has a cycle on the path from i to i.
                    element = i
                    break
            else:
                raise Exception('Graph does not have a negative cycle!')
        elif distance[(element,element)] >= 0:
            raise Exception('Graph does not have a negative cycle that contains node '+str(element)+'!')
        # find the cycle on the path from i to i.
        cycle = [element]
        k = nextn[(element,element)]
        while k not in cycle:
            cycle.insert(1,k)
            k = nextn[(element,k)]
        if k==element:
            return cycle
        else:
            return self.floyd_warshall_get_cycle(distance, nextn, k)

Response: This method returns a list of nodes on the cycle that are at a given distance from the next node.


Instruction:
Explain what the following Python 3 code does
def find_cycle_capacity(self, cycle):
        '''
        API:
            find_cycle_capacity(self, cycle):
        Description:
            Finds capacity of the cycle input.
        Pre:
            (1) Arcs should have 'capacity' attribute.
        Input:
            cycle: a list representing a cycle
        Return:
            Returns an integer number representing capacity of cycle.
        '''
        index = 0
        k = len(cycle)
        capacity = self.get_edge_attr(cycle[k-1], cycle[0], 'capacity')
        while index<(k-1):
            i = cycle[index]
            j = cycle[index+1]
            capacity_ij = self.get_edge_attr(i, j, 'capacity')
            if capacity > capacity_ij:
                capacity = capacity_ij
            index += 1
        return capacity

Response: This function finds the capacity of a cycle.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def label_correcting_check_cycle(self, j, pred):
        '''
        API:
            label_correcting_check_cycle(self, j, pred)
        Description:
            Checks if predecessor dictionary has a cycle, j represents the node
            that predecessor is recently updated.
        Pre:
            (1) predecessor of source node should be None.
        Input:
            j: node that predecessor is recently updated.
            pred: predecessor dictionary
        Return:
            If there exists a cycle, returns the list that represents the
            cycle, otherwise it returns to None.
        '''
        labelled = {}
        for n in self.neighbors:
            labelled[n] = None
        current = j
        while current != None:
            if labelled[current]==j:
                cycle = self.label_correcting_get_cycle(j, pred)
                return cycle
            labelled[current] = j
            current = pred[current]
        return None

Response: This function label_correcting_check_cycle returns the list of cycles that are in the predecessor dictionary j.


Instruction:
Explain what the following Python 3 code does
def augment_cycle(self, amount, cycle):
        '''
        API:
            augment_cycle(self, amount, cycle):
        Description:
            Augments 'amount' unit of flow along cycle.
        Pre:
            Arcs should have 'flow' attribute.
        Inputs:
            amount: An integer representing the amount to augment
            cycle: A list representing a cycle
        Post:
            Changes 'flow' attributes of arcs.
        '''
        index = 0
        k = len(cycle)
        while index<(k-1):
            i = cycle[index]
            j = cycle[index+1]
            if (i,j) in self.edge_attr:
                flow_ij = self.edge_attr[(i,j)]['flow']
                self.edge_attr[(i,j)]['flow'] = flow_ij+amount
            else:
                flow_ji = self.edge_attr[(j,i)]['flow']
                self.edge_attr[(j,i)]['flow'] = flow_ji-amount
            index += 1
        i = cycle[k-1]
        j = cycle[0]
        if (i,j) in self.edge_attr:
            flow_ij = self.edge_attr[(i,j)]['flow']
            self.edge_attr[(i,j)]['flow'] = flow_ij+amount
        else:
            flow_ji = self.edge_attr[(j,i)]['flow']
            self.edge_attr[(j,i)]['flow'] = flow_ji-amount

Response: Augment the amount of flow along a cycle.


Instruction:
Can you generate the documentation for the following Python 3 function
def network_simplex(self, display, pivot, root):
        '''
        API:
            network_simplex(self, display, pivot, root)
        Description:
            Solves minimum cost feasible flow problem using network simplex
            algorithm. It is recommended to use min_cost_flow(algo='simplex')
            instead of using network_simplex() directly. Returns True when an
            optimal solution is found, returns False otherwise. 'flow' attribute
            values of arcs should be considered as junk when returned False.
        Pre:
            (1) check Pre section of min_cost_flow()
        Input:
            pivot: specifies pivot rule. Check min_cost_flow()
            display: 'off' for no display, 'pygame' for live update of
            spanning tree.
            root: Root node for the underlying spanning trees that will be
            generated by network simplex algorthm.
        Post:
            (1) Changes 'flow' attribute of edges.
        Return:
            Returns True when an optimal solution is found, returns
            False otherwise.
        '''
        # ==== determine an initial tree structure (T,L,U)
        # find a feasible flow
        if not self.find_feasible_flow():
            return False
        t = self.simplex_find_tree()
        self.set_display_mode(display)
        # mark spanning tree arcs
        self.simplex_mark_st_arcs(t)
        # display initial spanning tree
        t.simplex_redraw(display, root)
        t.set_display_mode(display)
        #t.display()
        self.display()
        # set predecessor, depth and thread indexes
        t.simplex_search(root, 1)
        # compute potentials
        self.simplex_compute_potentials(t, root)
        # while some nontree arc violates optimality conditions
        while not self.simplex_optimal(t):
            self.display()
            # select an entering arc (k,l)
            (k,l) = self.simplex_select_entering_arc(t, pivot)
            self.simplex_mark_entering_arc(k, l)
            self.display()
            # determine leaving arc
            ((p,q), capacity, cycle)=self.simplex_determine_leaving_arc(t,k,l)
            # mark leaving arc
            self.simplex_mark_leaving_arc(p, q)
            self.display()
            self.simplex_remove_arc(t, p, q, capacity, cycle)
            # display after arc removed
            self.display()
            self.simplex_mark_st_arcs(t)
            self.display()
            # set predecessor, depth and thread indexes
            t.simplex_redraw(display, root)
            #t.display()
            t.simplex_search(root, 1)
            # compute potentials
            self.simplex_compute_potentials(t, root)
        return True

Response: This function returns True when an optimal solution is found and False otherwise.


Instruction:
Here you have a function in Python 3, explain what it does
def simplex_mark_st_arcs(self, t):
        '''
        API:
            simplex_mark_st_arcs(self, t)
        Description:
            Marks spanning tree arcs.
            Case 1, Blue: Arcs that are at lower bound and in tree.
            Case 2, Red: Arcs that are at upper bound and in tree.
            Case 3, Green: Arcs that are between bounds are green.
            Case 4, Brown: Non-tree arcs at lower bound.
            Case 5, Violet: Non-tree arcs at upper bound.
        Input:
            t: t is the current spanning tree
        Post:
            (1) color attribute of edges.
        '''
        tel = list(t.edge_attr.keys())
        for e in self.get_edge_list():
            flow_e = self.edge_attr[e]['flow']
            capacity_e = self.edge_attr[e]['capacity']
            if e in tel:
                if flow_e == 0:
                    self.edge_attr[e]['color'] = 'blue'
                elif flow_e == capacity_e:
                    self.edge_attr[e]['color'] = 'blue'
                else:
                    self.edge_attr[e]['color'] = 'blue'
            else:
                if flow_e == 0:
                    self.edge_attr[e]['color'] = 'black'
                elif flow_e == capacity_e:
                    self.edge_attr[e]['color'] = 'black'
                else:
                    msg = "Arc is not in ST but has flow between bounds."
                    raise Exception(msg)

Response: Mark all arcs in the current spanning tree as st.


Instruction:
Write a Python 3 function that can
print all positive flows to stdout.

Response:
def print_flow(self):
        '''
        API:
            print_flow(self)
        Description:
            Prints all positive flows to stdout. This method can be used for
            debugging purposes.
        '''
        print('printing current edge, flow, capacity')
        for e in self.edge_attr:
            if self.edge_attr[e]['flow']!=0:
                print(e, str(self.edge_attr[e]['flow']).ljust(4), end=' ')
                print(str(self.edge_attr[e]['capacity']).ljust(4))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def simplex_redraw(self, display, root):
        '''
        API:
            simplex_redraw(self, display, root)
        Description:
            Returns a new graph instance that is same as self but adds nodes
            and arcs in a way that the resulting tree will be displayed
            properly.
        Input:
            display: display mode
            root: root node in tree.
        Return:
            Returns a graph same as self.
        '''
        nl = self.get_node_list()
        el = self.get_edge_list()
        new = Graph(type=DIRECTED_GRAPH, layout='dot', display=display)
        pred_i = self.get_node(root).get_attr('pred')
        thread_i = self.get_node(root).get_attr('thread')
        depth_i = self.get_node(root).get_attr('depth')
        new.add_node(root, pred=pred_i, thread=thread_i, depth=depth_i)
        q = [root]
        visited = [root]
        while q:
            name = q.pop()
            visited.append(name)
            neighbors = self.neighbors[name] + self.in_neighbors[name]
            for n in neighbors:
                if n not in new.get_node_list():
                    pred_i = self.get_node(n).get_attr('pred')
                    thread_i = self.get_node(n).get_attr('thread')
                    depth_i = self.get_node(n).get_attr('depth')
                    new.add_node(n, pred=pred_i, thread=thread_i, depth=depth_i)
                if (name,n) in el:
                    if (name,n) not in new.edge_attr:
                        new.add_edge(name,n)
                else:
                    if (n,name) not in new.edge_attr:
                        new.add_edge(n,name)
                if n not in visited:
                    q.append(n)
        for e in el:
            flow = self.edge_attr[e]['flow']
            capacity = self.edge_attr[e]['capacity']
            cost = self.edge_attr[e]['cost']
            new.edge_attr[e]['flow'] = flow
            new.edge_attr[e]['capacity'] = capacity
            new.edge_attr[e]['cost'] = cost
            new.edge_attr[e]['label'] =  "%d/%d/%d" %(flow,capacity,cost)
        return new

Response: Simplex redraws the current tree.


Instruction:
Can you generate the documentation for the following Python 3 function
def simplex_optimal(self, t):
        '''
        API:
            simplex_optimal(self, t)
        Description:
            Checks if the current solution is optimal, if yes returns True,
            False otherwise.
        Pre:
            'flow' attributes represents a solution.
        Input:
            t: Graph instance tat reperesents spanning tree solution.
        Return:
            Returns True if the current solution is optimal (optimality
            conditions are satisfied), else returns False
        '''
        for e in self.edge_attr:
            if e in t.edge_attr:
                continue
            flow_ij = self.edge_attr[e]['flow']
            potential_i = self.get_node(e[0]).get_attr('potential')
            potential_j = self.get_node(e[1]).get_attr('potential')
            capacity_ij = self.edge_attr[e]['capacity']
            c_ij = self.edge_attr[e]['cost']
            cpi_ij = c_ij - potential_i + potential_j
            if flow_ij==0:
                if cpi_ij < 0:
                    return False
            elif flow_ij==capacity_ij:
                if cpi_ij > 0:
                    return False
        return True

Response: Simplex - optimal check for current solution.


Instruction:
Can you generate the documentation for the following Python 3 function
def simplex_find_tree(self):
        '''
        API:
            simplex_find_tree(self)
        Description:
            Assumes a feasible flow solution stored in 'flow' attribute's of
            arcs and converts this solution to a feasible spanning tree
            solution.
        Pre:
            (1) 'flow' attributes represents a feasible flow solution.
        Post:
            (1) 'flow' attributes may change when eliminating cycles.
        Return:
            Return a Graph instance that is a spanning tree solution.
        '''
        # find a cycle
        solution_g = self.get_simplex_solution_graph()
        cycle = solution_g.simplex_find_cycle()
        while cycle is not None:
            # find amount to augment and direction
            amount = self.simplex_augment_cycle(cycle)
            # augment along the cycle
            self.augment_cycle(amount, cycle)
            # find a new cycle
            solution_g = self.get_simplex_solution_graph()
            cycle = solution_g.simplex_find_cycle()
        # check if the solution is connected
        while self.simplex_connect(solution_g):
            pass
        # add attributes
        for e in self.edge_attr:
            flow = self.edge_attr[e]['flow']
            capacity = self.edge_attr[e]['capacity']
            cost = self.edge_attr[e]['cost']
            self.edge_attr[e]['label'] = "%d/%d/%d" %(flow,capacity,cost)
            if e in solution_g.edge_attr:
                solution_g.edge_attr[e]['flow'] = flow
                solution_g.edge_attr[e]['capacity'] = capacity
                solution_g.edge_attr[e]['cost'] = cost
                solution_g.edge_attr[e]['label'] = "%d/%d/%d" %(flow,capacity,cost)
        return solution_g

Response: A method that finds a feasible flow solution for a given set of nodes and edges.


Instruction:
Can you generate the documentation for the following Python 3 function
def simplex_connect(self, solution_g):
        '''
        API:
            simplex_connect(self, solution_g)
        Description:
            At this point we assume that the solution does not have a cycle.
            We check if all the nodes are connected, if not we add an arc to
            solution_g that does not create a cycle and return True. Otherwise
            we do nothing and return False.
        Pre:
            (1) We assume there is no cycle in the solution.
        Input:
            solution_g: current spanning tree solution instance.
        Post:
            (1) solution_g is updated. An arc that does not create a cycle is
            added.
            (2) 'component' attribute of nodes are changed.
        Return:
            Returns True if an arc is added, returns False otherwise.
        '''
        nl = solution_g.get_node_list()
        current = nl[0]
        pred = solution_g.simplex_search(current, current)
        separated = list(pred.keys())
        for n in nl:
            if solution_g.get_node(n).get_attr('component') != current:
                # find an arc from n to seperated
                for m in separated:
                    if (n,m) in self.edge_attr:
                        solution_g.add_edge(n,m)
                        return True
                    elif (m,n) in self.edge_attr:
                        solution_g.add_edge(m,n)
                        return True
        return False

Response: This function checks if all the nodes are connected to the current spanning tree solution instance and adds them to the solution_g.


Instruction:
Given the following Python 3 function, write the documentation
def simplex_search(self, source, component_nr):
        '''
        API:
            simplex_search(self, source, component_nr)
        Description:
            Searches graph starting from source. Its difference from usual
            search is we can also go backwards along an arc. When the graph
            is a spanning tree it computes predecessor, thread and depth
            indexes and stores them as node attributes. These values should be
            considered as junk when the graph is not a spanning tree.
        Input:
            source: source node
            component_nr: component number
        Post:
            (1) Sets the component number of all reachable nodes to component.
            Changes 'component' attribute of nodes.
            (2) Sets 'pred', 'thread' and 'depth' attributes of nodes. These
            values are junk if the graph is not a tree.
        Return:
            Returns predecessor dictionary.
        '''
        q = [source]
        pred = {source:None}
        depth = {source:0}
        sequence = []
        for n in self.neighbors:
            self.get_node(n).set_attr('component', None)
        while q:
            current = q.pop()
            self.get_node(current).set_attr('component', component_nr)
            sequence.append(current)
            neighbors = self.in_neighbors[current] + self.neighbors[current]
            for n in neighbors:
                if n in pred:
                    continue
                self.get_node(n).set_attr('component', component_nr)
                pred[n] = current
                depth[n] = depth[current]+1
                q.append(n)
        for i in range(len(sequence)-1):
            self.get_node(sequence[i]).set_attr('thread', int(sequence[i+1]))
        self.get_node(sequence[-1]).set_attr('thread', int(sequence[0]))
        for n in pred:
            self.get_node(n).set_attr('pred', pred[n])
            self.get_node(n).set_attr('depth', depth[n])
        return pred

Response: Simplex search for a node in the graph starting from a given component.


Instruction:
How would you code a function in Python 3 to
augment the cycle with the minimum capacity.

Response:
def simplex_augment_cycle(self, cycle):
        '''
        API:
            simplex_augment_cycle(self, cycle)
        Description:
            Augments along the cycle to break it.
        Pre:
            'flow', 'capacity' attributes on arcs.
        Input:
            cycle: list representing a cycle in the solution
        Post:
            'flow' attribute will be modified.
        '''
        # find amount to augment
        index = 0
        k = len(cycle)
        el = list(self.edge_attr.keys())
        # check arc (cycle[k-1], cycle[0])
        if (cycle[k-1], cycle[0]) in el:
            min_capacity = self.edge_attr[(cycle[k-1], cycle[0])]['capacity']-\
                              self.edge_attr[(cycle[k-1], cycle[0])]['flow']
        else:
            min_capacity = self.edge_attr[(cycle[0], cycle[k-1])]['flow']
        # check rest of the arcs in the cycle
        while index<(k-1):
            i = cycle[index]
            j = cycle[index+1]
            if (i,j) in el:
                capacity_ij = self.edge_attr[(i,j)]['capacity'] -\
                              self.edge_attr[(i,j)]['flow']
            else:
                capacity_ij = self.edge_attr[(j,i)]['flow']
            if min_capacity > capacity_ij:
                min_capacity = capacity_ij
            index += 1
        return min_capacity


Instruction:
Can you generate the documentation for the following Python 3 function
def simplex_find_cycle(self):
        '''
        API:
            simplex_find_cycle(self)
        Description:
            Returns a cycle (list of nodes) if the graph has one, returns None
            otherwise. Uses DFS. During DFS checks existence of arcs to lower
            depth regions. Note that direction of the arcs are not important.
        Return:
            Returns list of nodes that represents cycle. Returns None if the
            graph does not have any cycle.
        '''
        # make a dfs, if you identify an arc to a lower depth node we have a
        # cycle
        nl = self.get_node_list()
        q = [nl[0]]
        visited = []
        depth = {nl[0]:0}
        pred = {nl[0]:None}
        for n in nl:
            self.get_node(n).set_attr('component', None)
        component_nr = int(nl[0])
        self.get_node(nl[0]).set_attr('component', component_nr)
        while True:
            while q:
                current = q.pop()
                visited.append(current)
                neighbors = self.in_neighbors[current] +\
                    self.neighbors[current]
                for n in neighbors:
                    if n==pred[current]:
                        continue
                    self.get_node(n).set_attr('component', component_nr)
                    if n in depth:
                        # we have a cycle
                        cycle1 = []
                        cycle2 = []
                        temp = n
                        while temp is not None:
                            cycle1.append(temp)
                            temp = pred[temp]
                        temp = current
                        while temp is not None:
                            cycle2.append(temp)
                            temp = pred[temp]
                        cycle1.pop()
                        cycle1.reverse()
                        cycle2.extend(cycle1)
                        return cycle2
                    else:
                        pred[n] = current
                        depth[n] = depth[current] + 1
                    if n not in visited:
                        q.append(n)
            flag = False
            for n in nl:
                if self.get_node(n).get_attr('component') is None:
                    q.append(n)
                    depth = {n:0}
                    pred = {n:None}
                    visited = []
                    component_nr = int(n)
                    self.get_node(n).set_attr('component', component_nr)
                    flag = True
                    break
            if not flag:
                break
        return None

Response: This function finds a cycle in the graph.


Instruction:
Given the following Python 3 function, write the documentation
def get_simplex_solution_graph(self):
        '''
        API:
            get_simplex_solution_graph(self):
        Description:
            Assumes a feasible flow solution stored in 'flow' attribute's of
            arcs. Returns the graph with arcs that have flow between 0 and
            capacity.
        Pre:
            (1) 'flow' attribute represents a feasible flow solution. See
            Pre section of min_cost_flow() for details.
        Return:
            Graph instance that only has the arcs that have flow strictly
            between 0 and capacity.
        '''
        simplex_g = Graph(type=DIRECTED_GRAPH)
        for i in self.neighbors:
            simplex_g.add_node(i)
        for e in self.edge_attr:
            flow_e = self.edge_attr[e]['flow']
            capacity_e = self.edge_attr[e]['capacity']
            if flow_e>0 and flow_e<capacity_e:
                simplex_g.add_edge(e[0], e[1])
        return simplex_g

Response: Returns a graph that contains all the arcs that have flow between 0 and capacity.