networkx 1.8中是否有一个类在节点添加/删除操作中封装树断言

时间:2014-06-01 18:20:50

标签: tree encapsulation networkx directed-graph

我现在搜索了一个小时的答案来回答这个微不足道的问题(对于那些知道的人来说是微不足道的)在一个实际写得很好的文件中(文章引用,而不是一篇文章)。让我告诉你到目前为止我发现了什么:

  • networkx.generators.directed包其中gn_graph“始终是(定向)树”但不一定封装断言
  • networkx.balanced_tree显然会产生一棵树,但不是任意的,而是平衡的
  • graph.Graph.Treehttp://networkx.lanl.gov/archive/networkx-0.37/networkx.tree.Tree-class.html)似乎很完美,但是版本是0.37,而不是1.8
  • 无数的generatores和iteratores提供 - well - 生成器和迭代器,但它们都没有记录操作中树断言的记录

对于操作中的封装,我指的是在添加或删除边时检查树断言(有向非循环图),例如

tree = networkx.tree.Tree()
tree.add_edge(a,b) # ok
tree.add_edge(b,c) # ok
tree.add_edge(b,a) # should raise TreeException("This is a tree, i****")

1 个答案:

答案 0 :(得分:3)

以下是' Tree'的修改版本。 class(来自networkx-0.37,现已弃用),适用于现代版本的networkx。使用networkx-1.9轻微测试但不保证任何正常工作;期待虫子。 https://gist.github.com/hagberg/c855589980d644254f6d

的可下载版本
from networkx import Graph
from networkx.exception import NetworkXException, NetworkXError
import networkx.convert as convert

class Tree(Graph):
    """ A free (unrooted) tree."""
    def __init__(self, data=None, **attr):
        Graph.__init__(self, **attr)
        if data is not None:
            convert.to_networkx_graph(data, create_using=self)
            # check if it is a tree.
            if not (G.order() == G.size() + 1 and
                    nx.number_connected_components(G) == 1):
                raise NetworkXError("Data %s is not a tree" % data)
        # load graph attributes (must be after convert)
        self.graph.update(attr)
        self.edge = self.adj

    def add_node(self, n):
        if n in self:
            return  # already in tree
        elif len(self.adj) == 0:
            Graph.add_node(self, n)  # first node
        else:  # not allowed
            raise NetworkXError(
                "adding single node %s not allowed in non-empty tree" % (n))

    def add_nodes_from(self, nbunch):
        for n in nbunch:
            self.add_node(n)

    def remove_node(self, n):
        try:
            if len(self.adj[n]) == 1:  # allowed for leaf node
                Graph.remove_node(self, n)
            else:
                raise NetworkXError(
                    "deleting interior node %s not allowed in tree" % (n))
        except KeyError:  # NetworkXError if n not in self
            raise NetworkXError("node %s not in graph" % n)

    def remove_nodes_from(self, nbunch):
        for n in nbunch:
            self.remove_node(n)

    def add_edge(self, u, v=None):
        if v is None:
            (u, v) = u  # no v given, assume u is an edge tuple
        if self.has_edge(u, v):
            return  # no parallel edges allowed
        elif u in self and v in self:
            raise NetworkXError(
                "adding edge %s-%s not allowed in tree" % (u, v))
        elif u in self or v in self:
            Graph.add_edge(self, u, v)
            return
        elif len(self.adj) == 0:  # first leaf
            Graph.add_edge(self, u, v)
            return
        else:
            raise NetworkXError(
                "adding edge %s-%s not allowed in tree" % (u, v))

    def add_edges_from(self, ebunch):
        for e in ebunch:
            self.add_edge(e)

    def remove_edge(self, u, v=None):
        if v is None:
            (u, v) = u
        if self.degree(u) == 1 or self.degree(v) == 1:  # leaf edge
            Graph.remove_edge(self, u, v)
        else:  # interior edge
            raise NetworkXError(
                "deleting interior edge %s-%s not allowed in tree" % (u, v))
        if self.degree(u) == 0:  # OK to remove remaining isolated node
            Graph.remove_node(self, u)
        if self.degree(v) == 0:  # OK to remove remaining isolated node
            Graph.remove_node(self, v)

    def remove_edges_from(self, ebunch):
        for e in ebunch:
            self.remove_edge(e)

    # leaf notation
    def add_leaf(self, u, v=None):
        self.add_edge(u, v)

    def remove_leaf(self, u, v=None):
        self.remove_edge(u, v)

    def add_leaves_from(self, ebunch):
        for e in ebunch:
            self.add_leaf(e)

    def remove_leaves_from(self, ebunch):
        for e in ebunch:
            self.remove_leaf(e)