123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- 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()
|