def add_parallel_gateway(bpmn, counts): from pm4py.objects.bpmn.obj import BPMN counts.inc_para_gateways() split_name = "parallel_" + str(counts.num_para_gateways) + "_split" join_name = "parallel_" + str(counts.num_para_gateways) + "_join" split = BPMN.ParallelGateway(name=split_name, gateway_direction=BPMN.Gateway.Direction.DIVERGING) join = BPMN.ParallelGateway(name=join_name, gateway_direction=BPMN.Gateway.Direction.CONVERGING) bpmn.add_node(split) bpmn.add_node(join) return bpmn, split, join, counts
def add_inclusive_gateway(bpmn, counts): from pm4py.objects.bpmn.obj import BPMN counts.inc_para_gateways() split_name = "parallel_" + str(counts.num_para_gateways) + "_split" join_name = "parallel_" + str(counts.num_para_gateways) + "_join" split = BPMN.InclusiveGateway(name=split_name) join = BPMN.InclusiveGateway(name=join_name) bpmn.add_node(split) bpmn.add_node(join) return bpmn, split, join, counts
def apply(tree, parameters=None): """ Converts the process tree into a BPMN diagram Parameters -------------- tree Process tree parameters Parameters of the algorithm Returns -------------- bpmn_graph BPMN diagram """ from pm4py.objects.bpmn.obj import BPMN counts = Counts() bpmn = BPMN() start_event = BPMN.StartEvent(name="start", isInterrupting=True) end_event = BPMN.EndEvent(name="end") bpmn.add_node(start_event) bpmn.add_node(end_event) bpmn, counts, _, _ = recursively_add_tree(tree, tree, bpmn, start_event, end_event, counts, 0) bpmn = delete_tau_transitions(bpmn, counts) return bpmn
def add_task(bpmn, counts, label): """ Create a task with the specified label in the BPMN """ from pm4py.objects.bpmn.obj import BPMN task = BPMN.Task(name=label) bpmn.add_node(task) return bpmn, task, counts
def add_tau_task(bpmn, counts): """ Create a task with the specified label in the BPMN """ from pm4py.objects.bpmn.obj import BPMN counts.inc_tau_trans() tau_name = "tau_" + str(counts.num_tau_trans) tau_task = BPMN.Task(name=tau_name) bpmn.add_node(tau_task) counts.append_tau(tau_task) return bpmn, tau_task, counts
def delete_tau_transitions(bpmn, counts): from pm4py.objects.bpmn.obj import BPMN for tau_tran in counts.tau_trans: in_arcs = tau_tran.get_in_arcs() out_arcs = tau_tran.get_out_arcs() if len(in_arcs) > 1 or len(out_arcs) > 1: raise Exception("Tau transition has more than one incoming or outgoing edge!") if in_arcs and out_arcs: out_flow = out_arcs[0] in_flow = in_arcs[0] source = in_flow.get_source() target = out_flow.get_target() bpmn.remove_flow(out_flow) bpmn.remove_flow(in_flow) bpmn.add_flow(BPMN.Flow(source, target)) else: for in_flow in copy.copy(in_arcs): bpmn.remove_flow(in_flow) for out_flow in copy.copy(out_arcs): bpmn.remove_flow(out_flow) bpmn.remove_node(tau_tran) return bpmn
def import_xml_tree_from_root(root): """ Imports a BPMN graph from (the root of) an XML tree Parameters ------------- root Root of the tree Returns ------------- bpmn_graph BPMN graph """ bpmn_graph = BPMN() counts = Counts() incoming_dict = {} outgoing_dict = {} nodes_dict = {} nodes_bounds = {} flow_info = {} return parse_element(bpmn_graph, counts, root, [], incoming_dict, outgoing_dict, nodes_dict, nodes_bounds, flow_info)
def parse_element(bpmn_graph, counts, curr_el, parents, incoming_dict, outgoing_dict, nodes_dict, nodes_bounds, flow_info, process=None, node=None, bpmn_element=None, flow=None, rec_depth=0): """ Parses a BPMN element from the XML file """ tag = curr_el.tag.lower() if tag.endswith("subprocess"): # subprocess invocation name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el.attrib else "" subprocess = BPMN.SubProcess(id=curr_el.get("id"), name=name, process=process, depth=rec_depth) bpmn_graph.add_node(subprocess) node = subprocess process = curr_el.get("id") nodes_dict[process] = node elif tag.endswith("process"): # process of the current subtree process = curr_el.get("id") bpmn_graph.set_process_id(process) elif tag.endswith("shape"): # shape of a node, contains x,y,width,height information bpmn_element = curr_el.get("bpmnElement") elif tag.endswith("task"): # simple task object id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el.attrib else "" #this_type = str(curr_el.tag) #this_type = this_type[this_type.index("}") + 1:] task = BPMN.Task(id=id, name=name, process=process) bpmn_graph.add_node(task) node = task nodes_dict[id] = node elif tag.endswith("startevent"): # start node starting the (sub)process id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el.attrib else "" event_definitions = [child.tag.lower().replace("eventdefinition","") for child in curr_el if child.tag.lower().endswith("eventdefinition")] if len(event_definitions) > 0: event_type = event_definitions[0] if event_type.endswith("message"): start_event = BPMN.MessageStartEvent(id=curr_el.get("id"), name=name, process=process) else: # TODO: expand functionality, support more start event types start_event = BPMN.NormalStartEvent(id=curr_el.get("id"), name=name, process=process) else: start_event = BPMN.NormalStartEvent(id=curr_el.get("id"), name=name, process=process) bpmn_graph.add_node(start_event) node = start_event nodes_dict[id] = node elif tag.endswith("endevent"): # end node ending the (sub)process id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el.attrib else "" event_definitions = [child.tag.lower().replace("eventdefinition","") for child in curr_el if child.tag.lower().endswith("eventdefinition")] if len(event_definitions) > 0: event_type = event_definitions[0] if event_type.endswith("message"): end_event = BPMN.MessageEndEvent(id=curr_el.get("id"), name=name, process=process) elif event_type.endswith("terminate"): end_event = BPMN.TerminateEndEvent(id=curr_el.get("id"), name=name, process=process) elif event_type.endswith("error"): end_event = BPMN.ErrorEndEvent(id=curr_el.get("id"), name=name, process=process) elif event_type.endswith("cancel"): end_event = BPMN.CancelEndEvent(id=curr_el.get("id"), name=name, process=process) else: # TODO: expand functionality, support more start event types end_event = BPMN.NormalEndEvent(id=curr_el.get("id"), name=name, process=process) else: end_event = BPMN.NormalEndEvent(id=curr_el.get("id"), name=name, process=process) bpmn_graph.add_node(end_event) node = end_event nodes_dict[id] = node elif tag.endswith("intermediatecatchevent"): # intermediate event that happens (externally) and can be catched id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el.attrib else "" event_definitions = [child.tag.lower().replace("eventdefinition","") for child in curr_el if child.tag.lower().endswith("eventdefinition")] if len(event_definitions) > 0: event_type = event_definitions[0] if event_type.endswith("message"): intermediate_catch_event = BPMN.MessageIntermediateCatchEvent(id=curr_el.get("id"), name=name, process=process) elif event_type.endswith("error"): intermediate_catch_event = BPMN.ErrorIntermediateCatchEvent(id=curr_el.get("id"), name=name, process=process) elif event_type.endswith("cancel"): intermediate_catch_event = BPMN.CancelIntermediateCatchEvent(id=curr_el.get("id"), name=name, process=process) else: intermediate_catch_event = BPMN.IntermediateCatchEvent(id=curr_el.get("id"), name=name, process=process) else: intermediate_catch_event = BPMN.IntermediateCatchEvent(id=curr_el.get("id"), name=name, process=process) bpmn_graph.add_node(intermediate_catch_event) node = intermediate_catch_event nodes_dict[id] = node elif tag.endswith("intermediatethrowevent"): # intermediate event that is activated through the (sub)process id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el.attrib else "" event_definitions = [child.tag.lower().replace("eventdefinition","") for child in curr_el if child.tag.lower().endswith("eventdefinition")] if len(event_definitions) > 0: event_type = event_definitions[0] if event_type.endswith("message"): intermediate_throw_event = BPMN.MessageIntermediateThrowEvent(id=curr_el.get("id"), name=name, process=process) else: intermediate_throw_event = BPMN.NormalIntermediateThrowEvent(id=curr_el.get("id"), name=name, process=process) else: intermediate_throw_event = BPMN.NormalIntermediateThrowEvent(id=curr_el.get("id"), name=name, process=process) bpmn_graph.add_node(intermediate_throw_event) node = intermediate_throw_event nodes_dict[id] = node elif tag.endswith("boundaryevent"): id = curr_el.get("id") ref_activity = curr_el.get("attachedToRef") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el.attrib else "" event_definitions = [child.tag.lower().replace("eventdefinition","") for child in curr_el if child.tag.lower().endswith("eventdefinition")] if len(event_definitions) > 0: event_type = event_definitions[0] if event_type.endswith("message"): boundary_event = BPMN.MessageBoundaryEvent(id=curr_el.get("id"), name=name, process=process, activity=ref_activity) elif event_type.endswith("error"): boundary_event = BPMN.ErrorBoundaryEvent(id=curr_el.get("id"), name=name, process=process, activity=ref_activity) elif event_type.endswith("cancel"): boundary_event = BPMN.CancelBoundaryEvent(id=curr_el.get("id"), name=name, process=process, activity=ref_activity) else: boundary_event = BPMN.BoundaryEvent(id=curr_el.get("id"), name=name, process=process, activity=ref_activity) else: boundary_event = BPMN.BoundaryEvent(id=curr_el.get("id"), name=name, process=process, activity=ref_activity) bpmn_graph.add_node(boundary_event) node = boundary_event nodes_dict[id] = node elif tag.endswith("edge"): # related to the x, y information of an arc bpmnElement = curr_el.get("bpmnElement") flow = bpmnElement elif tag.endswith("exclusivegateway"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el.attrib else "" try: direction = BPMN.Gateway.Direction[curr_el.get("gatewayDirection").upper()] exclusive_gateway = BPMN.ExclusiveGateway(id=curr_el.get("id"), name=name, gateway_direction=direction, process=process) except: exclusive_gateway = BPMN.ExclusiveGateway(id=curr_el.get("id"), name=name, gateway_direction=BPMN.Gateway.Direction.UNSPECIFIED, process=process) bpmn_graph.add_node(exclusive_gateway) node = exclusive_gateway nodes_dict[id] = node elif tag.endswith("parallelgateway"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el.attrib else "" try: direction = BPMN.Gateway.Direction[curr_el.get("gatewayDirection").upper()] parallel_gateway = BPMN.ParallelGateway(id=curr_el.get("id"), name=name, gateway_direction=direction, process=process) except: parallel_gateway = BPMN.ParallelGateway(id=curr_el.get("id"), name=name, gateway_direction=BPMN.Gateway.Direction.UNSPECIFIED, process=process) bpmn_graph.add_node(parallel_gateway) node = parallel_gateway nodes_dict[id] = node elif tag.endswith("inclusivegateway"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el.attrib else "" try: direction = BPMN.Gateway.Direction[curr_el.get("gatewayDirection").upper()] inclusive_gateway = BPMN.InclusiveGateway(id=curr_el.get("id"), name=name, gateway_direction=direction, process=process) except: inclusive_gateway = BPMN.InclusiveGateway(id=curr_el.get("id"), name=name, gateway_direction=BPMN.Gateway.Direction.UNSPECIFIED, process=process) bpmn_graph.add_node(inclusive_gateway) node = inclusive_gateway nodes_dict[id] = node elif tag.endswith("incoming"): # incoming flow of a node if node is not None: incoming_dict[curr_el.text.strip()] = (node, process, tag) elif tag.endswith("outgoing"): # outgoing flow of a node if node is not None: outgoing_dict[curr_el.text.strip()] = (node, process, tag) elif tag.endswith("sequenceflow"): # normal sequence flow between two nodes seq_flow_id = curr_el.get("id") source_ref = curr_el.get("sourceRef") target_ref = curr_el.get("targetRef") if source_ref is not None and target_ref is not None: incoming_dict[seq_flow_id] = (target_ref, process, tag) outgoing_dict[seq_flow_id] = (source_ref, process, tag) elif tag.endswith("waypoint"): # contains information of x, y values of an edge if flow is not None: x = float(curr_el.get("x")) y = float(curr_el.get("y")) if not flow in flow_info: flow_info[flow] = [] flow_info[flow].append((x, y)) elif tag.endswith("label"): # label of a node, mostly at the end of a shape object bpmn_element = None elif tag.endswith("bounds"): # contains information of width, height, x, y of a node if bpmn_element is not None: x = float(curr_el.get("x")) y = float(curr_el.get("y")) width = float(curr_el.get("width")) height = float(curr_el.get("height")) nodes_bounds[bpmn_element] = {"x": x, "y": y, "width": width, "height": height} for child in curr_el: bpmn_graph = parse_element(bpmn_graph, counts, child, list(parents) + [child], incoming_dict, outgoing_dict, nodes_dict, nodes_bounds, flow_info, process=process, node=node, bpmn_element=bpmn_element, flow=flow, rec_depth=rec_depth + 1) # afterprocessing when the xml tree has been recursively parsed already if rec_depth == 0: # bpmn_graph.set_process_id(process) for seq_flow_id in incoming_dict: if incoming_dict[seq_flow_id][0] in nodes_dict: incoming_dict[seq_flow_id] = (nodes_dict[incoming_dict[seq_flow_id][0]], incoming_dict[seq_flow_id][1], incoming_dict[seq_flow_id][2]) for seq_flow_id in outgoing_dict: if outgoing_dict[seq_flow_id][0] in nodes_dict: outgoing_dict[seq_flow_id] = (nodes_dict[outgoing_dict[seq_flow_id][0]], outgoing_dict[seq_flow_id][1], outgoing_dict[seq_flow_id][2]) for flow_id in flow_info: if flow_id in outgoing_dict and flow_id in incoming_dict: if isinstance(outgoing_dict[flow_id][0], BPMN.BPMNNode) and isinstance(incoming_dict[flow_id][0], BPMN.BPMNNode): flow = BPMN.SequenceFlow(outgoing_dict[flow_id][0], incoming_dict[flow_id][0], id=flow_id, name="", process=outgoing_dict[flow_id][1]) bpmn_graph.add_flow(flow) flow.del_waypoints() for waypoint in flow_info[flow_id]: flow.add_waypoint(waypoint) for node_id in nodes_bounds: if node_id in nodes_dict: bounds = nodes_bounds[node_id] node = nodes_dict[node_id] node.set_x(bounds["x"]) node.set_y(bounds["y"]) node.set_width(bounds["width"]) node.set_height(bounds["height"]) return bpmn_graph
def parse_element(bpmn_graph, counts, curr_el, parents, incoming_dict, outgoing_dict, nodes_dict, nodes_bounds, flow_info, process=None, node=None, bpmn_element=None, flow=None, rec_depth=0): """ Parses a BPMN element from the XML file """ tag = curr_el.tag.lower() if tag.endswith("process"): process = curr_el.get("id") elif tag.endswith("shape"): bpmn_element = curr_el.get("bpmnElement") elif tag.endswith("task"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") this_type = str(curr_el.tag) this_type = this_type[this_type.index("}") + 1:] task = BPMN.Task(name=name, type=this_type) bpmn_graph.add_node(task) node = task nodes_dict[id] = node elif tag.endswith("startevent"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el else str(uuid.uuid4()) start_event = BPMN.StartEvent(name=name) bpmn_graph.add_node(start_event) node = start_event nodes_dict[id] = node elif tag.endswith("endevent"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el else str(uuid.uuid4()) end_event = BPMN.EndEvent(name=name) bpmn_graph.add_node(end_event) node = end_event nodes_dict[id] = node elif tag.endswith("event"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", " ").replace("\n", " ") if "name" in curr_el else str(uuid.uuid4()) this_type = str(curr_el.tag) this_type = this_type[this_type.index("}") + 1:] other_event = BPMN.OtherEvent(name=name, type=this_type) bpmn_graph.add_node(other_event) node = other_event nodes_dict[id] = node elif tag.endswith("edge"): bpmnElement = curr_el.get("bpmnElement") flow = bpmnElement elif tag.endswith("exclusivegateway"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el else str(uuid.uuid4()) exclusive_gateway = BPMN.ExclusiveGateway(name=name) bpmn_graph.add_node(exclusive_gateway) node = exclusive_gateway nodes_dict[id] = node elif tag.endswith("parallelgateway"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el else str(uuid.uuid4()) parallel_gateway = BPMN.ParallelGateway(name=name) bpmn_graph.add_node(parallel_gateway) node = parallel_gateway nodes_dict[id] = node elif tag.endswith("inclusivegateway"): id = curr_el.get("id") name = curr_el.get("name").replace("\r", "").replace("\n", "") if "name" in curr_el else str(uuid.uuid4()) inclusive_gateway = BPMN.InclusiveGateway(name=name) bpmn_graph.add_node(inclusive_gateway) node = inclusive_gateway nodes_dict[id] = node elif tag.endswith("incoming"): if node is not None: incoming_dict[curr_el.text.strip()] = node elif tag.endswith("outgoing"): if node is not None: outgoing_dict[curr_el.text.strip()] = node elif tag.endswith("sequenceflow"): seq_flow_id = curr_el.get("id") source_ref = curr_el.get("sourceRef") target_ref = curr_el.get("targetRef") # fix 28/04/2021: do not assume anymore to read the nodes before the edges incoming_dict[seq_flow_id] = target_ref outgoing_dict[seq_flow_id] = source_ref elif tag.endswith("waypoint"): if flow is not None: x = float(curr_el.get("x")) y = float(curr_el.get("y")) if not flow in flow_info: flow_info[flow] = [] flow_info[flow].append((x, y)) elif tag.endswith("label"): bpmn_element = None elif tag.endswith("bounds"): if bpmn_element is not None: x = float(curr_el.get("x")) y = float(curr_el.get("y")) width = float(curr_el.get("width")) height = float(curr_el.get("height")) nodes_bounds[bpmn_element] = {"x": x, "y": y, "width": width, "height": height} for child in curr_el: bpmn_graph = parse_element(bpmn_graph, counts, child, list(parents) + [child], incoming_dict, outgoing_dict, nodes_dict, nodes_bounds, flow_info, process=process, node=node, bpmn_element=bpmn_element, flow=flow, rec_depth=rec_depth + 1) if rec_depth == 0: for seq_flow_id in incoming_dict: if incoming_dict[seq_flow_id] in nodes_dict: incoming_dict[seq_flow_id] = nodes_dict[incoming_dict[seq_flow_id]] for seq_flow_id in outgoing_dict: if outgoing_dict[seq_flow_id] in nodes_dict: outgoing_dict[seq_flow_id] = nodes_dict[outgoing_dict[seq_flow_id]] for flow_id in flow_info: if flow_id in outgoing_dict and flow_id in incoming_dict: flow = BPMN.Flow(outgoing_dict[flow_id], incoming_dict[flow_id]) bpmn_graph.add_flow(flow) flow.del_waypoints() for waypoint in flow_info[flow_id]: flow.add_waypoint(waypoint) for node_id in nodes_bounds: if node_id in nodes_dict: bounds = nodes_bounds[node_id] node = nodes_dict[node_id] node.set_x(bounds["x"]) node.set_y(bounds["y"]) node.set_width(bounds["width"]) node.set_height(bounds["height"]) return bpmn_graph
def recursively_add_tree(parent_tree, tree, bpmn, initial_event, final_event, counts, rec_depth): from pm4py.objects.bpmn.obj import BPMN tree_childs = [child for child in tree.children] initial_connector = None final_connector = None if tree.operator is None: trans = tree if trans.label is None: bpmn, task, counts = add_tau_task(bpmn, counts) bpmn.add_flow(BPMN.Flow(initial_event, task)) bpmn.add_flow(BPMN.Flow(task, final_event)) initial_connector = task final_connector = task else: bpmn, task, counts = add_task(bpmn, counts, trans.label) bpmn.add_flow(BPMN.Flow(initial_event, task)) bpmn.add_flow(BPMN.Flow(task, final_event)) initial_connector = task final_connector = task elif tree.operator == Operator.XOR: bpmn, split_gateway, join_gateway, counts = add_xor_gateway(bpmn, counts) for subtree in tree_childs: bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway, join_gateway, counts, rec_depth + 1) bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) bpmn.add_flow(BPMN.Flow(join_gateway, final_event)) initial_connector = split_gateway final_connector = join_gateway elif tree.operator == Operator.PARALLEL: bpmn, split_gateway, join_gateway, counts = add_parallel_gateway(bpmn, counts) for subtree in tree_childs: bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway, join_gateway, counts, rec_depth + 1) bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) bpmn.add_flow(BPMN.Flow(join_gateway, final_event)) initial_connector = split_gateway final_connector = join_gateway elif tree.operator == Operator.OR: bpmn, split_gateway, join_gateway, counts = add_inclusive_gateway(bpmn, counts) for subtree in tree_childs: bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway, join_gateway, counts, rec_depth + 1) bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) bpmn.add_flow(BPMN.Flow(join_gateway, final_event)) initial_connector = split_gateway final_connector = join_gateway elif tree.operator == Operator.SEQUENCE: initial_intermediate_task = initial_event bpmn, final_intermediate_task, counts = add_tau_task(bpmn, counts) for i in range(len(tree_childs)): bpmn, counts, initial_connect, final_connect = recursively_add_tree(tree, tree_childs[i], bpmn, initial_intermediate_task, final_intermediate_task, counts, rec_depth + 1) initial_intermediate_task = final_connect if i == 0: initial_connector = initial_connect if i == len(tree_childs) - 2: final_intermediate_task = final_event else: bpmn, final_intermediate_task, counts = add_tau_task(bpmn, counts) final_connector = final_connect elif tree.operator == Operator.LOOP: if len(tree_childs) != 2: raise Exception("Loop doesn't have 2 childs") else: do = tree_childs[0] redo = tree_childs[1] bpmn, split, join, counts = add_xor_gateway(bpmn, counts) bpmn, counts, i, y = recursively_add_tree(tree, do, bpmn, join, split, counts, rec_depth + 1) bpmn, counts, x, y = recursively_add_tree(tree, redo, bpmn, split, join, counts, rec_depth + 1) bpmn.add_flow(BPMN.Flow(initial_event, join)) bpmn.add_flow(BPMN.Flow(split, final_event)) initial_connector = join final_connector = split return bpmn, counts, initial_connector, final_connector
def apply(net, im, fm, parameters=None): """ Converts an accepting Petri net into a BPMN diagram Parameters -------------- accepting_petri_net Accepting Petri net (list containing net + im + fm) parameters Parameters of the algorithm Returns -------------- bpmn_graph BPMN diagram """ if parameters is None: parameters = {} from pm4py.objects.bpmn.obj import BPMN from pm4py.objects.bpmn.util import reduction bpmn_graph = BPMN() entering_dictio = {} exiting_dictio = {} for place in net.places: node = BPMN.ExclusiveGateway() bpmn_graph.add_node(node) entering_dictio[place] = node exiting_dictio[place] = node for trans in net.transitions: if trans.label is None: if len(trans.in_arcs) > 1 or len(trans.out_arcs) > 1: node = BPMN.ParallelGateway() else: node = BPMN.ExclusiveGateway() bpmn_graph.add_node(node) entering_dictio[trans] = node exiting_dictio[trans] = node else: if len(trans.in_arcs) > 1: entering_node = BPMN.ParallelGateway() else: entering_node = BPMN.ExclusiveGateway() if len(trans.out_arcs) > 1: exiting_node = BPMN.ParallelGateway() else: exiting_node = BPMN.ExclusiveGateway() task = BPMN.Task(name=trans.label) bpmn_graph.add_node(task) bpmn_graph.add_flow(BPMN.Flow(entering_node, task)) bpmn_graph.add_flow(BPMN.Flow(task, exiting_node)) entering_dictio[trans] = entering_node exiting_dictio[trans] = exiting_node for arc in net.arcs: bpmn_graph.add_flow( BPMN.Flow(exiting_dictio[arc.source], entering_dictio[arc.target])) start_node = BPMN.StartEvent() end_node = BPMN.EndEvent() bpmn_graph.add_node(start_node) bpmn_graph.add_node(end_node) for place in im: bpmn_graph.add_flow(BPMN.Flow(start_node, entering_dictio[place])) for place in fm: bpmn_graph.add_flow(BPMN.Flow(exiting_dictio[place], end_node)) bpmn_graph = reduction.apply(bpmn_graph) return bpmn_graph
def apply(net, im, fm, parameters=None): """ Converts an accepting Petri net into a BPMN diagram Parameters -------------- accepting_petri_net Accepting Petri net (list containing net + im + fm) parameters Parameters of the algorithm Returns -------------- bpmn_graph BPMN diagram """ if parameters is None: parameters = {} from pm4py.objects.bpmn.obj import BPMN from pm4py.objects.bpmn.util import reduction bpmn_graph = BPMN() entering_dictio = {} exiting_dictio = {} for place in net.places: node = BPMN.ExclusiveGateway() bpmn_graph.add_node(node) entering_dictio[place] = node exiting_dictio[place] = node for trans in net.transitions: if trans.label is None: if len(trans.in_arcs) > 1: node = BPMN.ParallelGateway(gateway_direction=BPMN.Gateway.Direction.CONVERGING) elif len(trans.out_arcs) > 1: node = BPMN.ParallelGateway(gateway_direction=BPMN.Gateway.Direction.DIVERGING) else: node = BPMN.ExclusiveGateway(gateway_direction=BPMN.Gateway.Direction.UNSPECIFIED) bpmn_graph.add_node(node) entering_dictio[trans] = node exiting_dictio[trans] = node else: if len(trans.in_arcs) > 1: entering_node = BPMN.ParallelGateway(gateway_direction=BPMN.Gateway.Direction.CONVERGING) else: entering_node = BPMN.ExclusiveGateway(gateway_direction=BPMN.Gateway.Direction.UNSPECIFIED) if len(trans.out_arcs) > 1: exiting_node = BPMN.ParallelGateway(gateway_direction=BPMN.Gateway.Direction.DIVERGING) else: exiting_node = BPMN.ExclusiveGateway(gateway_direction=BPMN.Gateway.Direction.UNSPECIFIED) task = BPMN.Task(name=trans.label) bpmn_graph.add_node(task) bpmn_graph.add_flow(BPMN.Flow(entering_node, task)) bpmn_graph.add_flow(BPMN.Flow(task, exiting_node)) entering_dictio[trans] = entering_node exiting_dictio[trans] = exiting_node for arc in net.arcs: bpmn_graph.add_flow(BPMN.Flow(exiting_dictio[arc.source], entering_dictio[arc.target])) start_node = BPMN.StartEvent(name="start", isInterrupting=True) end_node = BPMN.NormalEndEvent(name="end") bpmn_graph.add_node(start_node) bpmn_graph.add_node(end_node) for place in im: bpmn_graph.add_flow(BPMN.Flow(start_node, entering_dictio[place])) for place in fm: bpmn_graph.add_flow(BPMN.Flow(exiting_dictio[place], end_node)) bpmn_graph = reduction.apply(bpmn_graph) for node in bpmn_graph.get_nodes(): node.set_process(bpmn_graph.get_process_id()) for edge in bpmn_graph.get_flows(): edge.set_process(bpmn_graph.get_process_id()) return bpmn_graph
def reduce_xor_gateways(bpmn_graph, parameters=None): """ Reduces the number of XOR gateways in the diagram Parameters ------------ bpmn_graph BPMN graph parameters Parameters Returns ------------ bpmn_graph (possibly reduced) BPMN graph """ if parameters is None: parameters = {} changed = True while changed: changed = False outgoing_edges = None incoming_edges = None outgoing_edges = {} incoming_edges = {} for flow in bpmn_graph.get_flows(): source = flow.get_source() target = flow.get_target() if source not in outgoing_edges: outgoing_edges[source] = set() outgoing_edges[source].add(flow) if target not in incoming_edges: incoming_edges[target] = set() incoming_edges[target].add(flow) nodes = list(bpmn_graph.get_nodes()) for node in nodes: if isinstance(node, BPMN.ExclusiveGateway): if node in outgoing_edges and node in incoming_edges and len( outgoing_edges[node]) == 1 and len( incoming_edges[node]) == 1: changed = True source_node = None target_node = None for flow in incoming_edges[node]: source_node = flow.get_source() if flow in bpmn_graph.get_flows(): bpmn_graph.remove_flow(flow) for flow in outgoing_edges[node]: target_node = flow.get_target() if flow in bpmn_graph.get_flows(): bpmn_graph.remove_flow(flow) if node in bpmn_graph.get_nodes(): bpmn_graph.remove_node(node) bpmn_graph.add_flow(BPMN.Flow(source_node, target_node)) break return bpmn_graph