From 7acc193daf87a21166778b7b8370c61cdea230cf Mon Sep 17 00:00:00 2001 From: KmolYuan Date: Sun, 30 Jun 2019 15:08:15 +0800 Subject: [PATCH] Add a counter for graph atlas. --- .../Ui_structure_widget.py | 1 + .../synthesis/structure_synthesis/__init__.py | 96 +++++++++---------- .../structure_synthesis/structure_widget.ui | 5 + core/synthesis/structure_synthesis/thread.py | 29 +++--- 4 files changed, 71 insertions(+), 60 deletions(-) diff --git a/core/synthesis/structure_synthesis/Ui_structure_widget.py b/core/synthesis/structure_synthesis/Ui_structure_widget.py index d9d730fc3..1ed693e69 100644 --- a/core/synthesis/structure_synthesis/Ui_structure_widget.py +++ b/core/synthesis/structure_synthesis/Ui_structure_widget.py @@ -251,6 +251,7 @@ def retranslateUi(self, Form): self.number_synthesis_button.setStatusTip(_translate("Form", "Find the possible number of different joints.")) self.number_synthesis_button.setText(_translate("Form", "Number Synthesis")) self.link_assortment_list.headerItem().setText(0, _translate("Form", "Link Assortment / Contracted Link Assortment")) + self.link_assortment_list.headerItem().setText(1, _translate("Form", "Count")) self.graph_engine_text.setText(_translate("Form", "Engine: ")) self.graph_engine.setStatusTip(_translate("Form", "Layout engine from NetworkX.")) self.reload_atlas.setToolTip(_translate("Form", "Re-layout")) diff --git a/core/synthesis/structure_synthesis/__init__.py b/core/synthesis/structure_synthesis/__init__.py index cb4ae1c0a..2d6a63c03 100644 --- a/core/synthesis/structure_synthesis/__init__.py +++ b/core/synthesis/structure_synthesis/__init__.py @@ -13,11 +13,9 @@ from typing import ( TYPE_CHECKING, - Tuple, List, Sequence, Dict, - Iterable, Optional, ) from time import time @@ -43,15 +41,20 @@ QScrollBar, QListWidgetItem, QTreeWidgetItem, + QHeaderView, ) from core.libs import ( VJoint, Graph, - link_assortment as l_a, - contracted_link_assortment as c_l_a, + link_assortment, + contracted_link_assortment, ) from core.graphics import to_graph, engines -from .thread import LinkSynthesisThread, GraphEnumerateThread +from .thread import ( + assortment_eval, + LinkSynthesisThread, + GraphEnumerateThread, +) from .Ui_structure_widget import Ui_Form if TYPE_CHECKING: @@ -62,20 +65,6 @@ Assortment = Sequence[int] -def _link_assortment(links_expr: str) -> Assortment: - """Return link assortment from expr.""" - return tuple(int(n.split('=')[-1]) for n in links_expr.split(", ")) - - -def compare_assortment(first: Tuple[int, ...], second: Sequence[Tuple[int, ...]]) -> int: - """Compare assortment.""" - my_len = len(first) - for i, job in enumerate(second): - if job == first + (0,) * (len(job) - my_len): - return i - return -1 - - class SynthesisProgressDialog(QProgressDialog): """Progress dialog for structure synthesis.""" @@ -118,6 +107,7 @@ def __init__(self, parent: MainWindowBase): """ super(StructureSynthesis, self).__init__(parent) self.setupUi(self) + self.link_assortment_list.header().setSectionResizeMode(QHeaderView.ResizeToContents) # Function references self.output_to = parent.output_to @@ -286,11 +276,11 @@ def update_result(assortment: Dict[Assortment, List[Assortment]]): for la, cla_list in assortment.items(): la_item = QTreeWidgetItem([", ".join( f"NL{i + 2} = {a}" for i, a in enumerate(la) - )]) + ), "N/A"]) for cla in cla_list: la_item.addChild(QTreeWidgetItem([", ".join( f"NC{i + 1} = {a}" for i, a in enumerate(cla) - )])) + ), "N/A"])) self.link_assortment_list.addTopLevelItem(la_item) first_item = self.link_assortment_list.topLevelItem(0) self.link_assortment_list.setCurrentItem(first_item) @@ -323,54 +313,64 @@ def __structure_synthesis(self): root = item.parent() if root is None: # Find by link assortment - _l_a = _link_assortment(item.text(0)) - self.__structural_combine( - ((_l_a, _c_l_a) for _c_l_a in self.assortment[_l_a]), - len(self.assortment[_l_a]) - ) - else: - # Find by contracted link assortment try: - _l_a = _link_assortment(root.text(0)) - _c_l_a = _link_assortment(item.text(0)) + # Test + assortment_eval(item.text(0)) except ValueError: return - self.__structural_combine(((_l_a, _c_l_a),), 1) + jobs = [item.child(i) for i in range(item.childCount())] + self.__structural_combine(jobs) + else: + # Find by contracted link assortment + jobs = [item] + self.__structural_combine(jobs) @Slot(name='on_structure_synthesis_all_button_clicked') def __structure_synthesis_all(self): """Structural synthesis - find all.""" self.__clear_structure_list() - - def iterator(): - for k, v in self.assortment.items(): - for s in v: - yield (k, s) - - self.__structural_combine(iterator(), sum(len(l) for l in self.assortment.values())) - - def __structural_combine( - self, - jobs: Iterable[Tuple[Assortment, Assortment]], - count: int - ): + jobs = [] + for i in range(self.link_assortment_list.topLevelItemCount()): + root: QTreeWidgetItem = self.link_assortment_list.topLevelItem(i) + for j in range(root.childCount()): + jobs.append(root.child(j)) + self.__structural_combine(jobs) + + def __structural_combine(self, jobs: Sequence[QTreeWidgetItem]): """Structural combine by iterator.""" t0 = time() dlg = SynthesisProgressDialog( "Structural Synthesis", - f"Number of cases: {count}", - count, + f"Number of cases: {len(jobs)}", + len(jobs), self ) + @Slot(QTreeWidgetItem, int) + def update_count(item: QTreeWidgetItem, count: int): + """Update the number of graphs.""" + item.setText(1, f"{count}") + @Slot(list) def update_result(answer: List[Graph]): + """Update the result of atlas.""" self.answer = answer dlg.deleteLater() + for i in range(self.link_assortment_list.topLevelItemCount()): + root: QTreeWidgetItem = self.link_assortment_list.topLevelItem(i) + count = 0 + for j in range(root.childCount()): + item = root.child(j) + try: + count += int(item.text(1)) + except ValueError: + pass + root.setText(1, f"{count}") self.__set_time_count(time() - t0, len(self.answer)) self.__reload_atlas() work = GraphEnumerateThread(jobs, self.graph_degenerate.currentIndex(), dlg) + work.count_update.connect(update_count) work.progress_update.connect(dlg.setValue) work.result.connect(update_result) dlg.show() @@ -425,8 +425,8 @@ def __draw_atlas(self, i: int, g: Graph) -> bool: )) item.setToolTip( f"Edge Set: {list(g.edges)}\n" - f"Link assortment: {l_a(g)}\n" - f"Contracted Link assortment: {c_l_a(g)}" + f"Link assortment: {link_assortment(g)}\n" + f"Contracted Link assortment: {contracted_link_assortment(g)}" ) self.structure_list.addItem(item) return True diff --git a/core/synthesis/structure_synthesis/structure_widget.ui b/core/synthesis/structure_synthesis/structure_widget.ui index 06f02f731..4d61f1307 100644 --- a/core/synthesis/structure_synthesis/structure_widget.ui +++ b/core/synthesis/structure_synthesis/structure_widget.ui @@ -238,6 +238,11 @@ Link Assortment / Contracted Link Assortment + + + Count + + diff --git a/core/synthesis/structure_synthesis/thread.py b/core/synthesis/structure_synthesis/thread.py index f1c89ffa6..ceb4b8f63 100644 --- a/core/synthesis/structure_synthesis/thread.py +++ b/core/synthesis/structure_synthesis/thread.py @@ -7,9 +7,9 @@ __license__ = "AGPL" __email__ = "pyslvs@gmail.com" -from typing import Tuple, Sequence, Iterable +from typing import Sequence from core.synthesis.thread import BaseThread -from core.QtModules import Signal, QWidget +from core.QtModules import Signal, QWidget, QTreeWidgetItem from core.libs import ( link_synthesis, contracted_link_synthesis, @@ -20,6 +20,11 @@ Assortment = Sequence[int] +def assortment_eval(links_expr: str) -> Assortment: + """Return link assortment from expr.""" + return tuple(int(n.split('=')[-1]) for n in links_expr.split(", ")) + + class LinkSynthesisThread(BaseThread): """Link assortment synthesis thread.""" @@ -59,14 +64,10 @@ class GraphEnumerateThread(BaseThread): """Graphs enumeration thread.""" progress_update = Signal(int) + count_update = Signal(QTreeWidgetItem, int) result = Signal(list) - def __init__( - self, - jobs: Iterable[Tuple[Assortment, Assortment]], - degenerate: int, - parent: QWidget - ): + def __init__(self, jobs: Sequence[QTreeWidgetItem], degenerate: int, parent: QWidget): super(GraphEnumerateThread, self).__init__(parent) self.jobs = jobs self.degenerate = degenerate @@ -75,20 +76,24 @@ def run(self): """Run and return conventional graph.""" cg_list = {} answers = [] - for i, (la, cla) in enumerate(self.jobs): + for i, item in enumerate(self.jobs): if self.is_stop: break + root = item.parent() + la = assortment_eval(root.text(0)) + cla = assortment_eval(item.text(0)) if la not in cg_list: cg_list[la] = contracted_graph(la, lambda: self.is_stop) - answers.extend(conventional_graph( + answer = conventional_graph( cg_list[la], cla, self.degenerate, lambda: self.is_stop - )) - + ) + self.count_update.emit(item, len(answer)) + answers.extend(answer) self.progress_update.emit(1 + i) self.result.emit(answers)