diff --git a/NodeLibrary.py b/NodeLibrary.py index 4348c7e..3d04bdc 100644 --- a/NodeLibrary.py +++ b/NodeLibrary.py @@ -1,5 +1,6 @@ import abc import copy +import itertools from collections import Counter from itertools import permutations from typing import * @@ -112,6 +113,7 @@ def state_visualization(self, n: DiagramNode) -> None: del t["BLOCK"] n.label += "\n" + str(t) n.height += 20 + n.height = min(400, n.height) elif n.tokens_display == 'count only': if len(n.sync) > 0: n.label += "\n %d tokens" % len(n.sync) @@ -131,12 +133,13 @@ def synchronization(self, tokens: Sequence[Dict], sync: Sequence[Dict], node: Di t['REQ'] = eval(node.req, globals(), t) if node.wait != "[]": - w=eval(node.wait, globals(), t) - t['WAIT']=w if callable(w) else self.genF(w) + print(t) + w = eval(node.wait, globals(), t) + t['WAIT'] = w if callable(w) else self.genF(w) if node.block != "[]": - b=eval(node.block, globals(), t) - t['BLOCK']=b if callable(b) else self.genF(b) + b = eval(node.block, globals(), t) + t['BLOCK'] = b if callable(b) else self.genF(b) if node.tokens_display != 'full with event': if 'event' in t: @@ -154,20 +157,20 @@ def type_string(self) -> str: return "loop" def node_manipulator(self, node: DiagramNode) -> None: - node.label='LOOP' + node.label = 'LOOP' node.label += "\ncount:" + node.count super().node_manipulator(node) def transformation(self, tokens: Sequence[Dict], node: DiagramNode, port: str) -> Sequence[Dict]: - nxtt=[] + nxtt = [] for pt in tokens: - t=copy.deepcopy(pt) + t = copy.deepcopy(pt) try: - t["COUNT"]=t["COUNT"] - 1 + t["COUNT"] = t["COUNT"] - 1 except KeyError: - t["COUNT"]=int(node.count) + t["COUNT"] = int(node.count) if port == 'after': if t["COUNT"] == 0: @@ -196,22 +199,22 @@ def type_string(self) -> str: return "permutation" def node_manipulator(self, node: DiagramNode) -> None: - node.label='PERMUTATION' + node.label = 'PERMUTATION' node.label += "\nkeys:" + node.keys super().node_manipulator(node) def transformation(self, tokens: Sequence[Dict], node: DiagramNode, port: str) -> Sequence[Dict]: - ret=[] + ret = [] for t in tokens: - keys=eval(node.keys, globals(), t) - values=[t[k] for k in keys] - pvalues=permutations(values) + keys = eval(node.keys, globals(), t) + values = [t[k] for k in keys] + pvalues = permutations(values) for pval in pvalues: - t=copy.deepcopy(t) + t = copy.deepcopy(t) for k in range(len(pval)): - t[keys[k]]=pval[k] + t[keys[k]] = pval[k] ret.append(t) return ret @@ -224,13 +227,13 @@ def type_string(self) -> str: return "join" def node_manipulator(self, node: DiagramNode) -> None: - node.label='JOIN\nCOUNT=%s' % node.count - node.log=[] + node.label = 'JOIN\nCOUNT=%s' % node.count + node.log = [] super().node_manipulator(node) def state_visualization(self, n: DiagramNode) -> None: - n.label=n.org_label - n.height=50 + n.label = n.org_label + n.height = 50 n.label += "\n---------------------" for t in n.log: @@ -238,34 +241,37 @@ def state_visualization(self, n: DiagramNode) -> None: n.height += 20 def get_groups(self, node: DiagramNode): - ret=[] + ret = [] - join_by=eval(node.join_by) - def joinby(t): return [t[i] for i in join_by] + join_by = eval(node.join_by) + + def joinby(t): + return [t[i] for i in join_by] node.log.sort(key=joinby) - join=None + join = None for t in node.log: if joinby(t) != join: - join=joinby(t) - group=[t] + join = joinby(t) + group = [t] else: group.append(t) - if(len(group) >= eval(node.count)): + if (len(group) >= eval(node.count)): ret.append(group) return ret - def synchronization(self, tokens: Sequence[Dict], sync: Sequence[Dict], node: DiagramNode) -> (Sequence[Dict], Sequence[Dict]): - if len(tokens) is not 0: + def synchronization(self, tokens: Sequence[Dict], sync: Sequence[Dict], node: DiagramNode) -> ( + Sequence[Dict], Sequence[Dict]): + if len(tokens) != 0: node.log.extend(tokens) return (tokens, []) # TODO change this node to work like WaitForSetType - i.e., without using transformation. def transformation(self, tokens: Sequence[Dict], node: DiagramNode, port: str) -> Sequence[Dict]: - groups=self.get_groups(node) + groups = self.get_groups(node) if len(groups) != 0: for g in groups: for t in g: @@ -286,17 +292,17 @@ def type_string(self) -> str: return "waitforset" def node_manipulator(self, node: DiagramNode) -> None: - node.label="ANY " + node.threshold + " OF \n" + node.set - node.set=eval(node.set) - node.visited=[] - node.threshold=int(node.threshold) + node.label = "ANY " + node.threshold + " OF \n" + node.set + node.set = eval(node.set) + node.visited = [] + node.threshold = int(node.threshold) # node.width = 400 - node.height=100 + node.height = 100 super().node_manipulator(node) def state_visualization(self, n: DiagramNode) -> None: - n.label=n.org_label - n.height=80 + n.label = n.org_label + n.height = 80 n.label += "\n---------------------" n.label += "\nhistory=" + str(n.visited) @@ -308,13 +314,95 @@ def transformation(self, tokens: Sequence[Dict], node: DiagramNode, port: str) - node.visited += [t for t in tokens if t in node.set and t not in node.visited] if len(node.visited) >= node.threshold: - tmp=node.visited - node.visited=[] + tmp = node.visited + node.visited = [] return [{'subset': tmp}] else: return [] +###################################################################################### +class WaitAll(NodeType): + + def type_string(self) -> str: + return "waitall" + + def node_manipulator(self, node: DiagramNode) -> None: + node.label = "WAIT All OF\n" + node.waitall + # node.waitall =[] if node.waitall == '[]' else node.waitall.split(",") + node.width = 400 + node.height = 300 + super().node_manipulator(node) + + def state_visualization(self, n: DiagramNode) -> None: + n.label = n.org_label + "\n-----------" + n.height = 300 + if n.tokens_display == 'full' or n.tokens_display == 'full with event': + for t in n.sync: + t = copy.deepcopy(t) + # if "WAITALL" in t: + # del t["WAITALL"] + if "WAIT" in t: + del t["WAIT"] + n.label += "\n" + str(t) + n.height += 20 + elif n.tokens_display == 'count only': + if len(n.sync) > 0: + n.label += "\n %d tokens" % len(n.sync) + else: + raise Exception("Illegal value for 'tokens_display': " + n.tokens_display) + + def genF(self, l): + return lambda e: True in [e in le for le in l] + + def synchronization(self, tokens: Sequence[Dict], sync: Sequence[Dict], node: DiagramNode) -> Sequence[Dict]: + sync = copy.deepcopy(sync) + for t in tokens: + t = copy.deepcopy(t) + + if node.waitall is not "[]": + if "WAITALL" not in t.keys(): + t['WAITALL']= eval(node.waitall, globals(), t) + + t['WAIT'] =(lambda w : w if callable(w) else self.genF(w))(list(itertools.chain(copy.deepcopy(t['WAITALL'])))) # need to be the union + # t['WAITALL']= [(lambda w :w if callable(w) else self.genF(w))(eval(w, globals(), t)) for w in node.waitall] + + sync.append(t) + + # try: + # t["COUNT"] = t["COUNT"] - 1 + # except KeyError: + # t["COUNT"] = int(node.count) + + return (sync, sync) + + def transformation(self, tokens: Sequence[Dict], node: DiagramNode, port: str) -> Sequence[Dict]: + nxtt = [] + + for t in tokens: + + + try: + e = t["event"] + t["le"] = e + if e is not None: + del t["event"] + for waitlist in t["WAITALL"]: + waitlist.remove(e) + if len(waitlist) == 0: + nxtt.append(copy.deepcopy(t)) + + except KeyError: + pass + + + + # if not t["WAITALL"]: + # nxtt.append(t) + + return nxtt + + ###################################################################################### class LoggerType(NodeType): @@ -322,13 +410,13 @@ def type_string(self) -> str: return "logger" def node_manipulator(self, node: DiagramNode) -> None: - node.label='LOG' - node.log=[] + node.label = 'LOG' + node.log = [] super().node_manipulator(node) def state_visualization(self, n: DiagramNode) -> None: - n.label=n.org_label - n.height=50 + n.label = n.org_label + n.height = 50 n.label += "\n---------------------" for t in n.log: diff --git a/Tests/TTT.png b/Tests/TTT.png index 1854aa4..889b938 100644 Binary files a/Tests/TTT.png and b/Tests/TTT.png differ diff --git a/Tests/TTT2.flow b/Tests/TTT2.flow index dee18e9..615d214 100644 --- a/Tests/TTT2.flow +++ b/Tests/TTT2.flow @@ -1,9 +1,9 @@ blockdiag { st -> join -> req; - st [type=start, initial="[{1:'1'},{2:'2'},{3:'3'}]"]; + st [type=start, initial="[{1:'1'},{2:'2'},{third:'3'}]"]; join [type=join] - req [type=sync, req="['O'+t[3]]"] + req [type=sync, req="['O'+third]"] diff --git a/Tests/TTT_maor.flow b/Tests/TTT_maor.flow new file mode 100644 index 0000000..d412cb7 --- /dev/null +++ b/Tests/TTT_maor.flow @@ -0,0 +1,53 @@ +blockdiag { +initialization_code=" +global X +X = lambda i : 'X'+str(i) + +global O +O=lambda i : 'O'+str(i) + +global perm3 +perm3 = lambda a : [[a[0],a[1],a[2]],[a[0],a[2],a[1]],[a[1],a[0],a[2]],[a[2],a[0],a[1]], [a[1],a[2],a[0]],[a[2],a[1],a[0]]] + +global Path +Path = [['1','2','3'],['4','5','6'],['7','8','9'],['1','4','7'],['2','5','8'],['3','6','9'],['1','5','9'],['3','5','7']] + +global Lines +Lines =[] +for p in Path: + Lines.extend(perm3(p)) + +global All +All= lambda A:[A(i) for i in range(1,9)] + +global AllMove +AllMove=lambda : All(X).extern(All(O)) +" + + + st3 -> wa -> rq3; + + st3 [type=start, initial="[{'path':Path[0]} ]", width=400]; + wa [type=waitall, waitall="[[X(i) for i in path]]"] + rq3 [type=sync, req="['Player X wins'], block =[AllMove()]"] + + + + + st2 -> rqX1 ; + + st2 [type=start, initial="[{'i':i }for i in range(1,4)]", width=400]; + rqX1[type = sync , req="[X(i)]"] + + + # For debugging + class hidden [color = none, style = none, textcolor = white]; + stt -> listener -> "Event viewer" -> listener [style = "none"]; + + listener [type=sync, + wait="['X'+str(i) for i in range(1,9)]+['O'+str(i) for i in range(1,9)]", + class = "hidden", autoformat='false']; + + stt [type=start, class = "hidden", autoformat='false']; + +} diff --git a/flow.py b/flow.py index 07a48eb..3ece00c 100644 --- a/flow.py +++ b/flow.py @@ -7,7 +7,7 @@ from NodeLibrary import * -statecount = 0 +statecount = 0 # const builder.DiagramNode.type = "pass" builder.DiagramNode.SYNC = None builder.DiagramNode.T = None @@ -28,12 +28,15 @@ builder.DiagramNode.join_by = [] builder.DiagramNode.join = None +builder.DiagramNode.waitall = "[]" + + builder.Diagram.run = None builder.Diagram.initialization_code = "" builder.Diagram.event_selection_mechanism = 'random' node_types = (StartType(), SyncType(), LoopType(), PassType(), PermutationType(), - JoinType(), WaitForSetType(), LoggerType()) + JoinType(), WaitForSetType(), LoggerType(), WaitAll()) def traverse_nodes(n):