graph.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import numpy as np
  2. from verticle import verticle
  3. import matplotlib.pyplot as plt
  4. from matplotlib.patches import FancyArrowPatch
  5. from functools import singledispatch
  6. class Graph:
  7. '''
  8. Graph by matrix
  9. '''
  10. __verticles = []
  11. __edges = []
  12. matrix = []
  13. def __init__(self, verticles, matrix):
  14. self.verticles = verticles
  15. self.matrix = matrix
  16. @singledispatch
  17. def build(structs) -> "Graph":
  18. raise Exception("Конструктор не работает")
  19. @build.register
  20. @staticmethod
  21. def build_verticles(verticles: dict):
  22. matrix = []
  23. for vert in verticles:
  24. to = verticles[vert]
  25. matrix.append( [1 if x in to else 0 for x in verticles] )
  26. matrix = np.array(matrix)
  27. return Graph(verticles, matrix)
  28. @build.register
  29. @staticmethod
  30. def build_matrix(matrix: np.ndarray):
  31. return Graph([str(i) for i in range(matrix.shape[0])], matrix)
  32. @build.register
  33. @staticmethod
  34. def build_matrix(matrix: list):
  35. return Graph([str(i) for i in range(len(matrix))], np.array(matrix))
  36. def __eq__(self, __o: object) -> bool:
  37. return np.array_equal(self.matrix, __o.matrix)
  38. def __and__(self, __o: "Graph"):
  39. result = self.copy()
  40. result.matrix = (self.matrix+__o.matrix==2).astype(int)
  41. return result
  42. def __or__(self, __o: "Graph"):
  43. result = self.copy()
  44. result.matrix = (self.matrix+__o.matrix>0).astype(int)
  45. return result
  46. def __sub__(self, __o: "Graph"):
  47. result = self.copy()
  48. result.matrix = (self.matrix-__o.matrix>0).astype(int)
  49. return result
  50. def __xor__(self, __o: "Graph"):
  51. result = self.copy()
  52. result.matrix = (self.matrix!=__o.matrix).astype(int)
  53. return result
  54. def __str__(self):
  55. result = " "+"".join([str(node) for node in self.verticles])+"\n"
  56. for i,row in enumerate(self.matrix):
  57. result += str(self.verticles[i]) + " " + "".join(map(str,row))+"\n"
  58. return result
  59. def __invert__(self):
  60. result = self.copy()
  61. result.matrix = (self.matrix==0).astype(int)
  62. return result
  63. def set(self, indexes: list[int]):
  64. '''
  65. Меняет вершины по заданым индексам.
  66. '''
  67. if len(indexes) != len(self.verticles):
  68. raise IndexError(f"indexes must be len of {len(self.verticles)}")
  69. new_matrix = self.matrix[indexes]
  70. self.matrix = new_matrix[:, indexes]
  71. self.__verticles = [self.verticles[x] for x in indexes]
  72. def replace(self, fro:str|verticle, to:str|verticle):
  73. '''
  74. Меняет 2 переданные вершины графа местами.
  75. '''
  76. index_fro = self.verticles.index(str(fro))
  77. index_to = self.verticles.index(str(to))
  78. indexes = [index_to if i==index_fro else index_fro if i==index_to else i for i in range(len(self.verticles))]
  79. self.set(indexes)
  80. def copy(self):
  81. return Graph(self.dict)
  82. def plot(self, x=0, y=0):
  83. '''
  84. x,y - смещение построения графа, если координаты вершин не заданы
  85. '''
  86. if not isinstance(self.verticles[0], verticle):
  87. print("Перепись " + "="*32)
  88. space = np.linspace(0, 2*np.pi, len(self.verticles)+1)[:-1]
  89. self.__verticles = [verticle(name, np.cos(sp)+x, np.sin(sp)+y) for name, sp in zip(self.verticles, space)]
  90. print([vert.name for vert in self.verticles])
  91. print([vert.x for vert in self.verticles])
  92. print([vert.y for vert in self.verticles])
  93. for i,row in enumerate(self.matrix):
  94. for j,elem in enumerate(row):
  95. if elem == 0: continue
  96. print(i, j ,elem)
  97. print(self.verticles[i].x, self.verticles[i].y, self.verticles[j].x, self.verticles[j].y)
  98. plt.arrow(self.verticles[i].x, self.verticles[i].y,
  99. (self.verticles[j].x-self.verticles[i].x)*0.93, (self.verticles[j].y-self.verticles[i].y)*0.93,
  100. head_width=0.035, head_length=0.035, arrowstyle='->')
  101. print(self.verticles)
  102. x = [v.x for v in self.verticles]
  103. y = [v.y for v in self.verticles]
  104. plt.scatter(x,y, c='red', zorder=1)
  105. @property
  106. def dict(self):
  107. review = {}
  108. if isinstance(self.__verticles[0],verticle): n_vert = [verticle(vert.name, vert.x, vert.y) for vert in self.verticles]
  109. else: n_vert = self.__verticles
  110. for vert, row in zip(n_vert, self.matrix):
  111. if isinstance(vert,verticle):
  112. review[vert] = [n_vert[i] for i,sym in enumerate(row) if sym]
  113. else:
  114. review[vert] = ''.join([self.__verticles[i] for i,sym in enumerate(row) if sym])
  115. return review
  116. @property
  117. def verticles(self):
  118. return self.__verticles
  119. @verticles.setter
  120. def verticles(self, verts):
  121. self.__verticles = verts
  122. if __name__ == "__main__":
  123. # g = Graph({'a':'ad','b':'ad','c':'bc','d':'bc', 'e':'ac', 'f':'bd'})
  124. # h = Graph({'a':'bd','b':'bc','c':'bc','d':'ac'})
  125. # print("graph G1:",g,sep="\n")
  126. # print("graph H1:",h,sep="\n")
  127. # print("graph G1 and H1:",g&h,sep="\n")
  128. # print("graph G1 or H1:",g|h,sep="\n")
  129. # print("graph G1 / H1:",g-h,sep="\n")
  130. # print("graph G1 xor H1:",g^h,sep="\n")
  131. # print("Invert G1:",~g)
  132. # g.plot(1, 1)
  133. # h.plot(3.2, 1)
  134. g = Graph.build([[0, 1, 1, 1, 1],
  135. [1, 0, 1, 1, 1],
  136. [1, 1, 0, 1, 1],
  137. [1, 1, 1, 0, 1],
  138. [1, 1, 1, 1, 0]])
  139. g.plot()
  140. print(g)
  141. plt.show()