<jupyter_start><jupyter_text>Table of Contents1&nbsp;&nbsp;Graph Theory and Graphs in Python1.1&nbsp;&nbsp;Introduction into Graph Theory Using Python1.2&nbsp;&nbsp;Graphs as a Python class1.3&nbsp;&nbsp;Tree / Forest1.3.1&nbsp;&nbsp;Spanning Tree1.3.2&nbsp;&nbsp;Hamiltonian Game1.4&nbsp;&nbsp;Distance and Diameter of a graph1.5&nbsp;&nbsp;Connected Graphs1.6&nbsp;&nbsp;Graph Density1.7&nbsp;&nbsp;Implementation of the Erdös-Gallai theorem1.8&nbsp;&nbsp;Degree Sequence1.9&nbsp;&nbsp;Degree1.10&nbsp;&nbsp;Paths in Graphs  Graph Theory and Graphs in Python[Python Advanced: Graph Theory and Graphs in Python](http://www.python-course.eu/graphs_python.php) - Paths  - Adjacent vertices    - Two vertices are adjacent when they are both incident to a common edge.   - Path in an undirected Graph    - A path in an undirected graph is a sequence of vertices P = ( v1, v2, ..., vn ) ∈ V x V x ... x V such that vi is adjacent to v{i+1} for 1 ≤ i < n. Such a path P is called a path of length n from v1 to vn.     - (a,c,e,b,c,d) is a path but not a simple path  - Simple Path    - A path with no repeated vertices is called a simple path.     - (a, c, e) is a simple path- Degree  - Degree    - The degree of a vertex v in a graph is the number of edges connecting it, with loops counted twice.    - The degree of a vertex v is denoted deg(v).     - The maximum degree of a graph G, denoted by Δ(G), and the minimum degree of a graph, denoted by δ(G), are the maximum and minimum degree of its vertices.   - regular graph    - If all the degrees in a graph are the same, the graph is a regular graph. In a regular graph, all degrees are the same, and so we can speak of the degree of the graph.   - degree sum formular(Handshaking lemma)    - ∑v ∈ Vdeg(v) = 2 |E|    - the sum of degrees of all the vertices is equal to the number of edges multiplied by 2.    - We can conclude that **the number of vertices with odd degree has to be even.**（有奇数度的顶点个数一定是偶数）    - "handshaking lemma" stems from a popular mathematical problem: In any group of people the number of people who have shaken hands with an odd number of other people from the group is even.- Degree Sequence  - The degree sequence of an undirected graph is defined as the sequence of its vertex degrees in a non-increasing order.   - Isomorphic graphs have the same degree sequence.     - However, two graphs with the same degree sequence are not necessarily isomorphic.   - The Erdös-Gallai theorem   - The Erdös-Gallai theorem states that a non-increasing sequence of n numbers di (for i = 1, ..., n) is the degree sequence of a simple graph if and only if the **sum of the sequence is even** and the **following condition** is fulfilled:   $$\sum_{i=1}^k d_i \leqslant k(k-1) + \sum_{i=k+1}^n min(d_i,k) \quad for \ k \in {1,...,n}$$    - 什么叫合法的度数序列？就是存在一个无重边无自环（简单）的无向图，使得图中每个点的度数构成的序列为给定的序列。- Graph Density  - The graph density is defined as the ratio of the number of edges of a given graph, and the total number of edges, the graph could have.  - It measures how close a given graph is to a complete graph.   - $D = \frac {\lvert E \rvert}{\lvert V \rvert(\lvert V \rvert -1)}$  - A dense graph is a graph in which the number of edges is close to the maximal number of edges. A graph with only a few edges, is called a sparse graph.  - The precisest mathematical notation uses the big O notation.  - A dense graph is a graph G = (V, E) in which |E| = Θ(|V|2). - Connected Graphs  - A graph is said to be connected if every pair of vertices in the graph is connected.    - It possible to determine with a simple algorithm whether a graph is connected:    - Choose an arbitrary node x of the graph G as the starting point    - Determine the set A of all the nodes which can be reached from x.    - If A is equal to the set of nodes of G, the graph is connected; otherwise it is disconnected.  - Distance and Diameter of a graph    - The distance "dist" between two vertices in a graph is the length of the shortest path between these vertices.     - No backtracks, detours, or loops are allowed for the calculation of a distance.   - The eccentricity of a vertex s of a graph g is the maximal distance to every other vertex of the graph:       - e(s) = max( { dist(s,v) | v ∈ V }), (V is the set of all vertices of g)     - The diameter d of a graph is defined as the maximum eccentricity of any vertex in the graph.       - **This means that the diameter is the length of the shortest path between the most distanced nodes.**     - 最短路径里面最长的那个就是图的直径。  - To determine the diameter of a graph,       - first find the shortest path between each pair of vertices.       - The greatest length of any of these paths is the diameter of the graph.- Tree / Forest  - A tree is an undirected graph which contains no cycles（某条路径的起点和终点相同）. This means that any two vertices of the graph are connected by exactly one simple path.   - **A forest is a disjoint union of trees.**     - Contrary to forests in nature, a forest in graph theory can consist of a single tree!   - A graph with one vertex and no edge is a tree (and a forest). - Spanning Tree  - A spanning tree T of a connected, undirected graph G is a subgraph G' of G, which is a tree, and G' contains all the vertices and a subset of the edges of G.     - G' contains all the edges of G, if G is a tree graph.     - Informally, a spanning tree of G is a selection of edges of G that form a tree spanning every vertex.     - That is, every vertex lies in the tree, but no cycles (or loops) are contained.   - Hamiltonian Game  - An Hamiltonian path is a path in an undirected or directed graph that visits each vertex **exactly once**.     - A Hamiltonian cycle (or circuit) is a Hamiltonian path that is a cycle.     - Note for computer scientists: Generally, it is not not possible to determine, whether such paths or cycles exist in arbitrary graphs, because the Hamiltonian path problem has been proven to be NP-complete.   - It is named after <NAME> who invented the so-called "icosian game", or Hamilton's puzzle, which involves finding a Hamiltonian cycle in the edge graph of the dodecahedron.     - Hamilton solved this problem using the icosian calculus, an algebraic structure based on roots of unity with many similarities to the quaternions, which he also invented.   Introduction into Graph Theory Using Python ![](http://www.python-course.eu/images/simple_graph_isolated.png)<jupyter_code>graph = { "a" : ["c"],
          "b" : ["c", "e"],
          "c" : ["a", "b", "d", "e"],
          "d" : ["c"],
          "e" : ["c", "b"],
          "f" : []
        }
graph
def generate_edges(graph):
    edges = []
    for node in graph:
        for neighbour in graph[node]:
            edges.append((node, neighbour))
    return edges
print(generate_edges(graph))
def find_isolated_nodes(graph):
    """returns a list of isolated nodes."""
    isolated = []
    for node in graph:
        if not graph[node]:
            isolated += node
    return isolated
print(find_isolated_nodes(graph))<jupyter_output>['f']<jupyter_text>Graphs as a Python class ![](http://www.python-course.eu/images/simple_graph_with_loop.png)<jupyter_code>""" A Python Class
A simple Python graph class, demonstrating the essential 
facts and functionalities of graphs.
"""

class Graph(object):

    def __init__(self, graph_dict=None):
        """ initializes a graph object 
            If no dictionary or None is given, 
            an empty dictionary will be used
        """
        if graph_dict == None:
            graph_dict = {}
        self.__graph_dict = graph_dict

    def vertices(self):
        """ returns the vertices of a graph """
        return list(self.__graph_dict.keys())

    def edges(self):
        """ returns the edges of a graph """
        return self.__generate_edges()

    def add_vertex(self, vertex):
        """ If the vertex "vertex" is not in 
            self.__graph_dict, a key "vertex" with an empty
            list as a value is added to the dictionary. 
            Otherwise nothing has to be done. 
        """
        if vertex not in self.__graph_dict:
            self.__graph_dict[vertex] = []

    def add_edge(self, edge):
        """ assumes that edge is of type set, tuple or list; 
            between two vertices can be multiple edges! 
        """
        edge = set(edge)
        # tuple 后变为 y,x
        (vertex1, vertex2) = tuple(edge)
        if vertex1 in self.__graph_dict:
            self.__graph_dict[vertex1].append(vertex2)
        else:
            self.__graph_dict[vertex1] = [vertex2]

    def __generate_edges(self):
        """ A static method generating the edges of the 
            graph "graph". Edges are represented as sets 
            with one (a loop back to the vertex) or two 
            vertices 
        """
        edges = []
        for vertex in self.__graph_dict:
            for neighbour in self.__graph_dict[vertex]:
                if {neighbour, vertex} not in edges:
                    # 重复值算一次，集合而非元组
                    #print((neighbour, vertex))
                    edges.append({vertex, neighbour})
        return edges

    def __str__(self):
        res = "vertices: "
        for k in self.__graph_dict:
            res += str(k) + " "
        res += "\nedges: "
        for edge in self.__generate_edges():
            res += str(edge) + " "
        return res
    
    def find_path(self, start_vertex, end_vertex, path=None):
        """ find a path from start_vertex to end_vertex 
            in graph """
        if path == None:
            path = []
        graph = self.__graph_dict
        path = path + [start_vertex]
        if start_vertex == end_vertex:
            return path
        if start_vertex not in graph:
            return None
        for vertex in graph[start_vertex]:
            if vertex not in path:
                # 递归！
                extended_path = self.find_path(vertex, 
                                               end_vertex, 
                                               path)
                if extended_path: 
                    return extended_path
        return None
    
    def find_all_paths(self, start_vertex, end_vertex, path=[]):
        """ find all paths from start_vertex to 
            end_vertex in graph """
        graph = self.__graph_dict 
        path = path + [start_vertex]
        if start_vertex == end_vertex:
            return [path]
        if start_vertex not in graph:
            return []
        paths = []
        for vertex in graph[start_vertex]:
            if vertex not in path:
                # 递归！
                extended_paths = self.find_all_paths(vertex, 
                                                     end_vertex, 
                                                     path)
#                 if extended_paths != []:
#                     paths.append(extended_paths)
#                 print(extended_paths)
                for p in extended_paths: 
                    paths.append(p)
        return paths
    
    def vertex_degree(self, vertex):
        """ The degree of a vertex is the number of edges connecting
            it, i.e. the number of adjacent vertices. Loops are counted 
            double, i.e. every occurence of vertex in the list 
            of adjacent vertices. """ 
        adj_vertices =  self.__graph_dict[vertex]
        # 额外加上包含该顶点的量（1）
        degree = len(adj_vertices) + adj_vertices.count(vertex)
        return degree

    def find_isolated_vertices(self):
        """ returns a list of isolated vertices. 孤立点"""
        graph = self.__graph_dict
        isolated = []
        for vertex in graph:
            #print(isolated, vertex)
            if not graph[vertex]:
                isolated += [vertex]
        return isolated

    def delta(self):
        """ the minimum degree of the vertices """
        min = 100000000
        # 遍历顶点
        for vertex in self.__graph_dict:
            vertex_degree = self.vertex_degree(vertex)
            if vertex_degree < min:
                min = vertex_degree
        return min
        
    def Delta(self):
        """ the maximum degree of the vertices """
        max = 0
        for vertex in self.__graph_dict:
            vertex_degree = self.vertex_degree(vertex)
            if vertex_degree > max:
                max = vertex_degree
        return max

    def degree_sequence(self):
        """ calculates the degree sequence """
        seq = []
        # 遍历顶点
        for vertex in self.__graph_dict:
            seq.append(self.vertex_degree(vertex))
        # 从大到小排序
        seq.sort(reverse=True)
        return tuple(seq)

    
    @staticmethod
    def is_degree_sequence(sequence):
        """ Method returns True, if the sequence "sequence" is a 
            degree sequence, i.e. a non-increasing sequence. 
            Otherwise False is returned.
        """
        # check if the sequence sequence is non-increasing:
        # all 参数是一个 iterable，所有值为真时，返回真
        return all( x>=y for x, y in zip(sequence, sequence[1:]))

    @staticmethod
    def erdoes_gallai(dsequence):
        """ Checks if the condition of the Erdoes-Gallai inequality 
            is fullfilled 
        """
        if sum(dsequence) % 2:
            # sum of sequence is odd
            return False
        if Graph.is_degree_sequence(dsequence):
            for k in range(1,len(dsequence) + 1):
                left = sum(dsequence[:k])
                right =  k * (k-1) + sum([min(x,k) for x in dsequence[k:]])
                if left > right:
                    return False
        else:
            # sequence is increasing
            return False
        return True

    def density(self):
        """ method to calculate the density of a graph """
        g = self.__graph_dict
        V = len(g.keys())
        E = len(self.edges())
        return 2.0 * E / (V *(V - 1))

    def is_connected(self, 
                     vertices_encountered = None, 
                     start_vertex=None):
        """ determines if the graph is connected """
        if vertices_encountered is None:
            vertices_encountered = set()
        gdict = self.__graph_dict        
        vertices = list(gdict.keys()) # "list" necessary in Python 3 
        if not start_vertex:
            # chosse a vertex from graph as a starting point
            start_vertex = vertices[0]
        vertices_encountered.add(start_vertex)
        if len(vertices_encountered) != len(vertices):
            for vertex in gdict[start_vertex]:
                if vertex not in vertices_encountered:
                    # 递归！
                    if self.is_connected(vertices_encountered, vertex):
                        return True
        else:
            return True
        return False    

    def diameter(self):
        """ calculates the diameter of the graph """
        
        v = self.vertices() 
        # 遍历完所有的对儿
        pairs = [ (v[i],v[j]) for i in range(len(v)-1) for j in range(i+1, len(v))]
        smallest_paths = []
        for (s,e) in pairs:
            paths = self.find_all_paths(s,e)
            # key 是长度，取最短的那个 path
            smallest = sorted(paths, key=len)[0]
            smallest_paths.append(smallest)
        
        # smallest_paths 里面都是 path，又一种排序方法
        smallest_paths.sort(key=len)

        # longest path is at the end of list, 
        # i.e. diameter corresponds to the length of this path
        diameter = len(smallest_paths[-1]) - 1
        return diameter



if __name__ == "__main__":

    g = { "a" : ["d"],
          "b" : ["c"],
          "c" : ["b", "c", "d", "e"],
          "d" : ["a", "c"],
          "e" : ["c"],
          "f" : []
        }


    graph = Graph(g)
print("Vertices of graph:")
print(graph.vertices())

print("Edges of graph:")
print(graph.edges())

print("Add vertex:")
graph.add_vertex("z")

print("Vertices of graph:")
print(graph.vertices())

print("Add an edge:")
graph.add_edge({"a","z"})

print("Vertices of graph:")
print(graph.vertices())

print("Edges of graph:")
print(graph.edges())

print('Adding an edge {"x","y"} with new vertices:')
graph.add_edge({"x","y"})

print("Vertices of graph:")
print(graph.vertices())

print("Edges of graph:")
print(graph.edges())<jupyter_output>Vertices of graph:
['b', 'a', 'f', 'd', 'c', 'e']
Edges of graph:
[{'b', 'c'}, {'d', 'a'}, {'d', 'c'}, {'c'}, {'c', 'e'}]
Add vertex:
Vertices of graph:
['z', 'b', 'a', 'f', 'd', 'c', 'e']
Add an edge:
Vertices of graph:
['z', 'b', 'a', 'f', 'd', 'c', 'e']
Edges of graph:
[{'z', 'a'}, {'b', 'c'}, {'d', 'a'}, {'d', 'c'}, {'c'}, {'c', 'e'}]
Adding an edge {"x","y"} with new vertices:
Vertices of graph:
['z', 'b', 'a', 'f', 'd', 'c', 'x', 'e']
Edges of graph:
[{'z', 'a'}, {'b', 'c'}, {'d', 'a'}, {'d', 'c'}, {'c'}, {'c', 'e'}, {'x', 'y'}]<jupyter_text>Tree / Forest A tree is an undirected graph which contains no cycles（某条路径的起点和终点相同）. This means that any two vertices of the graph are connected by exactly one simple path. **A forest is a disjoint union of trees.**   Contrary to forests in nature, a forest in graph theory can consist of a single tree! A graph with one vertex and no edge is a tree (and a forest).  A tree and forest:  ![](http://www.python-course.eu/images/tree_graph.png) Two Trees:  ![](http://www.python-course.eu/images/forest_graph.png)  Spanning Tree A spanning tree T of a connected, undirected graph G is a subgraph G' of G, which is a tree, and G' contains all the vertices and a subset of the edges of G.   G' contains all the edges of G, if G is a tree graph.   Informally, a spanning tree of G is a selection of edges of G that form a tree spanning every vertex.   That is, every vertex lies in the tree, but no cycles (or loops) are contained.   Hamiltonian Game An Hamiltonian path is a path in an undirected or directed graph that visits each vertex **exactly once**.   A Hamiltonian cycle (or circuit) is a Hamiltonian path that is a cycle.   Note for computer scientists: Generally, it is not not possible to determine, whether such paths or cycles exist in arbitrary graphs, because the Hamiltonian path problem has been proven to be NP-complete. It is named after <NAME> who invented the so-called "icosian game", or Hamilton's puzzle, which involves finding a Hamiltonian cycle in the edge graph of the dodecahedron.   Hamilton solved this problem using the icosian calculus, an algebraic structure based on roots of unity with many similarities to the quaternions, which he also invented.   Distance and Diameter of a graph  The distance "dist" between two vertices in a graph is the length of the shortest path between these vertices. No backtracks, detours, or loops are allowed for the calculation of a distance. The eccentricity of a vertex s of a graph g is the maximal distance to every other vertex of the graph:   e(s) = max( { dist(s,v) | v ∈ V })   (V is the set of all vertices of g)   The diameter d of a graph is defined as the maximum eccentricity of any vertex in the graph.   **This means that the diameter is the length of the shortest path between the most distanced nodes.**   To determine the diameter of a graph,     - first find the shortest path between each pair of vertices.     - The greatest length of any of these paths is the diameter of the graph. 最短路径里面最长的那个就是图的直径。<jupyter_code>v = list(g.keys())
v
pairs = [ (v[i],v[j]) for i in range(len(v)-1) for j in range(i+1, len(v))]
pairs
test = [['h','s','c'],['h'],['h', 'c']]
sorted(test, key=len)[0]
test.sort(key=len)
test
g = { "a" : ["c"],
      "b" : ["c","e","f"],
      "c" : ["a","b","d","e"],
      "d" : ["c"],
      "e" : ["b","c","f"],
      "f" : ["b","e"]
}


graph = Graph(g)

diameter = graph.diameter()

print(diameter)<jupyter_output>3<jupyter_text>Connected GraphsA graph is said to be connected if every pair of vertices in the graph is connected.  It possible to determine with a simple algorithm whether a graph is connected:- Choose an arbitrary node x of the graph G as the starting point- Determine the set A of all the nodes which can be reached from x.- If A is equal to the set of nodes of G, the graph is connected; otherwise it is disconnected.<jupyter_code>g = { "a" : ["d"],
      "b" : ["c"],
      "c" : ["b", "c", "d", "e"],
      "d" : ["a", "c"],
      "e" : ["c"],
      "f" : []
}

g2 = { "a" : ["d","f"],
       "b" : ["c"],
       "c" : ["b", "c", "d", "e"],
       "d" : ["a", "c"],
       "e" : ["c"],
       "f" : ["a"]
}

g3 = { "a" : ["d","f"],
       "b" : ["c","b"],
       "c" : ["b", "c", "d", "e"],
       "d" : ["a", "c"],
       "e" : ["c"],
       "f" : ["a"]
}


graph = Graph(g)
print(graph)
print(graph.is_connected())

graph = Graph(g2)
print(graph)
print(graph.is_connected())

graph = Graph(g3)
print(graph)
print(graph.is_connected())<jupyter_output>vertices: b a f d c e 
edges: {'b', 'c'} {'d', 'a'} {'d', 'c'} {'c'} {'c', 'e'} 
False
vertices: b a f d c e 
edges: {'b', 'c'} {'d', 'a'} {'a', 'f'} {'d', 'c'} {'c'} {'c', 'e'} 
True
vertices: b a f d c e 
edges: {'b', 'c'} {'b'} {'d', 'a'} {'a', 'f'} {'d', 'c'} {'c'} {'c', 'e'} 
True<jupyter_text>Graph Density<jupyter_code>g = { "a" : ["d","f"],
       "b" : ["c","b"],
       "c" : ["b", "c", "d", "e"],
       "d" : ["a", "c"],
       "e" : ["c"],
       "f" : ["a"]
}

complete_graph = { 
    "a" : ["b","c"],
    "b" : ["a","c"],
    "c" : ["a","b"]
}

isolated_graph = { 
    "a" : [],
    "b" : [],
    "c" : []
}


graph = Graph(g)
print(graph.density())

graph = Graph(complete_graph)
print(graph.density())

graph = Graph(isolated_graph)
print(graph.density())<jupyter_output>0.4666666666666667
1.0
0.0<jupyter_text>Implementation of the Erdös-Gallai theorem The Erdös-Gallai theorem states that a non-increasing sequence of n numbers di (for i = 1, ..., n) is the degree sequence of a simple graph if and only if the sum of the sequence is even and the following condition is fulfilled:   $$\sum_{i=1}^k d_i \leqslant k(k-1) + \sum_{i=k+1}^n min(d_i,k) \quad for \ k \in {1,...,n}$$  什么叫合法的度数序列？就是存在一个无重边无自环（简单）的无向图，使得图中每个点的度数构成的序列为给定的序列。<jupyter_code>def erdoes_gallai(dsequence):
    """ Checks if the condition of the Erdoes-Gallai inequality 
        is fullfilled 
    """
    if sum(dsequence) % 2:
        # sum of sequence is odd
        return False
    for k in range(1,len(dsequence) + 1):
        left = sum(dsequence[:k])
        right =  k * (k-1) + sum([min(x,k) for x in dsequence[k:]])
        if left > right:
            return False
    return True
graph.erdoes_gallai(t)
t = graph.degree_sequence()
t
for k in range(1, len(t) + 1):
    left = sum(t[:k])
    print(left)
    right = k * (k-1) + sum([min(x,k) for x in t[k:]])
    print(right)
    if left>right:
        print('False')
    else:
        print('True')<jupyter_output>5
4
False
7
5
False
8
8
True
9
13
True
10
20
True
10
30
True<jupyter_text>Degree SequenceIsomorphic graphs have the same degree sequence.   However, two graphs with the same degree sequence are not necessarily isomorphic.<jupyter_code>print('Degree sequence:')
print(graph.degree_sequence())<jupyter_output>Degree sequence:
(5, 2, 1, 1, 1, 0)<jupyter_text>Degree<jupyter_code>print('Degree of vertex:')
print(graph.vertex_degree("c"))
print('Isolated vertices:')
print(graph.find_isolated_vertices())
print('Minimum degree of the vertices:')
print(graph.delta())
print('Maximum degree of the vertices:')
print(graph.Delta())<jupyter_output>Maximum degree of the vertices:
5<jupyter_text>Paths in Graphs<jupyter_code>print("Vertices of graph:")
print(graph.vertices())

print("Edges of graph:")
print(graph.edges())


print('The path from vertex "a" to vertex "b":')
path = graph.find_path("a", "b")
print(path)

print('The path from vertex "a" to vertex "f":')
path = graph.find_path("a", "f")
print(path)

print('The path from vertex "c" to vertex "c":')
path = graph.find_path("c", "c")
print(path)
g = { "a" : ["d", "f"],
      "b" : ["c"],
      "c" : ["b", "c", "d", "e"],
      "d" : ["a", "c"],
      "e" : ["c"],
      "f" : ["d"]
    }


graph = Graph(g)

print("Vertices of graph:")
print(graph.vertices())

print("Edges of graph:")
print(graph.edges())


print('All paths from vertex "a" to vertex "b":')
path = graph.find_all_paths("a", "b")
print(path)

print('All paths from vertex "a" to vertex "f":')
path = graph.find_all_paths("a", "f")
print(path)

print('All paths from vertex "c" to vertex "c":')
path = graph.find_all_paths("c", "c")
print(path)<jupyter_output>Vertices of graph:
['a', 'c', 'f', 'b', 'e', 'd']
Edges of graph:
[{'a', 'd'}, {'a', 'f'}, {'b', 'c'}, {'c'}, {'c', 'd'}, {'c', 'e'}, {'f', 'd'}]
All paths from vertex "a" to vertex "b":
[['a', 'd', 'c', 'b'], ['a', 'f', 'd', 'c', 'b']]
All paths from vertex "a" to vertex "f":
[['a', 'f']]
All paths from vertex "c" to vertex "c":
[['c']]
{'fraction_non_alphanumeric': 0.12356739305891848, 'fraction_numerical': 0.005649717514124294, 'mean_word_length': 2.590408577223993, 'pattern_counts': {'":': 10, '<': 32, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 5, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '399937', 'license': 'MIT', 'n_tokens_mistral': 7837, 'n_tokens_neox': 7596, 'n_words': 2978, 'path': 'Graph/GraphTheory_Tutorial.ipynb', 'repo_name': 'hscspring/YamNLP', 'size': '24812'}