def get_state_id(self, places, petri_net): '''get the state_id from his marked places ids for example "<s1>" or "<s1,s2>" or "<s1,s2,s3>" sorted "<s2,s1>"--it is wrong! it must be "<s1,s2>" @return: state_id @rtype: str ''' places_dict = petri_net.places_dict state_id = "" places_ids = [place.pt_id for place in places] # "p6" < "p11" places_ids.sort(self.my_cmp) for pt_id in places_ids: place = places_dict[pt_id] if place.tokens > 1: temp = "," + pt_id + "(" + str(place.tokens) + ")" elif place.tokens == 1: temp = "," + pt_id else: log.show_error("no tokens in the place") state_id += temp # delete the first ","-----",s1,s2"-->"s1,s2" state_id = state_id[1:] state_id = "<" + state_id + ">" return state_id
def _get_new_id(self, pt_element, pt_elements_dict): '''get the new ID of P or T, for example, "p3","t4".. for example EAID_BB946565_CBA6_4ee7_820E_8D19061435F6 (the id in xml)--> p1 @param pt_element: place or transition @type pt_element: object of petri_net_element.Place or petri_net_element.Transition @param pt_elements_dict: places_dict or transitions_dict @type pt_elements_dict: dict @return: new_id --"p3","t4".. @rtype: new_id--str ''' new_id = None num = 1 for pt_id in pt_elements_dict: element = pt_elements_dict[pt_id] if element.id_changed is True: num += 1 if isinstance(pt_element, petri_net_element.Place): new_id = "p" + str(num) elif isinstance(pt_element, petri_net_element.Transition): new_id = "t" + str(num) else: log.show_error("the pt_element type is wrong") if new_id in pt_elements_dict: log.show_error("the new id " + new_id + " exist already..._get_new_id()") return new_id
def determine_marking(self, places, transition, places_dict, arcs_dict): '''fire t and determine the marking m' after firing. get the next state, in the state which places are marked @param places: the current marked places, pre-places. attention: do not change places!!! @type places: list @param transition: the next enabled transition,here just one transition from our definition @type transition: petri_net_element.Transition ''' pre_places = places[:] incomings = transition.incomings for incoming in incomings: arc = arcs_dict[incoming] source = arc.source place = places_dict[source] if place in pre_places: place.tokens -= 1 # not any more tokens,remove it if place.tokens == 0: pre_places.remove(place) else: log.show_error(place.pt_id + " is not marked") outgoings = transition.outgoings for outgoing in outgoings: arc = arcs_dict[outgoing] target = arc.target place = places_dict[target] place.tokens += 1 if place not in pre_places: pre_places.append(place) return pre_places
def _get_nodes_from_edge(self, edge, activity): '''get the node1, node2 from the edge. also, node1-->edge-->node2 @param edge: a edge instance in activity @type edge: a instance of edge, not the id of the edge ''' nodes_dict = activity.nodes_dict pins_dict = activity.pins_dict # node1 and node2 node1 = None node2 = None # the id of source and target source = edge.source target = edge.target # if source is node_id if source in nodes_dict: node1 = nodes_dict[source] else: # source is pout id pin = pins_dict[source] node1_id = pin.host node1 = nodes_dict[node1_id] # if target is node_id if target in nodes_dict: node2 = nodes_dict[target] else: # target is pin id pin = pins_dict[target] node2_id = pin.host node2 = nodes_dict[node2_id] # if node1 or node2 is None,it is error if node1 is None or node2 is None: log.show_error("the node1 or node2 is None") return node1, node2
def get_outgoings(self, node): '''get the outgoings list of the xml-node. create instances of uml_activity_diagram_element.Outgoing outgoing = uml_activity_diagram_element.Outgoing(xmi_idref) and put them in the outgoings list @param node: xml node @type node: xml.dom.Node (attention: it is not a instance of uml_activity_diagram_element.ActivityNode) @return: outgoings @rtype: list [instance1 of uml_activity_diagram_element.Outgoing, instance2 of uml_activity_diagram_element.Outgoing...] ''' outgoings = [] # get the outgoings of the node node_outgoings = self.get_child_nodes(node, 'outgoing') # outgoingsTag = node.getElementsByTagName('outgoing') for node_outgoing in node_outgoings: if node_outgoing.hasAttribute("xmi:idref"): xmi_idref = node_outgoing.getAttribute("xmi:idref") outgoing = uml_element.Outgoing(xmi_idref) if outgoing not in outgoings: outgoings.append(outgoing) else: log.show_error("node's outgoing has no id") return outgoings
def _get_nodes_from_edge(self, edge, activity): """get the node1, node2 from the edge. also, node1-->edge-->node2 @param edge: a edge instance in activity @type edge: a instance of edge, not the id of the edge """ nodes_dict = activity.nodes_dict pins_dict = activity.pins_dict # node1 and node2 node1 = None node2 = None # the id of source and target source = edge.source target = edge.target # if source is node_id if source in nodes_dict: node1 = nodes_dict[source] else: # source is pout id pin = pins_dict[source] node1_id = pin.host node1 = nodes_dict[node1_id] # if target is node_id if target in nodes_dict: node2 = nodes_dict[target] else: # target is pin id pin = pins_dict[target] node2_id = pin.host node2 = nodes_dict[node2_id] # if node1 or node2 is None,it is error if node1 is None or node2 is None: log.show_error("the node1 or node2 is None") return node1, node2
def get_outgoings(self, node): """get the outgoings list of the xml-node. create instances of uml_activity_diagram_element.Outgoing outgoing = uml_activity_diagram_element.Outgoing(xmi_idref) and put them in the outgoings list @param node: xml node @type node: xml.dom.Node (attention: it is not a instance of uml_activity_diagram_element.ActivityNode) @return: outgoings @rtype: list [instance1 of uml_activity_diagram_element.Outgoing, instance2 of uml_activity_diagram_element.Outgoing...] """ outgoings = [] # get the outgoings of the node node_outgoings = self.get_child_nodes(node, "outgoing") # outgoingsTag = node.getElementsByTagName('outgoing') for node_outgoing in node_outgoings: if node_outgoing.hasAttribute("xmi:idref"): xmi_idref = node_outgoing.getAttribute("xmi:idref") outgoing = uml_element.Outgoing(xmi_idref) if outgoing not in outgoings: outgoings.append(outgoing) else: log.show_error("node's outgoing has no id") return outgoings
def draw_petri_net(self, petri_net): '''draw Petri Net from the 3 dicts ''' places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict # G=pgv.AGraph(directed=True,strict=True,splines="polyline") # G = pgv.AGraph(directed=True, strict=True, splines=False) G = pgv.AGraph(directed=True, strict=True) G.graph_attr['label'] = petri_net.label + petri_net.probs for pt_id in places_dict: place = places_dict[pt_id] place_xlabel = place.xlabel G.add_node(pt_id, shape="circle", label="", xlabel=place_xlabel) for pt_id in transitions_dict: transition = transitions_dict[pt_id] # get the max number of the incomings and outgoings number = max(len(transition.incomings), len(transition.outgoings)) transition_width = 0.5 * number transition_xlabel = transition.xlabel transition_type = transition.transition_type # Deterministic transitions are drawn as black filled rectangles. if transition_type == petri_net_element.TransitionTypes.DETERMINISTIC_TRANSITION: G.add_node(pt_id, shape="box", style="filled", label="", \ xlabel=transition_xlabel, height=0.3, \ width=transition_width, fillcolor="#000000") # color:black # Exponential transitions are drawn as empty rectangles. elif transition_type == petri_net_element.TransitionTypes.EXPONENTIAL_TRANSITION: G.add_node(pt_id, shape="box", label="", xlabel=transition_xlabel, height=0.3, width=transition_width, fillcolor="#000000") # color:black # Immediate transitions are drawn as thin bars. elif transition_type == petri_net_element.TransitionTypes.IMMEDIATE_TRANSITION: G.add_node(pt_id, shape="box", style="filled", label="", xlabel=transition_xlabel, height=0.08, width=transition_width, fillcolor="#000000") # color:black else: log.show_error("the transition type is not defined") for pt_id in arcs_dict: arc = arcs_dict[pt_id] source = arc.source target = arc.target G.add_edge(source, target) # draw the arc with probability # if arc.prob == 1: # G.add_edge(source, target) # else: # G.add_edge(source, target, label=arc.prob) # print G.string() # print dot file to standard output png_name = self.get_png_name() # G.write("Pt"+png_name + ".dot") G.layout('dot') # layout with dot G.draw("Pt" + "_" + petri_net.name + png_name + ".png") # write to file log.show_info("the Petri Net Diagram is created.name:%s" % petri_net.name)
def _scan(self, buf): text = zlib.decompress(buf) content = json.loads(text) if not content or type(content) != dict: show_error(self, 'invalid content') return files = self._extract(content) if files: if not self._do_scan(files): raise Exception('this package contains invalid files') return content.get('description')
def _extract(self, content): if content.get('app'): files = content.get('app') elif content.get('driver'): files = content.get('driver') else: show_error(self, 'cannot extract') return filenames = filter(lambda f: f.endswith('.py'), files) info = {} for name in filenames: file = files.get(name) info.update({name: file}) return info
def _get_cf_prob_from_text(self, guard): '''get the cf_prob from text of guard. for example: [...prob:0.25] [...prob=0.25] [...pro:0.25] [...pro=0.25] [...pr:0.25] [...pr=0.25] ''' prob = 1 if guard is None: # cf_prob is default 1, also edge.prob =1 return 1 # delete the " " guard_body = guard.body.replace(' ', '') possibles = ["prob:", "prob=", "pro:", "pro=", "pr:", "pr="] index = -1 for possible_str in possibles: # find it from right index = guard_body.rfind(possible_str) if index != -1: # the length num = len(possible_str) break if index != -1: # find the number_str, such as "0.5" prob_str = guard_body[(index + num):] try: # str to float prob = float(prob_str) except ValueError: log.show_error("the prob is invalid,Please modify it " + prob_str) # if it is less than 0 or more than one if (prob <= 0.0) or (prob > 1.0): log.show_error("the prob should be a number between 0 and 1") # if it is not default one if prob != 1: # show info log.show_info("the guard:%s, has cf_prob:%f" % (guard_body, prob)) return prob
def _get_cf_prob_from_text(self, guard): """get the cf_prob from text of guard. for example: [...prob:0.25] [...prob=0.25] [...pro:0.25] [...pro=0.25] [...pr:0.25] [...pr=0.25] """ prob = 1 if guard is None: # cf_prob is default 1, also edge.prob =1 return 1 # delete the " " guard_body = guard.body.replace(" ", "") possibles = ["prob:", "prob=", "pro:", "pro=", "pr:", "pr="] index = -1 for possible_str in possibles: # find it from right index = guard_body.rfind(possible_str) if index != -1: # the length num = len(possible_str) break if index != -1: # find the number_str, such as "0.5" prob_str = guard_body[(index + num) :] try: # str to float prob = float(prob_str) except ValueError: log.show_error("the prob is invalid,Please modify it " + prob_str) # if it is less than 0 or more than one if (prob <= 0.0) or (prob > 1.0): log.show_error("the prob should be a number between 0 and 1") # if it is not default one if prob != 1: # show info log.show_info("the guard:%s, has cf_prob:%f" % (guard_body, prob)) return prob
def calculate_probability(lam1, distributions): '''calculate the probability with 2 exponential distributions. for example: calculate_probability(10,[10,20]) ''' # calculate with 2 exponential distributions if len(distributions) != 2: log.show_error("it can just calculate with 2 exponential distributions") if lam1 not in distributions: log.show_error("lam1 is not in the tup") lam2 = 0 # get the first number, if it equals lam1, set the second number to lam2 # if it not equals lam1, set it to lam2 temp = distributions[0] if temp == lam1: lam2 = distributions[1] else: lam2 = temp pro = float(lam2) / (lam1 + lam2) pro = round(pro, 3) return pro
def _get_object_next_node(self, object_node, activity): """get the action or control node after the object node. """ nodes_dict = activity.nodes_dict edges_dict = activity.edges_dict node = None outgoings = object_node.outgoings num = len(outgoings) if num == 0: log.show_warn("the object node has no ougoings") elif num == 1: outgoing = outgoings[0] edge_id = outgoing.xmi_idref edge = edges_dict[edge_id] node_id = edge.target node = nodes_dict[node_id] elif num > 1: log.show_error("the object node has more ougoings") # if the node after the object node is also object node.show error if isinstance(node, uml_element.ObjectNode): log.show_error("the node after the object node:%s is object node" % str(object_node.name)) return node
def set_next_place_tokens(self, place, tokens_num, petri_net): '''set the place.max_tokens after the place. tokens_num = place.max_tokens ''' places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict place_outgoings = place.outgoings for place_outgoing in place_outgoings: arc1 = arcs_dict[place_outgoing] next_transiton_id = arc1.target next_transition = transitions_dict[next_transiton_id] for transition_outgoing in next_transition.outgoings: arc2 = arcs_dict[transition_outgoing] next_place_id = arc2.target # get the next_place after the place next_place = places_dict[next_place_id] if next_place.max_tokens == 1: next_place.max_tokens = tokens_num self.set_next_place_tokens(next_place, tokens_num, petri_net) else: log.show_error("the place.max_tokens is already not 1 ")
def calculate_probability(lam1, distributions): '''calculate the probability with 2 exponential distributions. for example: calculate_probability(10,[10,20]) ''' # calculate with 2 exponential distributions if len(distributions) != 2: log.show_error( "it can just calculate with 2 exponential distributions") if lam1 not in distributions: log.show_error("lam1 is not in the tup") lam2 = 0 # get the first number, if it equals lam1, set the second number to lam2 # if it not equals lam1, set it to lam2 temp = distributions[0] if temp == lam1: lam2 = distributions[1] else: lam2 = temp pro = float(lam2) / (lam1 + lam2) pro = round(pro, 3) return pro
def _get_object_next_node(self, object_node, activity): '''get the action or control node after the object node. ''' nodes_dict = activity.nodes_dict edges_dict = activity.edges_dict node = None outgoings = object_node.outgoings num = len(outgoings) if num == 0: log.show_warn("the object node has no ougoings") elif num == 1: outgoing = outgoings[0] edge_id = outgoing.xmi_idref edge = edges_dict[edge_id] node_id = edge.target node = nodes_dict[node_id] elif num > 1: log.show_error("the object node has more ougoings") # if the node after the object node is also object node.show error if isinstance(node, uml_element.ObjectNode): log.show_error("the node after the object node:%s is object node" % str(object_node.name)) return node
def get_time(self, str_time): """get the real time. @param str_time: the time str, such as "20ms","25s" @type str_time: str @return: time @rtype: float """ if str_time is None: return original_str = str_time time = None unit = None # factor: ms-->0.01, s-->1, min-->60 # default is "s" factor = None # delete all ' ', for example " 20 m s"-->"20ms" str_time = str_time.replace(" ", "") # if it is "" if len(str_time) == 0: log.show_error("the time is empty string,Please modify it ") elif str_time.endswith("ms"): unit = "ms" factor = 0.001 elif str_time.endswith("s"): unit = "s" factor = 1 elif str_time.endswith("min"): unit = "min" factor = 60 elif str_time.endswith("h"): unit = "h" factor = 60 * 60 elif str_time.endswith("d"): unit = "d" factor = 60 * 60 * 24 elif str_time.endswith("mon"): unit = "mon" factor = 60 * 60 * 24 * 30 elif str_time.endswith("y"): unit = "y" factor = 60 * 60 * 24 * 30 * 12 else: log.show_error("the unit of the time is invalid,Please modify it " + original_str) exit(0) # delete the unit from the right end of the str_time str_time = str_time.rstrip(unit) try: # str to float time = float(str_time) except ValueError: log.show_error("the time is invalid,Please modify it " + original_str) time = time * factor return time
def get_time(self, str_time): '''get the real time. @param str_time: the time str, such as "20ms","25s" @type str_time: str @return: time @rtype: float ''' if str_time is None: return original_str = str_time time = None unit = None # factor: ms-->0.01, s-->1, min-->60 # default is "s" factor = None # delete all ' ', for example " 20 m s"-->"20ms" str_time = str_time.replace(' ', '') # if it is "" if len(str_time) == 0: log.show_error("the time is empty string,Please modify it ") elif str_time.endswith('ms'): unit = "ms" factor = 0.001 elif str_time.endswith('s'): unit = "s" factor = 1 elif str_time.endswith('min'): unit = "min" factor = 60 elif str_time.endswith('h'): unit = "h" factor = 60 * 60 elif str_time.endswith('d'): unit = "d" factor = 60 * 60 * 24 elif str_time.endswith('mon'): unit = "mon" factor = 60 * 60 * 24 * 30 elif str_time.endswith('y'): unit = "y" factor = 60 * 60 * 24 * 30 * 12 else: log.show_error("the unit of the time is invalid,Please modify it " + original_str) exit(0) # delete the unit from the right end of the str_time str_time = str_time.rstrip(unit) try: # str to float time = float(str_time) except ValueError: log.show_error("the time is invalid,Please modify it " + original_str) time = time * factor return time
def xml_parse(self, xml_path): """start the parsing @param xml_path: the path of the xml @attention: the different between windows and Linux """ # use minidom to open the xml try: DOMTree = minidom.parse(xml_path) # collection = DOMTree.documentElement except IOError: log.show_error("the xml is wrong") # get the root tag of the xml root = DOMTree.documentElement # get the tag: <xmi:Documentation> # get the exporter(Magic Draw or EA) and exporterVersion documentation = self.get_child_nodes(root, "xmi:Documentation")[0] exporter, export_version = self.get_exporter_version(documentation) log.show_info("exporter:" + exporter + ".exportVersion:" + export_version) # get <uml:Model /> model_node = self.get_child_nodes(root, "uml:Model")[0] # the 4 parameters: xmi_id, xmi_type, name, activitys_dict xmi_id, name, xmi_type = self.get_id_name_type(model_node) activitys_dict = {} # create the model model = uml_element.Model(xmi_id, xmi_type, name, activitys_dict) # get <packagedElement> # packaged_elements = self.get_child_nodes(model_node, "packagedElement") packaged_elements = model_node.getElementsByTagName("packagedElement") InstanceSpecification_nodes = [] activity_id = None for packaged_element in packaged_elements: xmi_id, name, xmi_type = self.get_id_name_type(packaged_element) # get the activity diagram "uml:Activity" if xmi_type == uml_element.Types.ACTIVITY: # xmi_id:ActivityNode (class UmlActivityDiagramElement.ActivityNode) nodes_dict = {} # xmi_id:ActivityEdge (class uml_activity_diagram_element.ActivityEdge) edges_dict = {} # Result and Argument pins_dict = {} # create activity activity = uml_element.Activity(xmi_id, xmi_type, name, nodes_dict, edges_dict, pins_dict) # put it in the activitys_dict activitys_dict[xmi_id] = activity # activity_id activity_id = xmi_id # get all the nodes nodes = self.get_child_nodes(packaged_element, "node") # get every node for node in nodes: # get the id, name, type of the node xmi_id, name, xmi_type = self.get_id_name_type(node) # get behavior behavior = self.get_behavior(node) # get incomings of the node incomings = self.get_incomings(node) # get outgoings of the node outgoings = self.get_outgoings(node) # get the results of the node results = self.get_results(node, xmi_id) # get the arguments of the node arguments = self.get_arguments(node, xmi_id) # create node object self.create_node_object( nodes_dict, xmi_id, xmi_type, name, incomings, outgoings, results, arguments, behavior ) # put all the results and arguments in the pins_dict # if not all empty if results or arguments: self.__set_pins_dict(pins_dict, results, arguments) # get all the edges edges = self.get_child_nodes(packaged_element, "edge") # get every node for edge in edges: # get the id,name,type of the edge xmi_id, name, xmi_type = self.get_id_name_type(edge) # get the target, source of the edge target, source = self.get_target_source(edge) # get the guard of the edge guard = self.get_guard(edge) # create edge object self.create_edge_object(edges_dict, xmi_id, xmi_type, name, target, source, guard) # <packagedElement name="UserData" xmi:type="uml:InstanceSpecification" xmi:id="EAID_C3D4C"/> elif xmi_type == "uml:InstanceSpecification": InstanceSpecification_node = uml_element.InstanceSpecification_node(xmi_id, xmi_type, name, [], []) InstanceSpecification_nodes.append(InstanceSpecification_node) for InstanceSpecification_node in InstanceSpecification_nodes: model.activitys_dict[activity_id].nodes_dict[InstanceSpecification_node.xmi_id] = InstanceSpecification_node if exporter == "MagicDraw UML": # time parser data_times = self.get_child_nodes(root, "Data:Time") for data_time in data_times: str_time, base_element, time_type = self.get_time_base_element(data_time) self.set_time(str_time, base_element, time_type, model) # for from EA imported xml thecustomprofile_times = self.get_child_nodes(root, "thecustomprofile:time") for thecustomprofile_time in thecustomprofile_times: str_time, base_element, time_type = self.get_time_base_element(thecustomprofile_time) self.set_time(str_time, base_element, time_type, model) elif exporter == "Enterprise Architect": # get the tag "time" for EA extension = self.get_child_nodes(root, "xmi:Extension")[0] elements = self.get_child_nodes(extension, "elements")[0] element_tags = self.get_child_nodes(elements, "element") for element in element_tags: tags = self.get_child_nodes(element, "tags") if len(tags) > 0: tags = tags[0] tag_elements = self.get_child_nodes(tags, "tag") for tag in tag_elements: if tag.hasAttribute("name"): name = tag.getAttribute("name") if name == "time": if tag.hasAttribute("value"): str_time = tag.getAttribute("value") base_element = element.getAttribute("xmi:idref") # TODO self.set_time(str_time, base_element, "exp", model) else: log.show_error("the exporter is not supported in the code") return model
def get_next_state(self, places, transitions, petri_net, rg_graph, unreach_list, reach, probs): '''fire t and determine the marking m' after firing. 1b).if 2 transitions t1,t2 can be enabled, so from the node < m > will create 2 arrows. fire t1,go to step2(until stop),then fire t2, go to step2. step2. fire t and determine the marking m' after firing. if m' is already a node in G, then add the new arrow(m,t,m') to G, stop. step3. if m' is not a node in G, add m' as a new node and (m,t,m') as a new arrow to G and go to step 1. get the next states, it can be more states. @param places: the current marked places,pre-places @type places: list ''' places_dict = petri_net.places_dict arcs_dict = petri_net.arcs_dict states_dict = rg_graph.states_dict edges_dict = rg_graph.edges_dict # pre_state_id: '<s1,s2>' pre_state_id = self.get_state_id(places, petri_net) reset_tokens = False # parallel, or decision if len(transitions) > 1: reset_tokens = True tokens_list = [place.tokens for place in places] if pre_state_id not in states_dict: pre_state = Rg.State(pre_state_id, pre_state_id, [], []) states_dict[pre_state_id] = pre_state # it is for unreach diagram, show in color blue if not reach: pre_state.reachability = False else: pre_state = states_dict[pre_state_id] # every time just one transition can be enabled. index = -1 for transition in transitions: index += 1 # reset the places 's tokens if reset_tokens: self.reset_tokens(places, tokens_list, places_dict) # get the next state-places, change id, and get the state id next_places = self.determine_marking(places, transition, places_dict, arcs_dict) for place in next_places: if not place.id_changed: self.change_pt_id(place, places_dict, arcs_dict, petri_net) next_state_id = self.get_state_id(next_places, petri_net) # "<p1,p2><p3>" # edge_id = "pre_state_id + next_state_id" # "edge0","edge1","edge2","edge3"... edge_id = "edge" + str(len(edges_dict)) if edge_id not in edges_dict: # pre_state.outgoings is list, append the edge_id pre_state.outgoings.append(edge_id) edge = Rg.Edge(edge_id, edge_id, pre_state_id, next_state_id) # TODO edge.prob = probs[index] edge.label = transition.pt_id + "(" + str(edge.prob) + ")" edges_dict[edge_id] = edge # if not reach: edge.reachability = False # multiedge, for example, p4-t5-p5,p4-t6-p5,p4-t7-p5 else: log.show_error("edge id error in RG") # edge = edges_dict[edge_id] # edge.label = edge.label + " or " + transition.pt_id # step 3. if m' is not a node in G if next_state_id not in states_dict: next_state = Rg.State(next_state_id, next_state_id, [], []) # pre_state.incomings is list, append the edge_id next_state.incomings.append(edge_id) states_dict[next_state_id] = next_state # if not reach: next_state.reachability = False # if m' is already a node in G,then add the new arrow(m,t,m') to G, stop. else: # next state exist, just incomings append the edge_id next_state = states_dict[next_state_id] if edge_id not in next_state.incomings: next_state.incomings.append(edge_id) continue # step 3a) if m' has final node, stop if self.final_in_places(next_places): continue if len(next_places) > 0: # go to step 1 self.find_enabled_transitions(next_places, petri_net, rg_graph, unreach_list, reach)
def find_enabled_transitions(self, places, petri_net, rg_graph, unreach_list, reach): ''' first,get the next following transition from the current marked places, second, see if it can be enabled(see function-is_transition_enabled), and save the transitions in one list, for example [s1,s2] @param places: the current marked places,pre-places @type places: list @param reach: True, for the reachability_graph diagram. False, unreach_list=[],for the unreachability_graph. @type reach: Boolean @see: algorithm- step1 ''' # [t1,t2,t3...] transitions = [] # [[t1],[t2,t3]...] # t1 fire from place1, t2,t3 fire from place2(decision) transitions_slices = [] # the probs to fire the transition # [prob1,prob2,prob3...], the sum must be 1 probs = [] # [[prob1],[prob2,prob3]...] # prob1 is 1, sum of prob2 and prob3 is 1 probs_slices = [] # petri_net places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict # get the next transition from the place, and see if it can be enabled for place in places: # [t1] or [t2,t3] transitions_slice = [] # [1] or [0.3,0.7] probs_slice = [] outgoings = place.outgoings for outgoing in outgoings: arc = arcs_dict[outgoing] target = arc.target transition = transitions_dict[target] # if the transition can be enabled if self.is_transition_enabled(transition, places, places_dict, arcs_dict): # get the prob from the arc prob = arc.prob # put the transition in the transitions_slice if transition not in transitions_slice: transitions_slice.append(transition) # put the prob in the probs_slice probs_slice.append(prob) else: # show error log.show_error("more than 1 arcs between the place and the transition:find_enabled_transitions()") # put it in the transitions if transition not in transitions: transitions.append(transition) probs.append(prob) # change the id of transition,which can be enabled if not transition.id_changed: self.change_pt_id(transition, transitions_dict, arcs_dict, petri_net) # if it is not [] if transitions_slice: transitions_slices.append(transitions_slice) probs_slices.append(probs_slice) if reach: # parallel find the min(delay), # if just decision len(transitions) > 1 and len(transitions_slices)=1 # if len(transitions_slices) > 1, but len(transitions) = 1-->join: # len(transitions_slices) >1 ,-->parallel if len(transitions) > 1 and len(transitions_slices) > 1: # delete the same type types_set = set([transition.transition_type for transition in transitions]) types_list = list(types_set) # TODO if len(types_list) == 1: # get the type of the transitions transition_type = types_list[0] # all are immediate transition if transition_type == petri_net_element.TransitionTypes.IMMEDIATE_TRANSITION: pass # all are DeterministicTransition elif transition_type == petri_net_element.TransitionTypes.DETERMINISTIC_TRANSITION: execute_transition = self.get_execute_transition(transitions) transitions.remove(execute_transition) # tokens_list = [place.tokens for place in places] unreach_list.append(places) unreach_list.append(tokens_list) unreach_list.append(transitions) # transitions = [execute_transition] # all are EXPONENTIAL_TRANSITION elif transition_type == petri_net_element.TransitionTypes.EXPONENTIAL_TRANSITION: if len(transitions_slices) == 2: self._calculate_probability(transitions_slices, probs_slices, transitions, probs) else: log.show_error("the code can not analyse 3 parallel exp distribution process") else: log.show_error("the type of the transition is not defined") # all are ExponentialTransition else: log.show_warn("the types of the enabled transitions are not the same") # see algorithm- step1a) if len(transitions) > 0: # fire t and determine the marking m' after firing. self.get_next_state(places, transitions, petri_net, rg_graph, unreach_list, reach, probs)
def check_names(self, activity): """check the name of action and object. 1.if it is None or "",it will cause a error when it transforms to epf. set the name "node1","node2" 2.if two nodes(action or object) have the same name, it will also cause a error when it transforms to epf. for example "get info" and "get_info" 3.change the name to the corrected name # TODO check the name of pin @return: check_ok, if checks ok @rtype: boolean """ check_ok = True names = [] nodes_dict = activity.nodes_dict pins_dict = activity.pins_dict # action, object, initial, final node_types = ( uml_element.ExecutableNode, uml_element.ObjectNode, uml_element.InitialNode, uml_element.FinalNode, uml_element.Fork, uml_element.Join, ) # for node num1 = 0 # for pin,pout num2 = 0 # it checks the name of pout, do not need to check the name of pin for pin_id in pins_dict: pin = pins_dict[pin_id] # if it is a pout(Result) if isinstance(pin, uml_element.Result): name = pin.name # if it has no name, see condition1 if name is None or name.strip() == "": # if the pin has no name, set the name "pin1","pin2"... num2 += 1 pin.name = "pin" + str(num2) log.show_warn("the pin has no name.id:%s" % pin.xmi_id) else: corrected_name = self.__get_corrected_name(name) # change the name of node to corrected name pin.name = corrected_name # see condition2 if corrected_name in names: check_ok = False log.show_error("the pin has the same name.name:%s" % name) else: names.append(corrected_name) for node_id in nodes_dict: node = nodes_dict[node_id] # if it is a action or object,initial,final # The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for # isinstance(x, A) or isinstance(x, B) or ... (etc.). if isinstance(node, node_types): name = node.name # if it has no name, see condition1 if name is None or name.strip() == "": # if the node has no name, set the name "node1","node2"... num1 += 1 node.name = "node" + str(num1) log.show_warn("the node has no name.id:%s" % node.xmi_id) else: corrected_name = self.__get_corrected_name(name) # change the name of node to corrected name node.name = corrected_name # see condition2 if corrected_name in names: check_ok = False log.show_error("the nodes has the same name.name:%s" % name) else: names.append(corrected_name) return check_ok
def get_init_final_num(self, activity): """ verify, if the uml activity diagram has just(genau) one Initial Node, and one or more ActivityFinal. if a node has no incoming or no outgoing, it is a error, except init node and final node and flow final. """ nodes_dict = activity.nodes_dict initial_num = 0 final_num = 0 for node_id in nodes_dict: node = nodes_dict[node_id] incomings = node.incomings outgoings = node.outgoings in_num = len(incomings) out_num = len(outgoings) # initial node, just one and it must have outgoing if node.xmi_type == uml_element.Types.INITIAL_NODE: initial_num += 1 if out_num == 0: log.show_error( "the Initial Node has no outgoing." + "name:" + str(node.name) + " id:" + node.xmi_id ) # final node, one or more, and it must have incoming elif node.xmi_type == uml_element.Types.ACTIVITY_FINAL_NODE: final_num += 1 if in_num == 0: log.show_error("the final Node has no incoming." + "name:" + str(node.name) + " id:" + node.xmi_id) # flow final, it must have incoming elif node.xmi_type == uml_element.Types.FLOW_FINAL_NODE: if len(incomings) == 0: log.show_error("the final Node has no incoming." + "name:" + str(node.name) + " id:" + node.xmi_id) elif isinstance(node, uml_element.ObjectNode): if not isinstance(node, uml_element.InstanceSpecification_node): if len(incomings) == 0: # @see example Order # show warn info, not error info log.show_warn("the object Node has no incoming.name:%s,id:%s" % (str(node.name), node.xmi_id)) if len(outgoings) == 0: # @see example Order # show warn info, not error info log.show_warn("the object Node has no outgoins.name:%s,id:%s" % (str(node.name), node.xmi_id)) # if the node has no incoming or no outgoing # it is a error(except initial,final,object node) else: # incoming and outgoing of a node if in_num == 0: # action has no incoming, but it has argument, and the argument has incoming if isinstance(node, uml_element.ExecutableNode): arguments = node.arguments for argument in arguments: # if the argument has no incoming if len(argument.incomings) == 0: log.show_error( "the action node's argument in " + "uml activity diagram has no incoming." + "name:" + str(node.name) + " id:" + node.xmi_id ) # it is not a action else: log.show_error( "the node in uml activity diagram has no incoming." + "name:" + str(node.name) + " id:" + node.xmi_id ) if out_num == 0: # action has no outgoing, but it has result, and the result has outgoing if isinstance(node, uml_element.ExecutableNode): results = node.results for result in results: # if the result has no outgoing if len(result.outgoings) == 0: log.show_error( "the action node's result in " + "uml activity diagram has no incoming." + +"name:" + str(node.name) + " id:" + node.xmi_id ) # it is not a action else: log.show_error( "the node in uml activity diagram has no outgoing." + "name:" + str(node.name) + " id:" + node.xmi_id ) # initial node just one if initial_num == 0: log.show_error("the uml activity diagram has no Initial Node") elif initial_num > 1: log.show_error("the uml activity diagram has " + str(initial_num) + " Initial Nodes") # final node one or more than one if final_num == 0: log.show_warn("the uml activity diagram has no final Node") return initial_num, final_num
def xml_parse(self, xml_path): '''start the parsing @param xml_path: the path of the xml @attention: the different between windows and Linux ''' # use minidom to open the xml try: DOMTree = minidom.parse(xml_path) # collection = DOMTree.documentElement except IOError: log.show_error("the xml is wrong") # get the root tag of the xml root = DOMTree.documentElement # get the tag: <xmi:Documentation> # get the exporter(Magic Draw or EA) and exporterVersion documentation = self.get_child_nodes(root, "xmi:Documentation")[0] exporter, export_version = self.get_exporter_version(documentation) log.show_info("exporter:" + exporter + ".exportVersion:" + export_version) # get <uml:Model /> model_node = self.get_child_nodes(root, "uml:Model")[0] # the 4 parameters: xmi_id, xmi_type, name, activitys_dict xmi_id, name, xmi_type = self.get_id_name_type(model_node) activitys_dict = {} # create the model model = uml_element.Model(xmi_id, xmi_type, name, activitys_dict) # get <packagedElement> # packaged_elements = self.get_child_nodes(model_node, "packagedElement") packaged_elements = model_node.getElementsByTagName("packagedElement") InstanceSpecification_nodes = [] activity_id = None for packaged_element in packaged_elements: xmi_id, name, xmi_type = self.get_id_name_type(packaged_element) # get the activity diagram "uml:Activity" if xmi_type == uml_element.Types.ACTIVITY: # xmi_id:ActivityNode (class UmlActivityDiagramElement.ActivityNode) nodes_dict = {} # xmi_id:ActivityEdge (class uml_activity_diagram_element.ActivityEdge) edges_dict = {} # Result and Argument pins_dict = {} # create activity activity = uml_element.Activity(xmi_id, xmi_type, name, nodes_dict, edges_dict, pins_dict) # put it in the activitys_dict activitys_dict[xmi_id] = activity # activity_id activity_id = xmi_id # get all the nodes nodes = self.get_child_nodes(packaged_element, "node") # get every node for node in nodes: # get the id, name, type of the node xmi_id, name, xmi_type = self.get_id_name_type(node) # get behavior behavior = self.get_behavior(node) # get incomings of the node incomings = self.get_incomings(node) # get outgoings of the node outgoings = self.get_outgoings(node) # get the results of the node results = self.get_results(node, xmi_id) # get the arguments of the node arguments = self.get_arguments(node, xmi_id) # create node object self.create_node_object(nodes_dict, xmi_id, xmi_type, name, \ incomings, outgoings, results, arguments, behavior) # put all the results and arguments in the pins_dict # if not all empty if (results or arguments): self.__set_pins_dict(pins_dict, results, arguments) # get all the edges edges = self.get_child_nodes(packaged_element, "edge") # get every node for edge in edges: # get the id,name,type of the edge xmi_id, name, xmi_type = self.get_id_name_type(edge) # get the target, source of the edge target, source = self.get_target_source(edge) # get the guard of the edge guard = self.get_guard(edge) # create edge object self.create_edge_object(edges_dict, xmi_id, xmi_type, name, \ target, source, guard) # <packagedElement name="UserData" xmi:type="uml:InstanceSpecification" xmi:id="EAID_C3D4C"/> elif xmi_type == "uml:InstanceSpecification": InstanceSpecification_node = uml_element.InstanceSpecification_node(xmi_id, xmi_type, name, [], []) InstanceSpecification_nodes.append(InstanceSpecification_node) for InstanceSpecification_node in InstanceSpecification_nodes: model.activitys_dict[activity_id].nodes_dict[InstanceSpecification_node.xmi_id] = InstanceSpecification_node if exporter == "MagicDraw UML": # time parser data_times = self.get_child_nodes(root, "Data:Time") for data_time in data_times: str_time, base_element , time_type = self.get_time_base_element(data_time) self.set_time(str_time, base_element, time_type, model) # for from EA imported xml thecustomprofile_times = self.get_child_nodes(root, "thecustomprofile:time") for thecustomprofile_time in thecustomprofile_times: str_time, base_element, time_type = self.get_time_base_element(thecustomprofile_time) self.set_time(str_time, base_element, time_type, model) elif exporter == "Enterprise Architect": # get the tag "time" for EA extension = self.get_child_nodes(root, "xmi:Extension")[0] elements = self.get_child_nodes(extension, "elements")[0] element_tags = self.get_child_nodes(elements, "element") for element in element_tags: tags = self.get_child_nodes(element, "tags") if len(tags) > 0: tags = tags[0] tag_elements = self.get_child_nodes(tags, "tag") for tag in tag_elements: if tag.hasAttribute("name"): name = tag.getAttribute("name") if name == "time": if tag.hasAttribute("value"): str_time = tag.getAttribute("value") base_element = element.getAttribute("xmi:idref") # TODO self.set_time(str_time, base_element, "exp", model) else: log.show_error("the exporter is not supported in the code") return model
def check_names(self, activity): '''check the name of action and object. 1.if it is None or "",it will cause a error when it transforms to epf. set the name "node1","node2" 2.if two nodes(action or object) have the same name, it will also cause a error when it transforms to epf. for example "get info" and "get_info" 3.change the name to the corrected name # TODO check the name of pin @return: check_ok, if checks ok @rtype: boolean ''' check_ok = True names = [] nodes_dict = activity.nodes_dict pins_dict = activity.pins_dict # action, object, initial, final node_types = (uml_element.ExecutableNode, uml_element.ObjectNode, uml_element.InitialNode, uml_element.FinalNode, uml_element.Fork, uml_element.Join) # for node num1 = 0 # for pin,pout num2 = 0 # it checks the name of pout, do not need to check the name of pin for pin_id in pins_dict: pin = pins_dict[pin_id] # if it is a pout(Result) if isinstance(pin, uml_element.Result): name = pin.name # if it has no name, see condition1 if name is None or name.strip() == "": # if the pin has no name, set the name "pin1","pin2"... num2 += 1 pin.name = "pin" + str(num2) log.show_warn("the pin has no name.id:%s" % pin.xmi_id) else: corrected_name = self.__get_corrected_name(name) # change the name of node to corrected name pin.name = corrected_name # see condition2 if corrected_name in names: check_ok = False log.show_error("the pin has the same name.name:%s" % name) else: names.append(corrected_name) for node_id in nodes_dict: node = nodes_dict[node_id] # if it is a action or object,initial,final # The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for # isinstance(x, A) or isinstance(x, B) or ... (etc.). if isinstance(node, node_types): name = node.name # if it has no name, see condition1 if name is None or name.strip() == "": # if the node has no name, set the name "node1","node2"... num1 += 1 node.name = "node" + str(num1) log.show_warn("the node has no name.id:%s" % node.xmi_id) else: corrected_name = self.__get_corrected_name(name) # change the name of node to corrected name node.name = corrected_name # see condition2 if corrected_name in names: check_ok = False log.show_error("the nodes has the same name.name:%s" % name) else: names.append(corrected_name) return check_ok
def get_init_final_num(self, activity): ''' verify, if the uml activity diagram has just(genau) one Initial Node, and one or more ActivityFinal. if a node has no incoming or no outgoing, it is a error, except init node and final node and flow final. ''' nodes_dict = activity.nodes_dict initial_num = 0 final_num = 0 for node_id in nodes_dict: node = nodes_dict[node_id] incomings = node.incomings outgoings = node.outgoings in_num = len(incomings) out_num = len(outgoings) # initial node, just one and it must have outgoing if node.xmi_type == uml_element.Types.INITIAL_NODE: initial_num += 1 if out_num == 0: log.show_error("the Initial Node has no outgoing." + \ "name:" + str(node.name) + " id:" + node.xmi_id) # final node, one or more, and it must have incoming elif node.xmi_type == uml_element.Types.ACTIVITY_FINAL_NODE: final_num += 1 if in_num == 0: log.show_error("the final Node has no incoming." + \ "name:" + str(node.name) + " id:" + node.xmi_id) # flow final, it must have incoming elif node.xmi_type == uml_element.Types.FLOW_FINAL_NODE: if len(incomings) == 0: log.show_error("the final Node has no incoming." + \ "name:" + str(node.name) + " id:" + node.xmi_id) elif isinstance(node, uml_element.ObjectNode): if not isinstance(node, uml_element.InstanceSpecification_node): if len(incomings) == 0: # @see example Order # show warn info, not error info log.show_warn( "the object Node has no incoming.name:%s,id:%s" % (str(node.name), node.xmi_id)) if len(outgoings) == 0: # @see example Order # show warn info, not error info log.show_warn( "the object Node has no outgoins.name:%s,id:%s" % (str(node.name), node.xmi_id)) # if the node has no incoming or no outgoing # it is a error(except initial,final,object node) else: # incoming and outgoing of a node if in_num == 0: # action has no incoming, but it has argument, and the argument has incoming if isinstance(node, uml_element.ExecutableNode): arguments = node.arguments for argument in arguments: # if the argument has no incoming if len(argument.incomings) == 0: log.show_error("the action node's argument in " + \ "uml activity diagram has no incoming." + \ "name:" + str(node.name) + \ " id:" + node.xmi_id) # it is not a action else: log.show_error("the node in uml activity diagram has no incoming."\ + "name:" + str(node.name) + " id:" + node.xmi_id) if out_num == 0: # action has no outgoing, but it has result, and the result has outgoing if isinstance(node, uml_element.ExecutableNode): results = node.results for result in results: # if the result has no outgoing if len(result.outgoings) == 0: log.show_error("the action node's result in " + \ "uml activity diagram has no incoming." + \ + "name:" + str(node.name) + " id:" + node.xmi_id) # it is not a action else: log.show_error("the node in uml activity diagram has no outgoing."\ + "name:" + str(node.name) \ + " id:" + node.xmi_id) # initial node just one if initial_num == 0: log.show_error("the uml activity diagram has no Initial Node") elif initial_num > 1: log.show_error("the uml activity diagram has " + str(initial_num) + " Initial Nodes") # final node one or more than one if final_num == 0: log.show_warn("the uml activity diagram has no final Node") return initial_num, final_num
def find_enabled_transitions(self, places, petri_net, rg_graph, unreach_list, reach): ''' first,get the next following transition from the current marked places, second, see if it can be enabled(see function-is_transition_enabled), and save the transitions in one list, for example [s1,s2] @param places: the current marked places,pre-places @type places: list @param reach: True, for the reachability_graph diagram. False, unreach_list=[],for the unreachability_graph. @type reach: Boolean @see: algorithm- step1 ''' # [t1,t2,t3...] transitions = [] # [[t1],[t2,t3]...] # t1 fire from place1, t2,t3 fire from place2(decision) transitions_slices = [] # the probs to fire the transition # [prob1,prob2,prob3...], the sum must be 1 probs = [] # [[prob1],[prob2,prob3]...] # prob1 is 1, sum of prob2 and prob3 is 1 probs_slices = [] # petri_net places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict # get the next transition from the place, and see if it can be enabled for place in places: # [t1] or [t2,t3] transitions_slice = [] # [1] or [0.3,0.7] probs_slice = [] outgoings = place.outgoings for outgoing in outgoings: arc = arcs_dict[outgoing] target = arc.target transition = transitions_dict[target] # if the transition can be enabled if self.is_transition_enabled(transition, places, places_dict, arcs_dict): # get the prob from the arc prob = arc.prob # put the transition in the transitions_slice if transition not in transitions_slice: transitions_slice.append(transition) # put the prob in the probs_slice probs_slice.append(prob) else: # show error log.show_error( "more than 1 arcs between the place and the transition:find_enabled_transitions()" ) # put it in the transitions if transition not in transitions: transitions.append(transition) probs.append(prob) # change the id of transition,which can be enabled if not transition.id_changed: self.change_pt_id(transition, transitions_dict, arcs_dict, petri_net) # if it is not [] if transitions_slice: transitions_slices.append(transitions_slice) probs_slices.append(probs_slice) if reach: # parallel find the min(delay), # if just decision len(transitions) > 1 and len(transitions_slices)=1 # if len(transitions_slices) > 1, but len(transitions) = 1-->join: # len(transitions_slices) >1 ,-->parallel if len(transitions) > 1 and len(transitions_slices) > 1: # delete the same type types_set = set( [transition.transition_type for transition in transitions]) types_list = list(types_set) # TODO if len(types_list) == 1: # get the type of the transitions transition_type = types_list[0] # all are immediate transition if transition_type == petri_net_element.TransitionTypes.IMMEDIATE_TRANSITION: pass # all are DeterministicTransition elif transition_type == petri_net_element.TransitionTypes.DETERMINISTIC_TRANSITION: execute_transition = self.get_execute_transition( transitions) transitions.remove(execute_transition) # tokens_list = [place.tokens for place in places] unreach_list.append(places) unreach_list.append(tokens_list) unreach_list.append(transitions) # transitions = [execute_transition] # all are EXPONENTIAL_TRANSITION elif transition_type == petri_net_element.TransitionTypes.EXPONENTIAL_TRANSITION: if len(transitions_slices) == 2: self._calculate_probability( transitions_slices, probs_slices, transitions, probs) else: log.show_error( "the code can not analyse 3 parallel exp distribution process" ) else: log.show_error( "the type of the transition is not defined") # all are ExponentialTransition else: log.show_warn( "the types of the enabled transitions are not the same" ) # see algorithm- step1a) if len(transitions) > 0: # fire t and determine the marking m' after firing. self.get_next_state(places, transitions, petri_net, rg_graph, unreach_list, reach, probs)