def delete_tau_transitions(bpmn, counts): from pm4py.objects.bpmn.bpmn_graph 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 recursively_add_tree(parent_tree, tree, bpmn, initial_event, final_event, counts, rec_depth): from pm4py.objects.bpmn.bpmn_graph 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.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.bpmn_graph 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 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
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", " ") 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", " ") 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", " ") 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", "") 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", "") 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", "") 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] = node elif tag.endswith("outgoing"): if node is not None: outgoing_dict[curr_el.text] = node 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 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