Beispiel #1
0
def add_parallel_gateway(bpmn, counts):
    from pm4py.objects.bpmn.bpmn_graph 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)
    join = BPMN.ParallelGateway(name=join_name)
    bpmn.add_node(split)
    bpmn.add_node(join)
    return bpmn, split, join, counts
Beispiel #2
0
def add_xor_gateway(bpmn, counts):
    from pm4py.objects.bpmn.bpmn_graph import BPMN
    counts.inc_xor_gateways()
    split_name = "xor_" + str(counts.num_xor_gateways) + "_split"
    join_name = "xor_" + str(counts.num_xor_gateways) + "_join"

    split = BPMN.ExclusiveGateway(name=split_name)
    join = BPMN.ExclusiveGateway(name=join_name)
    bpmn.add_node(split)
    bpmn.add_node(join)

    return bpmn, split, join, counts
Beispiel #3
0
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.bpmn_graph 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
Beispiel #4
0
def apply(path, parameters=None):
    """
    Imports a BPMN diagram from a file

    Parameters
    -------------
    path
        Path to the file
    parameters
        Parameters of the algorithm

    Returns
    -------------
    bpmn_graph
        BPMN graph
    """
    if parameters is None:
        parameters = {}

    from lxml import etree, objectify

    parser = etree.XMLParser(remove_comments=True)
    xml_tree = objectify.parse(path, parser=parser)
    root = xml_tree.getroot()
    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)
Beispiel #5
0
def add_task(bpmn, counts, label):
    """
    Create a task with the specified label in the BPMN
    """
    from pm4py.objects.bpmn.bpmn_graph import BPMN
    task = BPMN.Task(name=label)
    bpmn.add_node(task)
    return bpmn, task, counts
Beispiel #6
0
def add_tau_task(bpmn, counts):
    """
    Create a task with the specified label in the BPMN
    """
    from pm4py.objects.bpmn.bpmn_graph 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
Beispiel #7
0
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
Beispiel #8
0
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)
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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