def dorogovtsev_mendes(n, directed=False): """ Create a Dorogovtsev-Mendes graph :param n: number of nodes :param directed: enable graph directed :return: graph created """ # Parameter's validation if n < 3: raise ValueError("n parameter must to be >= 3 ") g = graph.Graph() # Add attribute DIRECTED in graph g.attr[graph.DIRECTED] = directed # Create 3 vertex and 3 edges to form triangle for i in range(3): g.add_vertex(vertex.Vertex(i)) for i in range(3): j = i + 1 if i < 2 else 0 g.add_edge(edge.Edge(i, j), directed) # To add next vertices one by one, choosing randomly one edge of the grap # and create edges between new vertice and origin and source of edge selected for i in range(3, n): g.add_vertex(vertex.Vertex(i)) # Select random edge of the graph id_edge = randint(0, len(g.get_edges()) - 1) edge_selected = g.get_edges()[id_edge] (source, target) = edge_selected # Create edges between new vertice and origin and source of edge selected g.add_edge(edge.Edge(i, source), directed) g.add_edge(edge.Edge(i, target), directed) return g
def dijkstra_tree(self, s): """ dijkstra_tree is an algorithm for finding tree of cost for each node according Dijkstra's algorithm. :param s: node source :param t: node target :return g graph generated with the shortest path from source to target """ l = [] dist = {} prev = {} discovered = {} g = Graph(attr={DIRECTED: True}) g.add_vertex(vertex.Vertex(s, {"WEIGHT": 0})) for v in self.get_vertices(): dist[v] = float('inf') prev[v] = None discovered[v] = False dist[s] = 0 l.append((s, dist[s])) while len(l) != 0: u = min(l, key=lambda x: x[1]) l.remove(u) u = u[0] discovered[u] = True for v in self.get_adjacent_vertices_by_vertex(u): if not discovered[v]: alt = dist[u] + self.get_edge((u, v)).attr["WEIGHT"] if alt < dist[v]: dist[v] = alt prev[v] = u l.append((v, dist[v])) g.add_vertex(vertex.Vertex(v, {"WEIGHT": dist[v]})) g.add_edge(edge.Edge(u, v, {"WEIGHT": dist[v]})) return g
def KruskalD(self): """ KruskalD is a function based on Krustal's algorithm to find a minimum spanning forest of an undirected edge-weighted graph. :return g graph representing minimum spannng forest """ g = Graph(attr={DIRECTED: False}) # Create set for each v of V[G] parent = [] rank = [] for v in self.get_vertices(): parent.append(v) rank.append(0) # Sort edges by weight q = sorted(self.edges.items(), key=lambda e: e[1].attr["WEIGHT"]) for e in q: (u, v) = e[0] v1 = self.find(parent, u) v2 = self.find(parent, v) if v1 != v2: g.add_vertex(vertex.Vertex(u)) g.add_vertex(vertex.Vertex(v)) g.add_edge(edge.Edge(u, v, {"WEIGHT": e[1].attr["WEIGHT"]})) if rank[v1] < rank[v2]: parent[v1] = v2 rank[v2] += 1 else: parent[v2] = v1 rank[v1] += 1 return g
def test_calculate_distance(self): v1 = vertex.Vertex(1, {models.COORDINATE_X: 3, models.COORDINATE_Y: 2}) v2 = vertex.Vertex(2, {models.COORDINATE_X: 9, models.COORDINATE_Y: 7}) p1 = (v1.attributes[models.COORDINATE_X], v1.attributes[models.COORDINATE_Y]) p2 = (v2.attributes[models.COORDINATE_X], v2.attributes[models.COORDINATE_Y]) models.calculate_distance(p1, p2)
def test_edges(self): g = graph.Graph() v = vertex.Vertex(1) g.add_vertex(v) v = vertex.Vertex(2) g.add_vertex(v) e = edge.Edge(1, 2) g.add_edge(e) self.assertEqual([(1, 2)], g.get_edges())
def test_add_edge(self): g = graph.Graph() v1 = vertex.Vertex(1) v2 = vertex.Vertex(2) g.add_vertex(v1) g.add_vertex(v2) e = edge.Edge(1, 2) g.add_edge(e) self.assertEqual(1, len(g.get_edges()))
def erdos_rengy(n, m, directed=False, auto=False): """ Creates a graph of n nodes with model Erdos-Renyi :param n: number of nodes ( > 0) :param m: number of edges ( >= n-1) :param directed: enable graph directed :param auto: allow auto-cycle (loops) :return: Graph created """ # Parameter's validation if n <= 0: raise ValueError("n parameter must to be > 0 ") if m < n - 1: raise ValueError("m parameter must to be >= n-1 ") g = graph.Graph() # Add attribute DIRECTED in graph g.attr[graph.DIRECTED] = directed for i in range(n): g.add_vertex(vertex.Vertex(i)) edges = {} while len(g.edges) != m: # Create random m different edges source = randint(0, m - 1) target = randint(0, m - 1) e = (source, target) if e not in edges: edges[e] = e g.add_edge(edge.Edge(source, target), directed, auto) return g
def test_prim(self): g = graph.Graph() for i in range(0, 6): v = vertex.Vertex(i) g.add_vertex(v) e1 = edge.Edge(0, 1, {"WEIGHT": 4}) g.add_edge(e1) e2 = edge.Edge(0, 2, {"WEIGHT": 1}) g.add_edge(e2) e3 = edge.Edge(0, 3, {"WEIGHT": 5}) g.add_edge(e3) e4 = edge.Edge(1, 3, {"WEIGHT": 2}) g.add_edge(e4) e5 = edge.Edge(1, 4, {"WEIGHT": 3}) g.add_edge(e5) e6 = edge.Edge(1, 5, {"WEIGHT": 3}) g.add_edge(e6) e7 = edge.Edge(2, 3, {"WEIGHT": 2}) g.add_edge(e7) e8 = edge.Edge(2, 4, {"WEIGHT": 8}) g.add_edge(e8) e9 = edge.Edge(3, 4, {"WEIGHT": 1}) g.add_edge(e9) e10 = edge.Edge(4, 5, {"WEIGHT": 3}) g.add_edge(e10) primg = g.Prim() amount = 0 for k in primg.edges: amount = amount + primg.edges[k].attr["WEIGHT"] self.assertEqual(amount, 9)
def mesh(m, n, directed=False): """ Creates a graph of m*n nodes :param m: number of columns (>1) :param n: number of rows (>1) :param directed: enable graph directed :return: Graph created """ # Parameter's validation if m <= 1 or n <= 1: raise ValueError("m,n parameters must to be > 1") g = graph.Graph() # Add attribute DIRECTED in graph g.attr[graph.DIRECTED] = directed for i in range(m * n): v = vertex.Vertex(i) g.add_vertex(v) index = 0 for i in range(m): for j in range(n): if i != (m - 1): g.add_edge(edge.Edge(index, (index + n)), directed) if j != (n - 1): g.add_edge(edge.Edge(index, (index + 1)), directed) index = index + 1 return g
def gilbert(n, p, directed=False, auto=False): """ Creates a graph of n nodes with model Gilbert :param n: number of nodes ( > 0) :param p: probability to create an edge (0,1) :param directed: enable graph directed :param auto: allow auto-cycle (loops) :return: Graph created """ # Parameter's validation if n <= 0: raise ValueError("n parameter must to be > 0 ") if p <= 0 or p >= 1: raise ValueError("p parameter must to be in range (0,1)") g = graph.Graph() # Add attribute DIRECTED in graph g.attr[graph.DIRECTED] = directed for i in range(n): g.add_vertex(vertex.Vertex(i)) for i in range(n): for j in range(n): # Create edge with probability => random number (0,1) if random() <= p: g.add_edge(edge.Edge(i, j), directed, auto) return g
def dijkstra(self, s, t): """ dijkstra is an algorithm for finding the shortest paths between nodes in a graph. :param s: node source :param t: node target :return g graph generated with the shortest path from source to target """ l = [] dist = {} prev = {} discovered = {} for v in self.get_vertices(): dist[v] = float('inf') prev[v] = None discovered[v] = False dist[s] = 0 l.append((s, dist[s])) while len(l) != 0: u = min(l, key=lambda x: x[1]) l.remove(u) u = u[0] discovered[u] = True if u == t: break for v in self.get_adjacent_vertices_by_vertex(u): if not discovered[v]: alt = dist[u] + self.get_edge((u, v)).attr["WEIGHT"] if alt < dist[v]: dist[v] = alt prev[v] = u l.append((v, dist[v])) # Create a graph according to visited nodes store in prev array u = t g = Graph(attr={DIRECTED: True}) while u is not None: g.add_vertex(vertex.Vertex(u, {"WEIGHT": dist[u]})) if prev[u] is not None: g.add_vertex(vertex.Vertex(prev[u], {"WEIGHT": dist[prev[u]]})) g.add_edge(edge.Edge(prev[u], u)) u = prev[u] else: break return g
def test_get_by_vertex(self): g = graph.Graph() v = vertex.Vertex(1) g.add_vertex(v) v = vertex.Vertex(2) g.add_vertex(v) v = vertex.Vertex(3) g.add_vertex(v) e = edge.Edge(1, 2) g.add_edge(e) self.assertEqual([(1, 2)], g.get_edges_by_vertex(1)) e = edge.Edge(1, 3) g.add_edge(e) self.assertEqual(2, len(g.get_edges_by_vertex(1))) e = edge.Edge(2, 1) g.add_edge(e, True) self.assertEqual(3, len(g.get_edges_by_vertex(1, 0))) self.assertEqual(2, len(g.get_edges_by_vertex(1, 1))) self.assertEqual(1, len(g.get_edges_by_vertex(1, 2)))
def test_bfs_simple_10(self): g = graph.Graph() for i in range(1, 11): v = vertex.Vertex(i) g.add_vertex(v) e = edge.Edge(1, 2) g.add_edge(e) e = edge.Edge(1, 3) g.add_edge(e) e = edge.Edge(1, 4) g.add_edge(e) e = edge.Edge(1, 5) g.add_edge(e) e = edge.Edge(2, 6) g.add_edge(e) e = edge.Edge(2, 7) g.add_edge(e) e = edge.Edge(6, 9) g.add_edge(e) e = edge.Edge(9, 10) g.add_edge(e) e = edge.Edge(3, 7) g.add_edge(e) e = edge.Edge(3, 8) g.add_edge(e) e = edge.Edge(4, 8) g.add_edge(e) e = edge.Edge(5, 10) g.add_edge(e) g2 = g.bfs(1) dot = g2.create_graphviz('bfs') gbase = '''digraph { 1 [label=1] 2 [label=2] 3 [label=3] 4 [label=4] 5 [label=5] 6 [label=6] 7 [label=7] 8 [label=8] 10 [label=10] 9 [label=9] 1 -> 2 1 -> 3 1 -> 4 1 -> 5 2 -> 6 2 -> 7 3 -> 8 5 -> 10 6 -> 9 }''' # dot.render('bfs',view=True) self.assertEqual(gbase, str(dot))
def test_dfs_simple_10(self): g = graph.Graph(attr={graph.DIRECTED: True}) for i in range(1, 11): v = vertex.Vertex(i) g.add_vertex(v) e = edge.Edge(1, 2) g.add_edge(e) e = edge.Edge(1, 3) g.add_edge(e) e = edge.Edge(1, 4) g.add_edge(e) e = edge.Edge(1, 5) g.add_edge(e) e = edge.Edge(2, 6) g.add_edge(e) e = edge.Edge(2, 7) g.add_edge(e) e = edge.Edge(6, 9) g.add_edge(e) e = edge.Edge(9, 10) g.add_edge(e) e = edge.Edge(3, 7) g.add_edge(e) e = edge.Edge(3, 8) g.add_edge(e) e = edge.Edge(4, 8) g.add_edge(e) e = edge.Edge(5, 10) g.add_edge(e) g2 = g.dfs(1) dot = g2.create_graphviz('dfs') gbase = '''digraph { 1 [label=1] 5 [label=5] 10 [label=10] 4 [label=4] 8 [label=8] 3 [label=3] 7 [label=7] 2 [label=2] 6 [label=6] 9 [label=9] 1 -> 5 5 -> 10 1 -> 4 4 -> 8 1 -> 3 3 -> 7 1 -> 2 2 -> 6 6 -> 9 }''' # dot.render('dfs',view=True) self.assertEqual(gbase, str(dot))
def barabasi(n, d, directed=False, auto=False): """ Create Barabasi-Albert (BA) graph :param n: number of nodes ( > 0) :param d: max number of edges of vertex ( > 1) :param directed: enable graph directed :param auto: allow auto-cycle (loops) return: graph created """ # Parameter's validation if n <= 0: raise ValueError("n parameter must to be > 0 ") if d <= 1: raise ValueError("d parameter must to be > 1") g = graph.Graph() # Add attribute DIRECTED in graph g.attr[graph.DIRECTED] = directed # The first d vertices are created with edges to relate each one with the others for i in range(d): g.add_vertex(vertex.Vertex(i)) for i in range(d): for j in range(d): if len(g.get_edges_by_vertex(i)) < d and len( g.get_edges_by_vertex(j)) < d: g.add_edge(edge.Edge(i, j), directed, auto) for i in range(d, n): g.add_vertex(vertex.Vertex(i)) for j in range(i): # The probability p that the new node i is connected to node j # is the grade of vertex j divided by the number of edges of graph p = len(g.get_edges_by_vertex(j)) / len(g.get_edges()) if len(g.get_edges_by_vertex(i)) < d and len( g.get_edges_by_vertex(j)) < d and p >= random(): g.add_edge(edge.Edge(i, j), directed, auto) return g
def test_dfs_r_simple_8(self): g = graph.Graph(attr={graph.DIRECTED: True}) for i in range(1, 9): v = vertex.Vertex(i) g.add_vertex(v) e = edge.Edge(1, 2) g.add_edge(e) e = edge.Edge(1, 3) g.add_edge(e) e = edge.Edge(1, 4) g.add_edge(e) e = edge.Edge(2, 5) g.add_edge(e) e = edge.Edge(5, 7) g.add_edge(e) e = edge.Edge(7, 8) g.add_edge(e) e = edge.Edge(3, 6) g.add_edge(e) e = edge.Edge(6, 8) g.add_edge(e) e = edge.Edge(6, 7) g.add_edge(e) g2 = g.dfs_r(1) dot = g2.create_graphviz('dfs') print(dot) gbase = '''digraph { 1 [label=1] 2 [label=2] 5 [label=5] 7 [label=7] 8 [label=8] 3 [label=3] 6 [label=6] 4 [label=4] 1 -> 2 2 -> 5 5 -> 7 7 -> 8 1 -> 3 3 -> 6 1 -> 4 }''' # dot.render('dfs_r',view=True) self.assertEqual(gbase, str(dot))
def Prim(self): """ Prim is a function based on Prim's algorithm to find a minimum spanning forest of an undirected edge-weighted graph. :return g graph representing minimum spannng forest """ g = Graph(attr={DIRECTED: False}) distance = [sys.maxsize] * len(self.vertices) parent = [None] * len(self.vertices) set = [False] * len(self.vertices) distance[0] = 0 parent[0] = -1 for i in self.vertices: # Search vertex with minimum distance min_index = 0 min = sys.maxsize for v in self.vertices: if distance[v] < min and set[v] is False: min = distance[v] min_index = v u = min_index # Add u vertex in set to not use it in other iteration set[u] = True g.add_vertex(vertex.Vertex(u)) # Iterate all adjacent vertices of u vertex and update distance for v in self.get_adjacent_vertices_by_vertex(u): if set[v] is False and distance[v] > \ self.get_edge((u, v)).attr["WEIGHT"]: distance[v] = self.get_edge((u, v)).attr["WEIGHT"] parent[v] = u for i in self.vertices: if i == 0: continue if parent[i] is not None: g.add_edge(edge.Edge(parent[i], i, {"WEIGHT": self.get_edge((parent[i], i)).attr["WEIGHT"]})) return g
def test_dijkstra_simple_3(self): g = graph.Graph() for i in range(1, 6): v = vertex.Vertex(i) g.add_vertex(v) e = edge.Edge(1, 2, {"WEIGHT": 1}) g.add_edge(e) e = edge.Edge(2, 4, {"WEIGHT": 1}) g.add_edge(e) e = edge.Edge(4, 5, {"WEIGHT": 1}) g.add_edge(e) e = edge.Edge(1, 3, {"WEIGHT": 5}) g.add_edge(e) e = edge.Edge(3, 4, {"WEIGHT": 3}) g.add_edge(e) dot = g.create_graphviz('dijkstra_original_3', attr_label_edge="WEIGHT") dot.render('dijkstra_3_original', view=True) result = g.dijkstra(1, 5) print(result) dot = result.create_graphviz('dijkstra_calculado_3', "WEIGHT", 1)
def geo_simple(n, r, directed=False, auto=False): """ Create a random graph with simple method geographic :param n: number of vertices ( > 0) :param r: max distance to generate edge between nodes (0,1) :param directed: enable graph directed :param auto: allow auto-cycle (loops) :return: graph created """ # Parameter's validation if n <= 0: raise ValueError("n parameter must to be > 0 ") if r <= 0 or r >= 1: raise ValueError("r parameter must to be in range (0,1)") g = graph.Graph() # Add attribute DIRECTED in graph g.attr[graph.DIRECTED] = directed # Create n nodes with uniform coordinates for i in range(n): g.add_vertex( vertex.Vertex(i, { COORDINATE_X: random(), COORDINATE_Y: random() })) # Create edge between two vertex if there is a distance <= r for i in range(n): for j in range(n): # Calculate distance between two points p1 = (g.get_vertex(i).attributes[COORDINATE_X], g.get_vertex(i).attributes[COORDINATE_Y]) p2 = (g.get_vertex(j).attributes[COORDINATE_X], g.get_vertex(j).attributes[COORDINATE_Y]) d = calculate_distance(p1, p2) if d <= r: g.add_edge(edge.Edge(i, j), directed, auto) return g
def test_initialize_vertex(self): v = vertex.Vertex(1) self.assertEqual(1, v.id)
def test_add_vertice(self): g = graph.Graph() v = vertex.Vertex(1) g.add_vertex(v) self.assertEqual(1, len(g.vertices))