From c78f66f5e4a5f12b588fccda97bbd11eb7d9f6bb Mon Sep 17 00:00:00 2001 From: codeboss <2422523675@qq.com> Date: Tue, 30 Jul 2024 22:30:59 +0800 Subject: [PATCH] update --- .idea/workspace.xml | 60 ++-- frame/ContentView.py | 4 + frame/MergeView.py | 3 +- frame/__pycache__/MergeView.cpython-312.pyc | Bin 4234 -> 4403 bytes graph/DataType.py | 51 ++++ graph/__init__.py | 0 graph/__pycache__/DataType.cpython-312.pyc | Bin 0 -> 3182 bytes graph/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 144 bytes graph/dagpresent/DAGGraph.py | 315 ++++++++++++++++++++ graph/dagpresent/__init__.py | 0 10 files changed, 404 insertions(+), 29 deletions(-) create mode 100644 frame/ContentView.py create mode 100644 graph/DataType.py create mode 100644 graph/__init__.py create mode 100644 graph/__pycache__/DataType.cpython-312.pyc create mode 100644 graph/__pycache__/__init__.cpython-312.pyc create mode 100644 graph/dagpresent/DAGGraph.py create mode 100644 graph/dagpresent/__init__.py diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 9ff407a..fef8eda 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,10 +5,13 @@ + + + + + - - - + - + + + + - - - + - + - diff --git a/frame/ContentView.py b/frame/ContentView.py new file mode 100644 index 0000000..6322abd --- /dev/null +++ b/frame/ContentView.py @@ -0,0 +1,4 @@ +from PyQt5.QtWidgets import QApplication, QWidget +from networkx import DiGraph +import networkx as nx + diff --git a/frame/MergeView.py b/frame/MergeView.py index 0b0613f..4519e79 100644 --- a/frame/MergeView.py +++ b/frame/MergeView.py @@ -22,10 +22,11 @@ class LinesMergeView(QWidget, MemorySkin): layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - splitter = QSplitter(Qt.Orientation.Vertical, self) + splitter = QSplitter(Qt.Orientation.Horizontal, self) layout.addWidget(splitter) self.tabs_con: QTabWidget = QTabWidget(self) + self.tabs_con.setTabPosition(QTabWidget.TabPosition.West) splitter.addWidget(self.tabs_con) self.define_prev: QTextEdit = QTextEdit(self) diff --git a/frame/__pycache__/MergeView.cpython-312.pyc b/frame/__pycache__/MergeView.cpython-312.pyc index fd48e7e387f266b60fdf631fce0c87bb61499529..20e055ed29bdaa4bf7963e30da6e893ad6a15fb7 100644 GIT binary patch delta 604 zcmeBD+^ocVnwOW00SHn&SESW$5@HZgB8j=a9I_Au&VZ3Ww4Y6}=TDmsLzUSbBJGaPai=cJf~5P`SvV zvLx!ds`W)x>+7lx7gZgua5!$B$Z5jFXgK*8w+6Qv&?!aYAi`wwPi{>{`^m~Yij4Z3 zU3nTA%|Md3xJ&W_auPH1LQ*SAicG*F#ffF9@g@23xv9BD4nUD&CLp1pP$UJUid-lE z;gx5!oGioF!DbH;SjDF)CBw>lK~C=j1CZV!a>35;qNV?55a+YaJ~naSH&K2PRnGc%V4sR4l+ zhSiKPRy-es1rp7Yfw2*Emi*)zHd98$$p^Sa#j(iOFlH%DzQ?90D+JS1!{ovco5H|Q z%T}Te6Pw(?F2+*BmZb$WMr5)VyP~8bObS8Qume?q43m)nxbR%)cBJ8_}tXoB3qzHF%ytbP$-fDQbkUam-5LoT1-C5*TH53 z5eVkjl#*uUy&$LefdNSG5V>IIchS=SGl=uqYVtJxuZ+QydjyR5^ci_4gwM$O!T@A^ KNSS;_ARPcdZf0-* diff --git a/graph/DataType.py b/graph/DataType.py new file mode 100644 index 0000000..5446d1d --- /dev/null +++ b/graph/DataType.py @@ -0,0 +1,51 @@ +from typing import List + + +class Pos: + def __init__(self, x: float = 0, y: float = 0): + self.x_pos = x + self.y_pos = y + pass + + def make_copy(self) -> 'Pos': + return Pos(self.x_pos, self.y_pos) + + +class Point: + def __init__(self, name:str, pos: Pos = Pos()): + self.point_name = name + self.pos = pos + pass + + def name(self) -> str: + return self.point_name + + def make_copy(self) -> 'Point': + return Point(self.point_name, self.pos.make_copy()) + + +class Line: + def __init__(self, p0: Point, p1: Point): + self.point_set = [p0, p1] + pass + + def points(self) -> List[Point]: + return self.point_set + + def make_copy(self) -> 'Line': + return Line(self.points()[0].make_copy(), self.points()[1].make_copy()) + + +class Arrow(Line): + def __init__(self, start: Point, end: Point): + Line.__init__(self, start, end) + pass + + def start_point(self): + return self.point_set[0] + + def end_point(self): + return self.point_set[1] + + pass + diff --git a/graph/__init__.py b/graph/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/graph/__pycache__/DataType.cpython-312.pyc b/graph/__pycache__/DataType.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ec0844b689a94b5f80fa1828ec4418745bd1eb2 GIT binary patch literal 3182 zcmb_eO>7fK6rR~Xubnt9#QZd+sZm4d5}KrewkRN^(x4tlLnPo(E9%O4Hza9dyR(bR zS`l#Y0i;R8V7yQ1#Gj@4X~SrKGF&)Dt%cQz3Ecdo$imyjWC49m#KI-u%6v z?|a@~lgR{uW?y+Y{h30@UpNVx+8i{l!k|hlV$pfBK(mw*iF`sVsX{DyRT8_h64xo9 zQ$wB1bsFemp-$mC9dvP9S(TfoRWD(5JjRJZePw*sar0tD$k3F2m{*BSveY73$C5v>Cm@pD;QGyu_ zW*%9g6NcogH_Q^;rFz&IvadMy{4~>G8;gN(@VZPU^L%J*bZU|n=j^=eOig<3OtCO^ z$t^PPavM^L5jlEzG*6S?&a52ZI^<>vV&-O}6&!zoUGe z2s*v90cw&DO@s*~PB?T9236vQYl~#AnI2dO8))%Fqy-7OL|7b_44I)34B^2#K&(*K z37vzNXIK)XA799QVVn74$tx$(`f!SeoC6?klRr{>mrhnk?~m5p@5&F#8>wS!`Z1P* zHHa%i>$rdzYs_}9vjTtC&@eKE+=6YIe!?^tiq`dc9Cw=Lm)CRi%@uWezL;}a7v8cL z#0udzbL)ip=mR?I^nj?4ZAn&>wIg)`-9xp3-O~hB2gEVl+#YskVPyw)60zk~&|sUU z06}FJ1XWA1m1)UR0fw5TTN?B+FJ{Djb+R~HaD4@h_hkUmtD{n+Nb(aUypjis9Rh10 zYnUYV1`1RJ$P^*LK$W|=86ng#6#>+GdI4&wt!_k|zNL4Hupkaw@P-iJ1j3*Kfyf;6 z(H7u{vR+tXdqC{M4!5wJ5T;;2(zuSc1L9NN_io+2wWjy-_gkLE6!E7&hrz2teGWMr zX+b`tG*B2iDSW_ya-6;34T7(n65fO?Kms@!5Xge`(&ego-(0qSnE8HYv;Wk3|EZ1s z(T&vUHT^Vq6X}4F=IsxnLs;FFuuwTqQE4I6mx4)V6L435Eb(K z@uAi8+X(jB#~k|0c@F(LK>w{J7(@3|qv{!P51wwJ0TKvX;{y;oG-#>43e;Z3R&Dup z*wYsNP}K{zFO`Pj_g;JGqo=$eOV_Xr!%Q?!)T9;a#|7XW+YO-J2V2+?5N)8I#3w_f zb3VKVI{{)nhiX@A2La|?{}0UBQ8Xh0a$n=tI^_;-hnQs0)E%JTynAy^fAb|k{}%Q~ zfQ|%+v;e*q#rV%5S|Tmj0c?HQdFkKI?-0b0CwT3CjP(H0@iuhq7zz%|NHDmv+{Ggi zQUs4UAA&%NbT5rnFWkTI&8N$U*VBEQ>B05%;6{4*QQyx4KMwr#?k{wGm7*>f)Myv6VS^+l$QMjNpF}==UxIBh2CEqd;yonNyb}AkF)A0^PFRz^<-SwYR3! zt~}^K;`AbMCaGW!p3cKBY$0>r0oBWxQz2Ou{xV2b^E4yos~<5|{K{7yH^*FGwhLAZ zVZtgn!moA1_u8d)5x;Px;7f~=CYhkzaE~!E0hfkg%!Wa<;ZhejDI^m*dJnO`B4}rclAddJ<1!ot`ja(c-=X(G$1}%WSl+ z526kQ78<7yM1=@++8mt^k8pH80dyXI0+2jh*N7Syu*72%@JXe)UTL;)jma<JmtkIamWj77{q761!aBE Point: + return self.bind_node + + def next_append(self, inst: 'DAGLayerHelper'): + self.next_points.append(inst) + inst.input_count += 1 + pass + + def next_nodes(self) -> List['DAGLayerHelper']: + return self.next_points + + def make_copy(self) -> 'DAGLayerHelper': + temp_ps = [] + for n in self.next_points: + temp_ps.append(n.make_copy()) + pass + + ins = DAGLayerHelper(self.bind_node.make_copy()) + ins.input_count = self.input_count + ins.next_points = temp_ps + ins.layer_v = self.layer_v + ins.sort_v = self.sort_v + return ins + + +class DAGOrderHelper: + def __init__(self, level:int = 0, relate:DAGLayerHelper|None = None, bind: DAGLayerHelper|None = None): + self.layer_bind = bind + self.relate_bind = relate + self.layer_number = level + self.sort_number:float = 0 + self.__prev_layer_nodes: List['DAGOrderHelper'] = [] + + if bind is not None: + self.layer_number = bind.layer_v + pass + pass + + def is_fake_node(self) -> bool: + return self.layer_bind is None + + def get_previous_sibling_layer_nodes(self): + return self.__prev_layer_nodes + + def append_previous_sibling_layer_node(self, node: 'DAGOrderHelper'): + self.__prev_layer_nodes.append(node) + pass + + +class DAGGraph: + def __init__(self, orie: Direction): + self.orientation = orie + self.graph_inst: Dict[str, DAGLayerHelper] = {} + self.nodes_with_layout: List[DAGOrderHelper] = [] + pass + + def rebuild_from_edges(self, arrow_list: List[Arrow]) -> None: + """ + 通过有序边构建有向图 + :param arrow_list: 有向边集合 + """ + for arr in arrow_list: + start = arr.start_point() + start_helper = None + if start.point_name in self.graph_inst: + start_helper = self.graph_inst[start.point_name] + else: + start_helper = DAGLayerHelper(start) + self.graph_inst[start.point_name] = start_helper + + end = arr.end_point() + end_helper = None + if end.point_name in self.graph_inst: + end_helper = self.graph_inst[end.point_name] + else: + end_helper = DAGLayerHelper(end) + self.graph_inst[end.point_name] = end_helper + + start_helper.next_append(end_helper) + pass + pass + + def __spawns_peak(self, refset: List[DAGLayerHelper]) -> Tuple[DAGLayerHelper, List[DAGLayerHelper]] | None: + """ + 拓扑排序迭代处理 + :param refset: + :return: + """ + for inst in refset: + if inst.input_count == 0: + for it_nxt in inst.next_nodes(): + refset.append(it_nxt) + it_nxt.input_count -= 1 + pass + + refset.remove(inst) + if inst.bind_point().point_name in self.graph_inst: + self.graph_inst.pop(inst.bind_point().point_name) + + return inst, refset + + for inst in self.graph_inst.values(): + if inst.input_count == 0: + if inst in refset: + refset.remove(inst) + + for it_nxt in inst.next_nodes(): + refset.append(it_nxt) + it_nxt.input_count -= 1 + pass + + self.graph_inst.pop(inst.bind_point().point_name) + return inst, refset + pass + + if len(self.graph_inst) > 0: + raise RuntimeError("有向无环图中发现环形结构!") + + return None + + def __graph_recovery(self, sort_seqs: List[DAGLayerHelper]) -> None: + """ + 通过拓扑排序结果恢复数据图 + :param sort_seqs: 有序序列 + """ + + # 清空cache + for it in sort_seqs: + it.input_count = 0 + pass + + # 入度复原 + for it in sort_seqs: + for nxt in it.next_nodes(): + nxt.input_count += 1 + pass + pass + + # 数据图恢复 + self.graph_inst.clear() + for it in sort_seqs: + self.graph_inst[it.bind_point().point_name] = it + pass + + pass + + def __node_layering(self, inst: DAGLayerHelper, layer_current: int = 0) -> int: + """ + 节点分层处理,返回路径最大长度 + :param inst: 当前节点 + :param layer_current: 节点等级 + :return: 最长路径长度 + """ + inst.layer_v = max(inst.layer_v, layer_current) + + max_remains = inst.layer_v + values = inst.next_nodes() + for fork in values: + max_remains = max(self.__node_layering(fork, inst.layer_v + 1), max_remains) + pass + + return max_remains + 1 + + def __tidy_graph_nodes(self) -> List[DAGOrderHelper]: + nodes_temp: Dict[str, DAGOrderHelper] = {} + + # 注册所有数据图实节点 + for node in self.graph_inst.values(): + nodes_temp[node.bind_point().point_name] = DAGOrderHelper(bind=node, relate=node) + pass + + temp_array: List[DAGOrderHelper] = [] + temp_array.extend(nodes_temp.values()) + + # 生成链接fake-node节点,并执行链接 + for node in self.graph_inst.values(): + for next in node.next_nodes(): + node_links = [nodes_temp[node.bind_point().point_name]] + for layer_index in range(node.layer_v + 1, next.layer_v): + node_links.append(DAGOrderHelper(layer_index, relate=node)) + pass + + node_links.append(nodes_temp[next.bind_point().point_name]) + + # 节点链接串已经构建完成,链接各层级节点 + for idx in range(1, len(node_links)): + start_point = node_links[idx-1] + end_point = node_links[idx] + end_point.append_previous_sibling_layer_node(start_point) + pass + + temp_array.extend(node_links[1:len(node_links)-1]) + pass + pass + + return temp_array + + def __graph_layer_nodes_sort(self, layer_index:int, nodes: List[DAGOrderHelper]): + # 提取当前层次的节点 + target_nodes_within_layer = [] + for n in nodes: + if n.layer_number == layer_index: + target_nodes_within_layer.append(n) + pass + pass + + # 当前层次没有节点,则不做处理 + if len(target_nodes_within_layer) == 0: + return + + if layer_index == 0: + for idx in range(0, len(target_nodes_within_layer)): + target_nodes_within_layer[idx].sort_number = idx + pass + pass + + elif layer_index > 0: + # 计算排序系数 + for target_node in target_nodes_within_layer: + prev_sorts = list(map(lambda n:n.sort_number, target_node.get_previous_sibling_layer_nodes())) + target_node.sort_number = sum(prev_sorts)/len(prev_sorts) + pass + + def compare_item(a: DAGOrderHelper): + return a.sort_number + + # 整理节点排序 + target_nodes_within_layer.sort(key=compare_item) + for idx in range(0, len(target_nodes_within_layer)): + target_nodes_within_layer[idx].sort_number = idx + pass + + pass + + self.__graph_layer_nodes_sort(layer_index + 1, nodes) + pass + + + def graph_layout(self): + sort_seqs = [] + + # 拓扑排序 + head = None + refs = [] + while True: + peaks_result = self.__spawns_peak(refs) + if peaks_result is None: + break + + head, refs = peaks_result + sort_seqs.append(head) + pass + + # 数据图恢复 + self.__graph_recovery(sort_seqs) + + # 数据图节点分层 + max_length = 0 + for item in sort_seqs: + if item.input_count == 0: + max_length = max(max_length, self.__node_layering(item)) + pass + pass + + # 整理数据图节点 + rich_nodes = self.__tidy_graph_nodes() + self.__graph_layer_nodes_sort(0, rich_nodes) + self.nodes_with_layout = rich_nodes + + pass + + def visible_nodes(self) -> List[DAGOrderHelper]: + retvs = [] + for n in self.nodes_with_layout: + if not n.is_fake_node(): + retvs.append(n) + pass + pass + return retvs + + +if __name__ == "__main__": + graph = DAGGraph(Direction.RankLR) + arrows = [ + Arrow(Point('a'), Point('b')), + Arrow(Point('a'), Point('c')), + Arrow(Point('c'), Point('d')), + Arrow(Point('a'), Point('d')), + ] + graph.rebuild_from_edges(arrows) + + graph.graph_layout() + + points = graph.visible_nodes() + for p in points: + print(f"{p.layer_bind.bind_point().point_name},level{p.layer_number},sort{p.sort_number}") \ No newline at end of file diff --git a/graph/dagpresent/__init__.py b/graph/dagpresent/__init__.py new file mode 100644 index 0000000..e69de29