import numpy as np from verticle import verticle import matplotlib.pyplot as plt from matplotlib.patches import FancyArrowPatch from functools import singledispatch class Graph: ''' Graph by matrix ''' __verticles = [] __edges = [] matrix = [] def __init__(self, verticles, matrix): self.verticles = verticles self.matrix = matrix @singledispatch def build(structs) -> "Graph": raise Exception("Конструктор не работает") @build.register @staticmethod def build_verticles(verticles: dict): matrix = [] for vert in verticles: to = verticles[vert] matrix.append( [1 if x in to else 0 for x in verticles] ) matrix = np.array(matrix) return Graph(verticles, matrix) @build.register @staticmethod def build_matrix(matrix: np.ndarray): return Graph([str(i) for i in range(matrix.shape[0])], matrix) @build.register @staticmethod def build_matrix(matrix: list): return Graph([str(i) for i in range(len(matrix))], np.array(matrix)) def __eq__(self, __o: object) -> bool: return np.array_equal(self.matrix, __o.matrix) def __and__(self, __o: "Graph"): result = self.copy() result.matrix = (self.matrix+__o.matrix==2).astype(int) return result def __or__(self, __o: "Graph"): result = self.copy() result.matrix = (self.matrix+__o.matrix>0).astype(int) return result def __sub__(self, __o: "Graph"): result = self.copy() result.matrix = (self.matrix-__o.matrix>0).astype(int) return result def __xor__(self, __o: "Graph"): result = self.copy() result.matrix = (self.matrix!=__o.matrix).astype(int) return result def __str__(self): result = " "+"".join([str(node) for node in self.verticles])+"\n" for i,row in enumerate(self.matrix): result += str(self.verticles[i]) + " " + "".join(map(str,row))+"\n" return result def __invert__(self): result = self.copy() result.matrix = (self.matrix==0).astype(int) return result def set(self, indexes: list[int]): ''' Меняет вершины по заданым индексам. ''' if len(indexes) != len(self.verticles): raise IndexError(f"indexes must be len of {len(self.verticles)}") new_matrix = self.matrix[indexes] self.matrix = new_matrix[:, indexes] self.__verticles = [self.verticles[x] for x in indexes] def replace(self, fro:str|verticle, to:str|verticle): ''' Меняет 2 переданные вершины графа местами. ''' index_fro = self.verticles.index(str(fro)) index_to = self.verticles.index(str(to)) indexes = [index_to if i==index_fro else index_fro if i==index_to else i for i in range(len(self.verticles))] self.set(indexes) def copy(self): return Graph(self.dict) def plot(self, x=0, y=0): ''' x,y - смещение построения графа, если координаты вершин не заданы ''' if not isinstance(self.verticles[0], verticle): print("Перепись " + "="*32) space = np.linspace(0, 2*np.pi, len(self.verticles)+1)[:-1] self.__verticles = [verticle(name, np.cos(sp)+x, np.sin(sp)+y) for name, sp in zip(self.verticles, space)] print([vert.name for vert in self.verticles]) print([vert.x for vert in self.verticles]) print([vert.y for vert in self.verticles]) for i,row in enumerate(self.matrix): for j,elem in enumerate(row): if elem == 0: continue print(i, j ,elem) print(self.verticles[i].x, self.verticles[i].y, self.verticles[j].x, self.verticles[j].y) plt.arrow(self.verticles[i].x, self.verticles[i].y, (self.verticles[j].x-self.verticles[i].x)*0.93, (self.verticles[j].y-self.verticles[i].y)*0.93, head_width=0.035, head_length=0.035, arrowstyle='->') print(self.verticles) x = [v.x for v in self.verticles] y = [v.y for v in self.verticles] plt.scatter(x,y, c='red', zorder=1) @property def dict(self): review = {} if isinstance(self.__verticles[0],verticle): n_vert = [verticle(vert.name, vert.x, vert.y) for vert in self.verticles] else: n_vert = self.__verticles for vert, row in zip(n_vert, self.matrix): if isinstance(vert,verticle): review[vert] = [n_vert[i] for i,sym in enumerate(row) if sym] else: review[vert] = ''.join([self.__verticles[i] for i,sym in enumerate(row) if sym]) return review @property def verticles(self): return self.__verticles @verticles.setter def verticles(self, verts): self.__verticles = verts if __name__ == "__main__": # g = Graph({'a':'ad','b':'ad','c':'bc','d':'bc', 'e':'ac', 'f':'bd'}) # h = Graph({'a':'bd','b':'bc','c':'bc','d':'ac'}) # print("graph G1:",g,sep="\n") # print("graph H1:",h,sep="\n") # print("graph G1 and H1:",g&h,sep="\n") # print("graph G1 or H1:",g|h,sep="\n") # print("graph G1 / H1:",g-h,sep="\n") # print("graph G1 xor H1:",g^h,sep="\n") # print("Invert G1:",~g) # g.plot(1, 1) # h.plot(3.2, 1) g = Graph.build([[0, 1, 1, 1, 1], [1, 0, 1, 1, 1], [1, 1, 0, 1, 1], [1, 1, 1, 0, 1], [1, 1, 1, 1, 0]]) g.plot() print(g) plt.show()