def num_node_edge(self):
        def f():
            df = self.get_edges()
            m = len(df)
            n = len(set(np.unique(self.edges[['src', 'dest']].values)))
            return (n, m)

        prop_name = "_num_node_edge"
        return utils.set_if_not_exists(self, prop_name, f)
    def num_self_edges(self):
        '''
        return number of self edges 
        '''
        def f():
            snap = self.snap
            return snap.CntSelfEdges(self.graph)

        prop_name = "_" + sys._getframe().f_code.co_name
        return utils.set_if_not_exists(self, prop_name, f)
    def is_overlap(self):
        """
        :rtype: True if the clusters are overlapped
        """
        prop_name = "_" + sys._getframe().f_code.co_name

        def f():
            return (self.node_overlaps > 1).any()

        return utils.set_if_not_exists(self, prop_name, f)
    def index(self):
        """
        :rtype: cluster ids
        """
        prop_name = "_" + sys._getframe().f_code.co_name

        def f():
            df = self.value()
            return np.unique(df['cluster'].values)

        return utils.set_if_not_exists(self, prop_name, f)
    def node_overlaps(self):
        '''
        :rtype: overlapping count of each node.
        '''
        prop_name = "_" + sys._getframe().f_code.co_name

        def f():
            df = self.value()
            return df.groupby('node')['cluster'].count()

        return utils.set_if_not_exists(self, prop_name, f)
    def wcc_distribution(self):
        '''
        return list[(cc_size, count)] for weakly connected components
        '''
        def f():
            snap = self.snap
            ret = []
            ComponentDist = snap.TIntPr64V()
            snap.GetWccSzCnt(self.graph, ComponentDist)
            for comp in ComponentDist:
                ret.append((comp.GetVal1(), comp.GetVal2()))
            return ret

        prop_name = "_" + sys._getframe().f_code.co_name
        return utils.set_if_not_exists(self, prop_name, f)
    def degree_out_histogram(self):
        '''
        return list[(degree,num_node)] of out degree
        '''
        def f():
            snap = self.snap
            DegToCntV = snap.TFltPr64V()
            snap.GetOutDegCnt(self.graph, DegToCntV)
            ret = []
            for item in DegToCntV:
                ret.append((item.GetVal1(), item.GetVal2()))
            return ret

        prop_name = "_" + sys._getframe().f_code.co_name
        return utils.set_if_not_exists(self, prop_name, f)
    def node_degrees(self):
        '''
        return list[(node,degree)] 
        '''
        def f():
            snap = self.snap
            nodes = self.nodes
            V = snap.TInt64V()
            snap.GetDegSeqV(self.graph, V)
            ret = []
            for i in range(0, V.Len()):
                ret.append((nodes[i], V[i]))
            return ret

        prop_name = "_" + sys._getframe().f_code.co_name
        return utils.set_if_not_exists(self, prop_name, f)
    def edge_bridges(self):
        '''
        return list[edge] where edge is a bridge.
        
        An edge is a bridge if, when removed, increases the number of connected components.
        '''
        def f():
            snap = self.snap
            ret = []
            EdgeV = snap.TIntPr64V()
            snap.GetEdgeBridges(self.graph, EdgeV)
            for edge in EdgeV:
                ret.append((edge.GetVal1(), edge.GetVal2()))
            return ret

        prop_name = "_" + sys._getframe().f_code.co_name
        return utils.set_if_not_exists(self, prop_name, f)
    def nodes(self):
        def f():
            return [u.GetId() for u in self.graph.Nodes()]

        prop_name = "_" + sys._getframe().f_code.co_name
        return utils.set_if_not_exists(self, prop_name, f)