Alexandre B A Villares 2020-08-04 13:48:58 -03:00
rodzic ee57b186cc
commit 4c393cd798
5 zmienionych plików z 368 dodań i 0 usunięć

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 33 B

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 16 KiB

Wyświetl plik

@ -0,0 +1,272 @@
#*- coding: utf-8 -*-
"""
A simple Python graph class, demonstrating the essential facts and functionalities of graphs
based on https://www.python-course.eu/graphs_python.php and https://www.python.org/doc/essays/graphs/
"""
class Graph(object):
def __init__(self, graph_dict=None):
"""
Initialize a graph object with dictionary provided,
if none provided, create an empty one.
"""
if graph_dict is None:
graph_dict = {}
self.__graph_dict = graph_dict
def __len__(self):
return len(self.__graph_dict)
def __iter__(self):
return iter(self.__graph_dict.keys())
def __getitem__(self, i):
return self.__graph_dict[i]
def vertices(self):
"""Return the vertices of graph."""
return list(self.__graph_dict.keys())
def edges(self):
"""Return the edges of graph """
return self.__generate_edges()
def add_vertex(self, vertex):
"""
If the vertex "vertex" is not in self.__graph_dict,
add key "vertex" with an empty list as a value,
otherwise, do nothing.
"""
if vertex not in self.__graph_dict:
self.__graph_dict[vertex] = []
def add_edge(self, edge):
"""
Assuming that edge is of type set, tuple or list;
add edge between vertices. Can add multiple edges!
"""
edge = set(edge)
vertex1 = edge.pop()
if edge:
# not a loop
vertex2 = edge.pop()
if vertex1 in self.__graph_dict:
self.__graph_dict[vertex1].append(vertex2)
else:
self.__graph_dict[vertex1] = [vertex2]
if vertex2 in self.__graph_dict:
self.__graph_dict[vertex2].append(vertex1)
else:
self.__graph_dict[vertex2] = [vertex1]
else:
# a loop
if vertex1 in self.__graph_dict:
self.__graph_dict[vertex1].append(vertex1)
else:
self.__graph_dict[vertex1] = [vertex1]
def __generate_edges(self):
"""
Generate the edges, 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:
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_isolated_vertices(self):
"""
Return 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 find_path(self, start_vertex, end_vertex, path=[]):
"""
Find a path 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 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.
"""
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)
for p in extended_paths:
paths.append(p)
return paths
def is_connected(self,
vertices_encountered=None,
start_vertex=None):
"""Find 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 vertex_degree(self, vertex):
"""
Return the number of edges connecting to a vertex (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]
degree = len(adj_vertices) + adj_vertices.count(vertex)
return degree
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):
"""
Return True, if the sequence is a degree sequence (non-increasing),
otherwise return False.
"""
return all(x >= y for x, y in zip(sequence, sequence[1:]))
def delta(self):
"""Find minimum degree of 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):
"""Finde maximum degree of 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 density(self):
"""Calculate the graph density."""
g = self.__graph_dict
V = len(g.keys())
E = len(self.edges())
return 2.0 * E / (V * (V - 1))
def diameter(self):
"""Calculates the graph diameter."""
v = self.vertices()
pairs = [
(v[i],
v[j]) for i in range(
len(v)) for j in range(
i + 1,
len(v) - 1)]
smallest_paths = []
for (s, e) in pairs:
paths = self.find_all_paths(s, e)
smallest = sorted(paths, key=len)[0]
smallest_paths.append(smallest)
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
@staticmethod
def erdoes_gallai(dsequence):
"""
Check if Erdoes-Gallai inequality condition 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
# Code by Eryk Kopczyński
def find_shortest_path(self, start, end):
from collections import deque
graph = self.__graph_dict
dist = {start: [start]}
q = deque(start)
while len(q):
at = q.popleft()
for next in graph[at]:
if next not in dist:
#dist[next] = [dist[at], next]
dist[next] = dist[at]+[next] # less efficient but nicer output
q.append(next)
return dist.get(end)

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 208 KiB

Wyświetl plik

@ -0,0 +1,90 @@
from graph import Graph
MARGIN = 10
def setup():
global graph, grid
size(400, 400)
graph = random_graph()
grid = setup_grid(graph)
fill(0)
textAlign(CENTER, CENTER)
f = createFont("Source Code Pro Bold", 14)
textFont(f)
def draw():
background(200)
noFill()
stroke(255)
strokeWeight(4)
for v in grid.keys():
xa, ya, za = grid[v]
for e in graph[v]:
if e != v:
xb, yb, zb = grid[e]
line(xa + za, ya + za, xb + zb, yb + zb)
else:
circle(20 + xa + za, ya + za, 42)
for v in grid.keys():
x, y, z = grid[v]
fill(200)
stroke(0)
strokeWeight(2)
circle(x + z, y + z, 30)
fill(0)
text("{}:{}".format(v.upper(),graph.vertex_degree(v)), x + z, y + z - 3)
# saveFrame('sketch_2020_08_04a.png')
def setup_grid(graph):
cols, rows = dimensionar_grade(len(graph))
w, h = (width - MARGIN * 2) / cols, (height - MARGIN * 2) / rows
grid = {}
v_list = sorted(graph.vertices(), key=graph.vertex_degree)
c, r = 0, 0
next = None
while v_list:
if next is None:
next = v_list.pop()
else:
v_list.remove(next)
z = len(graph[next])
grid[next] = (MARGIN + w * 0.3 + c * w,
MARGIN + h * 0.3 + r * h,
z * w / 10)
for v in graph[next]:
if v in v_list:
next = v
break
else:
if v_list:
next = None
c += 1
if c == cols:
c = 0
r += 1
return grid
def random_graph(names="abcdefghijklmnop"):
from random import choice
graph = Graph()
for v in names:
graph.add_vertex(v)
if random(100) < 90:
graph.add_edge({v, choice(names)})
return graph
def dimensionar_grade(n):
a = int(sqrt(n))
b = n / a
if a * b < n:
b += 1
print(u'{}: {} × {} ({})'.format(n, a, b, a * b))
return a, b
def keyPressed():
global graph, grid
graph = random_graph()
grid = setup_grid(graph)
print(graph)

Wyświetl plik

@ -22,6 +22,12 @@
---
![sketch_2020_08_04a](2020/sketch_2020_08_04a/sketch_2020_08_04a.gif)
[sketch_2020_08_04a](https://github.com/villares/sketch-a-day/tree/master/2020/sketch_2020_08_04a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)]
---
![sketch_2020_08_03a](2020/sketch_2020_08_03a/sketch_2020_08_03a.png)
[sketch_2020_08_03a](https://github.com/villares/sketch-a-day/tree/master/2020/sketch_2020_08_03a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)]