Ejemplo n.º 1
0
def reduce(bottomup_nodes: List[ProcessTree], fps: Dict[str, Any],
           activities: Set[str]) -> ProcessTree:
    """
    Reduce a process tree replacing the skippable elements that have empty intersection with the
    trace.

    Parameters
    -----------------
    bottomup_nodes
        List of nodes of the process tree (that are process trees by themselves) in a bottomup order
    fps
        Footprints of the process tree
    activities
        Set of activities in the trace

    Returns
    ------------------
    tree
        Reduced process tree
    """
    i = 0
    while i < len(bottomup_nodes) - 1:
        node = bottomup_nodes[i]
        parent = node.parent

        is_skippable = fps[id(node)][Outputs.SKIPPABLE.value]
        node_activities = fps[id(node)][Outputs.ACTIVITIES.value]

        if is_skippable and not node_activities.intersection(activities):
            pt = ProcessTree()
            pt.parent = parent
            parent.children[parent.children.index(node)] = pt
        i = i + 1

    return fold(bottomup_nodes[-1])
Ejemplo n.º 2
0
 def __init__(self, tree):
     i = 0
     while i < len(tree.children):
         tree.children[i] = GenerationTree(tree.children[i])
         tree.children[i].parent = self
         i = i + 1
     ProcessTree.__init__(self, operator=tree.operator, parent=tree.parent, children=tree.children, label=tree.label)
Ejemplo n.º 3
0
def execute_enabled(enabled, open, closed, execution_sequence=None):
    """
    Execute an enabled node of the process tree

    Parameters
    -----------
    enabled
        Enabled nodes
    open
        Open nodes
    closed
        Closed nodes
    execution_sequence
        Execution sequence

    Returns
    -----------
    execution_sequence
        Execution sequence
    """
    execution_sequence = list() if execution_sequence is None else execution_sequence
    vertex = random.sample(list(enabled), 1)[0]
    enabled.remove(vertex)
    open.add(vertex)
    execution_sequence.append((vertex, pt_st.State.OPEN))
    if len(vertex.children) > 0:
        if vertex.operator is pt_opt.Operator.LOOP:
            while len(vertex.children) < 3:
                vertex.children.append(ProcessTree(parent=vertex))
        if vertex.operator is pt_opt.Operator.SEQUENCE or vertex.operator is pt_opt.Operator.LOOP:
            c = vertex.children[0]
            enabled.add(c)
            execution_sequence.append((c, pt_st.State.ENABLED))
        elif vertex.operator is pt_opt.Operator.PARALLEL:
            enabled |= set(vertex.children)
            for x in vertex.children:
                if x in closed:
                    closed.remove(x)
            map(lambda c: execution_sequence.append((c, pt_st.State.ENABLED)), vertex.children)
        elif vertex.operator is pt_opt.Operator.XOR:
            vc = vertex.children
            c = vc[random.randint(0, len(vc) - 1)]
            enabled.add(c)
            execution_sequence.append((c, pt_st.State.ENABLED))
        elif vertex.operator is pt_opt.Operator.OR:
            some_children = [c for c in vertex.children if random.random() < 0.5]
            enabled |= set(some_children)
            for x in some_children:
                if x in closed:
                    closed.remove(x)
            map(lambda c: execution_sequence.append((c, pt_st.State.ENABLED)), some_children)
        elif vertex.operator is pt_opt.Operator.INTERLEAVING:
            random.shuffle(vertex.children)
            c = vertex.children[0]
            enabled.add(c)
            execution_sequence.append((c, pt_st.State.ENABLED))
    else:
        close(vertex, enabled, open, closed, execution_sequence)
    return execution_sequence
Ejemplo n.º 4
0
def process_tree_to_binary_process_tree(tree: ProcessTree) -> ProcessTree:
    if len(tree.children) > 2:
        left_tree = tree.children[0]

        right_tree_op = tree.operator
        if tree.operator == pt_op.Operator.LOOP:
            right_tree_op = pt_op.Operator.XOR

        right_tree = ProcessTree(operator=right_tree_op,
                                 parent=tree,
                                 children=tree.children[1:])
        for child in right_tree.children:
            child.parent = right_tree

        tree.children = [left_tree, right_tree]

    for child in tree.children:
        process_tree_to_binary_process_tree(child)

    return tree
Ejemplo n.º 5
0
def calculate_optimal_alignment(pt: ProcessTree, trace: Trace, parameters=None):
    if parameters is None:
        parameters = {}
    align_variant = exec_utils.get_param_value(Parameters.CLASSIC_ALIGNMENTS_VARIANT, parameters,
                                               Variants.VERSION_STATE_EQUATION_A_STAR)
    conversion_version = exec_utils.get_param_value(Parameters.CONVERSION_VERSION, parameters,
                                                    pt_converter.Variants.TO_PETRI_NET_TRANSITION_BORDERED)

    parent = pt.parent
    pt.parent = None
    net, im, fm = pt_converter.apply(pt, variant=conversion_version)

    # in this way, also the other parameters are passed to alignments
    alignment_parameters = copy(parameters)
    alignment_parameters[AlignParameters.PARAM_ALIGNMENT_RESULT_IS_SYNC_PROD_AWARE] = True

    alignment = get_alignment(trace, net, im, fm, variant=align_variant,
                              parameters=alignment_parameters)

    pt.parent = parent
    res = []

    # if the alignment has terminated prematurely due to time constraints, raise an Exception
    if alignment is None:
        raise AlignmentNoneException("alignment terminated prematurely")

    if conversion_version == pt_converter.Variants.TO_PETRI_NET_TRANSITION_BORDERED or conversion_version == pt_converter.Variants.TO_PETRI_NET_TRANSITION_BORDERED.value:
        # remove invisible model moves from alignment steps that do not belong to a silent model move in the process tree
        # this is possible only if the TO_PETRI_NET_TRANSITION_BORDERED variant is used
        for a in alignment["alignment"]:
            if not (a[0][0] == SKIP and not a[0][1].isdigit()):
                res.append(a[1])
    else:
        for a in alignment["alignment"]:
            res.append(a[1])

    return res
Ejemplo n.º 6
0
def process_tree_to_binary_process_tree(pt: ProcessTree) -> ProcessTree:
    if len(pt.children) > 2:
        new_subtree = ProcessTree()
        new_subtree.operator = pt.operator
        new_subtree.children = pt.children[1:]
        pt.children = pt.children[:1]
        pt.children.append(new_subtree)
        new_subtree.parent = pt
    for c in pt.children:
        process_tree_to_binary_process_tree(c)
    return pt
Ejemplo n.º 7
0
def execute_script():
    root = ProcessTree(operator=Operator.SEQUENCE)

    choice = ProcessTree(operator=Operator.XOR, parent=root)
    parallel = ProcessTree(operator=Operator.PARALLEL, parent=root)

    root.children.append(choice)
    root.children.append(parallel)

    leaf_A = ProcessTree(label="A", parent=choice)
    leaf_B = ProcessTree(label="B", parent=choice)
    leaf_C = ProcessTree(label="C", parent=choice)

    choice.children.append(leaf_A)
    choice.children.append(leaf_B)
    choice.children.append(leaf_C)

    leaf_D = ProcessTree(label="D", parent=parallel)
    leaf_E = ProcessTree(label="E", parent=parallel)
    leaf_F = ProcessTree(label="F", parent=parallel)

    parallel.children.append(leaf_D)
    parallel.children.append(leaf_E)
    parallel.children.append(leaf_F)

    pm4py.view_process_tree(root, format="svg")

    # remove leaf_C from choice
    choice.children.remove(leaf_C)

    # remove the leaf with label "E" from parallel
    parallel.children.remove([
        parallel.children[i] for i in range(len(parallel.children))
        if parallel.children[i].label == "E"
    ][0])

    pm4py.view_process_tree(root, format="svg")
Ejemplo n.º 8
0
def get_repr(spec_tree_struct, rec_depth, contains_empty_traces=False):
    """
    Get the representation of a process tree

    Parameters
    -----------
    spec_tree_struct
        Internal tree structure (after application of Inductive Miner)
    rec_depth
        Current recursion depth
    contains_empty_traces
        Boolean value that is True if the event log from which the DFG has been extracted contains empty traces

    Returns
    -----------
    final_tree_repr
        Representation of the tree (could be printed, transformed, viewed)
    """

    need_loop_on_subtree = check_loop_need(spec_tree_struct)

    if contains_empty_traces and rec_depth == 0:
        rec_depth = rec_depth + 1

    child_tree = None
    if spec_tree_struct.detected_cut == "flower" or (
            spec_tree_struct.detected_cut == "base_xor"
            and need_loop_on_subtree):
        final_tree_repr = ProcessTree(operator=Operator.LOOP)
        child_tree = ProcessTree(operator=Operator.XOR)
        child_tree_redo = ProcessTree(label=None)
        #child_tree_exit = ProcessTree(label=None)
        final_tree_repr.children.append(child_tree)
        final_tree_repr.children.append(child_tree_redo)
        #final_tree_repr.children.append(child_tree_exit)
        child_tree.parent = final_tree_repr
        child_tree_redo.parent = final_tree_repr
        #child_tree_exit.parent = final_tree_repr
    elif spec_tree_struct.detected_cut == "base_xor":
        if len(spec_tree_struct.activities
               ) > 1 or spec_tree_struct.must_insert_skip:
            final_tree_repr = ProcessTree(operator=Operator.XOR)
            child_tree = final_tree_repr
        else:
            final_tree_repr = ProcessTree(operator=None, label=None)
    elif spec_tree_struct.detected_cut == "sequential":
        if spec_tree_struct.need_loop_on_subtree:
            final_tree_repr = ProcessTree(operator=Operator.LOOP)
            child_tree = ProcessTree(operator=Operator.SEQUENCE)
            child_tree.parent = final_tree_repr
            final_tree_repr.children.append(child_tree)
            child = ProcessTree()
            final_tree_repr.children.append(child)
            child.parent = final_tree_repr
        else:
            final_tree_repr = ProcessTree(operator=Operator.SEQUENCE)
            child_tree = final_tree_repr
    elif spec_tree_struct.detected_cut == "loopCut":
        final_tree_repr = ProcessTree(operator=Operator.LOOP)
        child_tree = final_tree_repr
    elif spec_tree_struct.detected_cut == "xor":
        final_tree_repr = ProcessTree(operator=Operator.XOR)
        child_tree = final_tree_repr
    elif spec_tree_struct.detected_cut == "parallel":
        final_tree_repr = ProcessTree(operator=Operator.PARALLEL)
        child_tree = final_tree_repr

    if spec_tree_struct.detected_cut == "base_xor" or spec_tree_struct.detected_cut == "flower":
        for act in spec_tree_struct.activities:
            if child_tree is None:
                new_vis_trans = get_transition(act)
                child_tree = new_vis_trans
                final_tree_repr = child_tree
            else:
                new_vis_trans = get_transition(act)
                child_tree.children.append(new_vis_trans)
                new_vis_trans.parent = child_tree
    if spec_tree_struct.detected_cut == "sequential" or spec_tree_struct.detected_cut == "loopCut":
        for ch in spec_tree_struct.children:
            child = get_repr(ch, rec_depth + 1)
            child_tree.children.append(child)
            child.parent = child_tree

        if spec_tree_struct.detected_cut == "loopCut" and len(
                spec_tree_struct.children) < 2:
            while len(spec_tree_struct.children) < 2:
                child = ProcessTree()
                child_tree.children.append(child)
                child.parent = child_tree
                spec_tree_struct.children.append(
                    ProcessTree(operator=None,
                                label=None,
                                parent=spec_tree_struct))

    if spec_tree_struct.detected_cut == "parallel":
        for child in spec_tree_struct.children:
            child_final = get_repr(child, rec_depth + 1)
            child_tree.children.append(child_final)
            child_final.parent = child_tree

    if spec_tree_struct.detected_cut == "xor":
        for child in spec_tree_struct.children:
            child_final = get_repr(child, rec_depth + 1)
            child_tree.children.append(child_final)
            child_final.parent = child_tree

    if spec_tree_struct.must_insert_skip:
        skip = get_new_hidden_trans()
        if spec_tree_struct.detected_cut == "base_xor":
            child_tree.children.append(skip)
            skip.parent = child_tree
        else:
            master_tree_repr = ProcessTree(operator=Operator.XOR)
            master_tree_repr.children.append(final_tree_repr)
            final_tree_repr.parent = master_tree_repr

            master_tree_repr.children.append(skip)
            skip.parent = master_tree_repr

            return master_tree_repr

    if contains_empty_traces and rec_depth == 1:
        master_tree_repr = ProcessTree(operator=Operator.XOR)
        master_tree_repr.children.append(final_tree_repr)
        final_tree_repr.parent = master_tree_repr

        skip_transition = ProcessTree()

        master_tree_repr.children.append(skip_transition)
        skip_transition.parent = master_tree_repr

        return master_tree_repr

    return final_tree_repr
Ejemplo n.º 9
0
def get_new_hidden_trans():
    """
    Create a hidden node (transition) in the process tree
    """
    return ProcessTree(operator=None, label=None)
Ejemplo n.º 10
0
def get_transition(label):
    """
    Create a node (transition) with the specified label in the process tree
    """
    return ProcessTree(operator=None, label=label)
Ejemplo n.º 11
0
def get_repr(spec_tree_struct, rec_depth, contains_empty_traces=False):
    """
    Get the representation of a process tree

    Parameters
    -----------
    spec_tree_struct
        Internal tree structure (after application of Inductive Miner)
    rec_depth
        Current recursion depth
    contains_empty_traces
        Boolean value that is True if the event log from which the DFG has been extracted contains empty traces

    Returns
    -----------
    final_tree_repr
        Representation of the tree (could be printed, transformed, viewed)
    """

    activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, spec_tree_struct.parameters,
                                              xes_constants.DEFAULT_NAME_KEY)

    base_cases = ('empty_log', 'single_activity')
    cut = ('concurrent', 'sequential', 'parallel', 'loopCut')
    # note that the activity_once_per_trace is not included here, as it is can be dealt with as a parallel cut
    fall_throughs = ('empty_trace', 'strict_tau_loop', 'tau_loop', 'flower')

    # if a cut was detected in the current subtree:
    if spec_tree_struct.detected_cut in cut:
        if spec_tree_struct.detected_cut == "sequential":
            final_tree_repr = ProcessTree(operator=Operator.SEQUENCE)
        elif spec_tree_struct.detected_cut == "loopCut":
            final_tree_repr = ProcessTree(operator=Operator.LOOP)
        elif spec_tree_struct.detected_cut == "concurrent":
            final_tree_repr = ProcessTree(operator=Operator.XOR)
        elif spec_tree_struct.detected_cut == "parallel":
            final_tree_repr = ProcessTree(operator=Operator.PARALLEL)


        if not (spec_tree_struct.detected_cut == "loopCut" and len(spec_tree_struct.children) >= 3):
            for ch in spec_tree_struct.children:
                # get the representation of the current child (from children in the subtree-structure):
                child = get_repr(ch, rec_depth + 1)
                # add connection from child_tree to child_final and the other way around:
                final_tree_repr.children.append(child)
                child.parent = final_tree_repr
        
        else:
            child = get_repr(spec_tree_struct.children[0], rec_depth + 1)
            final_tree_repr.children.append(child)
            child.parent = final_tree_repr

            redo_child = ProcessTree(operator=Operator.XOR)
            for ch in spec_tree_struct.children[1:]:
                child = get_repr(ch, rec_depth + 1)
                redo_child.children.append(child)
                child.parent = redo_child
            
            final_tree_repr.children.append(redo_child)
            redo_child.parent = final_tree_repr

        if spec_tree_struct.detected_cut == "loopCut" and len(spec_tree_struct.children) < 3:
            while len(spec_tree_struct.children) < 2:
                child = ProcessTree()
                final_tree_repr.children.append(child)
                child.parent = final_tree_repr
                spec_tree_struct.children.append(None)
        


    if spec_tree_struct.detected_cut in base_cases:
        # in the base case of an empty log, we only return a silent transition
        if spec_tree_struct.detected_cut == "empty_log":
            return ProcessTree(operator=None, label=None)
        # in the base case of a single activity, we return a tree consisting of the single activity
        elif spec_tree_struct.detected_cut == "single_activity":
            act_a = spec_tree_struct.log[0][0][activity_key]
            return ProcessTree(operator=None, label=act_a)

    if spec_tree_struct.detected_cut in fall_throughs:
        if spec_tree_struct.detected_cut == "empty_trace":
            # should return XOR(tau, IM(L') )
            final_tree_repr = ProcessTree(operator=Operator.XOR)
            final_tree_repr.children.append(ProcessTree(operator=None, label=None))
            # iterate through all children of the current node
            for ch in spec_tree_struct.children:
                child = get_repr(ch, rec_depth + 1)
                final_tree_repr.children.append(child)
                child.parent = final_tree_repr

        elif spec_tree_struct.detected_cut == "strict_tau_loop" or spec_tree_struct.detected_cut == "tau_loop":
            # should return LOOP( IM(L'), tau)
            final_tree_repr = ProcessTree(operator=Operator.LOOP)
            # iterate through all children of the current node
            if spec_tree_struct.children:
                for ch in spec_tree_struct.children:
                    child = get_repr(ch, rec_depth + 1)
                    final_tree_repr.children.append(child)
                    child.parent = final_tree_repr
            else:
                for ch in spec_tree_struct.activities:
                    child = get_transition(ch)
                    final_tree_repr.append(child)
                    child.parent = final_tree_repr

            # add a silent tau transition as last child of the current node
            final_tree_repr.children.append(ProcessTree(operator=None, label=None))

        elif spec_tree_struct.detected_cut == "flower":
            # should return something like LOOP(XOR(a,b,c,d,...), tau)
            final_tree_repr = ProcessTree(operator=Operator.LOOP)
            xor_child = ProcessTree(operator=Operator.XOR, parent=final_tree_repr)
            # append all the activities in the current subtree to the XOR part to allow for any behaviour
            for ch in spec_tree_struct.activities:
                child = get_transition(ch)
                xor_child.children.append(child)
                child.parent = xor_child
            final_tree_repr.children.append(xor_child)
            # now add the tau to the children to get the wanted output
            final_tree_repr.children.append(ProcessTree(operator=None, label=None))

    return final_tree_repr
Ejemplo n.º 12
0
def recursively_add_tree(parent_tree,
                         tree,
                         net,
                         initial_entity_subtree,
                         final_entity_subtree,
                         counts,
                         rec_depth,
                         force_add_skip=False):
    """
    Recursively add the subtrees to the Petri net

    Parameters
    -----------
    parent_tree
        Parent tree
    tree
        Current subtree
    net
        Petri net
    initial_entity_subtree
        Initial entity (place/transition) that should be attached from the subtree
    final_entity_subtree
        Final entity (place/transition) that should be attached from the subtree
    counts
        Counts object (keeps the number of places, transitions and hidden transitions)
    rec_depth
        Recursion depth of the current iteration
    force_add_skip
        Boolean value that tells if the addition of a skip is mandatory

    Returns
    ----------
    net
        Updated Petri net
    counts
        Updated counts object (keeps the number of places, transitions and hidden transitions)
    final_place
        Last place added in this recursion
    """
    if type(initial_entity_subtree) is PetriNet.Transition:
        initial_place = get_new_place(counts)
        net.places.add(initial_place)
        add_arc_from_to(initial_entity_subtree, initial_place, net)
    else:
        initial_place = initial_entity_subtree
    if final_entity_subtree is not None and type(
            final_entity_subtree) is PetriNet.Place:
        final_place = final_entity_subtree
    else:
        final_place = get_new_place(counts)
        net.places.add(final_place)
        if final_entity_subtree is not None and type(
                final_entity_subtree) is PetriNet.Transition:
            add_arc_from_to(final_place, final_entity_subtree, net)
    tree_childs = [child for child in tree.children]

    if force_add_skip:
        invisible = get_new_hidden_trans(counts, type_trans="skip")
        add_arc_from_to(initial_place, invisible, net)
        add_arc_from_to(invisible, final_place, net)

    if tree.operator is None:
        trans = tree
        if trans.label is None:
            petri_trans = get_new_hidden_trans(counts, type_trans="skip")
        else:
            petri_trans = get_transition(counts, trans.label)
        net.transitions.add(petri_trans)
        add_arc_from_to(initial_place, petri_trans, net)
        add_arc_from_to(petri_trans, final_place, net)

    if tree.operator == Operator.XOR:
        for subtree in tree_childs:
            net, counts, intermediate_place = recursively_add_tree(
                tree, subtree, net, initial_place, final_place, counts,
                rec_depth + 1)
    elif tree.operator == Operator.OR:
        new_initial_trans = get_new_hidden_trans(counts, type_trans="tauSplit")
        net.transitions.add(new_initial_trans)
        add_arc_from_to(initial_place, new_initial_trans, net)
        new_final_trans = get_new_hidden_trans(counts, type_trans="tauJoin")
        net.transitions.add(new_final_trans)
        add_arc_from_to(new_final_trans, final_place, net)
        terminal_place = get_new_place(counts)
        net.places.add(terminal_place)
        add_arc_from_to(terminal_place, new_final_trans, net)
        first_place = get_new_place(counts)
        net.places.add(first_place)
        add_arc_from_to(new_initial_trans, first_place, net)

        for subtree in tree_childs:
            subtree_init_place = get_new_place(counts)
            net.places.add(subtree_init_place)
            add_arc_from_to(new_initial_trans, subtree_init_place, net)
            subtree_start_place = get_new_place(counts)
            net.places.add(subtree_start_place)
            subtree_end_place = get_new_place(counts)
            net.places.add(subtree_end_place)
            trans_start = get_new_hidden_trans(counts,
                                               type_trans="inclusiveStart")
            trans_later = get_new_hidden_trans(counts,
                                               type_trans="inclusiveLater")
            trans_skip = get_new_hidden_trans(counts,
                                              type_trans="inclusiveSkip")
            net.transitions.add(trans_start)
            net.transitions.add(trans_later)
            net.transitions.add(trans_skip)
            add_arc_from_to(first_place, trans_start, net)
            add_arc_from_to(subtree_init_place, trans_start, net)
            add_arc_from_to(trans_start, subtree_start_place, net)
            add_arc_from_to(trans_start, terminal_place, net)

            add_arc_from_to(terminal_place, trans_later, net)
            add_arc_from_to(subtree_init_place, trans_later, net)
            add_arc_from_to(trans_later, subtree_start_place, net)
            add_arc_from_to(trans_later, terminal_place, net)

            add_arc_from_to(terminal_place, trans_skip, net)
            add_arc_from_to(subtree_init_place, trans_skip, net)
            add_arc_from_to(trans_skip, terminal_place, net)
            add_arc_from_to(trans_skip, subtree_end_place, net)

            add_arc_from_to(subtree_end_place, new_final_trans, net)

            net, counts, intermediate_place = recursively_add_tree(
                tree, subtree, net, subtree_start_place, subtree_end_place,
                counts, rec_depth + 1)

    elif tree.operator == Operator.PARALLEL:
        new_initial_trans = get_new_hidden_trans(counts, type_trans="tauSplit")
        net.transitions.add(new_initial_trans)
        add_arc_from_to(initial_place, new_initial_trans, net)
        new_final_trans = get_new_hidden_trans(counts, type_trans="tauJoin")
        net.transitions.add(new_final_trans)
        add_arc_from_to(new_final_trans, final_place, net)

        for subtree in tree_childs:
            net, counts, intermediate_place = recursively_add_tree(
                tree, subtree, net, new_initial_trans, new_final_trans, counts,
                rec_depth + 1)
    elif tree.operator == Operator.SEQUENCE:
        intermediate_place = initial_place
        for i in range(len(tree_childs)):
            final_connection_place = None
            if i == len(tree_childs) - 1:
                final_connection_place = final_place
            net, counts, intermediate_place = recursively_add_tree(
                tree, tree_childs[i], net, intermediate_place,
                final_connection_place, counts, rec_depth + 1)
    elif tree.operator == Operator.LOOP:
        # if not parent_tree.operator == Operator.SEQUENCE:
        new_initial_place = get_new_place(counts)
        net.places.add(new_initial_place)
        init_loop_trans = get_new_hidden_trans(counts, type_trans="init_loop")
        net.transitions.add(init_loop_trans)
        add_arc_from_to(initial_place, init_loop_trans, net)
        add_arc_from_to(init_loop_trans, new_initial_place, net)
        initial_place = new_initial_place
        loop_trans = get_new_hidden_trans(counts, type_trans="loop")
        net.transitions.add(loop_trans)
        if len(tree_childs) == 1:
            net, counts, intermediate_place = recursively_add_tree(
                tree, tree_childs[0], net, initial_place, final_place, counts,
                rec_depth + 1)
            add_arc_from_to(final_place, loop_trans, net)
            add_arc_from_to(loop_trans, initial_place, net)
        else:
            dummy = ProcessTree()
            do = tree_childs[0]
            redo = tree_childs[1]
            exit = tree_childs[2] if len(tree_childs) > 2 and (
                tree_childs[2].label is not None
                or tree_childs[2].children) else dummy

            net, counts, int1 = recursively_add_tree(tree, do, net,
                                                     initial_place, None,
                                                     counts, rec_depth + 1)
            net, counts, int2 = recursively_add_tree(tree, redo, net, int1,
                                                     None, counts,
                                                     rec_depth + 1)
            net, counts, int3 = recursively_add_tree(tree, exit, net, int1,
                                                     final_place, counts,
                                                     rec_depth + 1)

            looping_place = int2

            add_arc_from_to(looping_place, loop_trans, net)
            add_arc_from_to(loop_trans, initial_place, net)

    return net, counts, final_place
Ejemplo n.º 13
0
def export_ptree_tree(tree, parameters=None):
    """
    Exports the XML tree from a process tree

    Parameters
    -----------------
    tree
        Process tree
    parameters
        Parameters of the algorithm

    Returns
    -----------------
    xml_tree
        XML tree object
    """
    tree = copy.deepcopy(tree)
    if parameters is None:
        parameters = {}

    nodes = get_list_nodes_from_tree(tree, parameters=parameters)
    nodes_dict = {(id(x), x): str(uuid.uuid4()) for x in nodes}

    # make sure that in the exporting, loops have 3 children
    # (for ProM compatibility)
    # just add a skip as third child
    for node in nodes:
        if node.operator == Operator.LOOP and len(node.children) < 3:
            third_children = ProcessTree(operator=None, label=None)
            third_children.parent = node
            node.children.append(third_children)
            nodes_dict[(id(third_children), third_children)] = str(uuid.uuid4())

    # repeat twice (structure has changed)
    nodes = get_list_nodes_from_tree(tree, parameters=parameters)
    nodes_dict = {(id(x), x): str(uuid.uuid4()) for x in nodes}

    root = etree.Element("ptml")
    processtree = etree.SubElement(root, "processTree")
    processtree.set("name", str(uuid.uuid4()))
    processtree.set("root", nodes_dict[(id(tree), tree)])
    processtree.set("id", str(uuid.uuid4()))

    for node in nodes:
        nk = nodes_dict[(id(node), node)]
        child = None
        if node.operator is None:
            if node.label is None:
                child = etree.SubElement(processtree, "automaticTask")
                child.set("name", "")
            else:
                child = etree.SubElement(processtree, "manualTask")
                child.set("name", node.label)
        else:
            if node.operator is Operator.SEQUENCE:
                child = etree.SubElement(processtree, "sequence")
            elif node.operator is Operator.XOR:
                child = etree.SubElement(processtree, "xor")
            elif node.operator is Operator.PARALLEL:
                child = etree.SubElement(processtree, "and")
            elif node.operator is Operator.OR:
                child = etree.SubElement(processtree, "or")
            elif node.operator is Operator.LOOP:
                child = etree.SubElement(processtree, "xorLoop")
            child.set("name", "")
        child.set("id", nk)

    for node in nodes:
        if not node == tree:
            child = etree.SubElement(processtree, "parentsNode")
            child.set("id", str(uuid.uuid4()))
            child.set("sourceId", nodes_dict[(id(node.parent), node.parent)])
            child.set("targetId", nodes_dict[(id(node), node)])

    tree = etree.ElementTree(root)
    return tree
Ejemplo n.º 14
0
def apply(parameters=None):
    """
    Generate a process tree

    Parameters
    ------------
    parameters
        Paramters of the algorithm, including:
            Parameters.REC_DEPTH -> current recursion depth
            Parameters.MIN_REC_DEPTH -> minimum recursion depth
            Parameters.MAX_REC_DEPTH -> maximum recursion depth
            Parameters.PROB_LEAF -> Probability to get a leaf

    Returns
    ------------
    tree
        Process tree
    """
    if parameters is None:
        parameters = {}

    rec_depth = exec_utils.get_param_value(Parameters.REC_DEPTH, parameters, 0)
    min_rec_depth = exec_utils.get_param_value(Parameters.MIN_REC_DEPTH,
                                               parameters, 1)
    max_rec_depth = exec_utils.get_param_value(Parameters.MAX_REC_DEPTH,
                                               parameters, 3)
    prob_leaf = exec_utils.get_param_value(Parameters.PROB_LEAF, parameters,
                                           0.25)

    next_parameters = {
        Parameters.REC_DEPTH: rec_depth + 1,
        Parameters.MIN_REC_DEPTH: min_rec_depth,
        Parameters.MAX_REC_DEPTH: max_rec_depth,
        Parameters.PROB_LEAF: prob_leaf
    }

    is_leaf = False

    if min_rec_depth <= rec_depth <= max_rec_depth:
        r = random.random()
        if r < prob_leaf:
            is_leaf = True
    elif rec_depth > max_rec_depth:
        is_leaf = True

    if is_leaf:
        current_tree = ProcessTree(label=generate_random_string(6))
    elif rec_depth == 0:
        current_tree = ProcessTree(operator=Operator.SEQUENCE)
        start = ProcessTree(label=generate_random_string(6),
                            parent=current_tree)
        current_tree.children.append(start)
        node = apply(parameters=next_parameters)
        node.parent = current_tree
        current_tree.children.append(node)
        end = ProcessTree(label=generate_random_string(6))
        end.parent = current_tree
        current_tree.children.append(end)
    else:
        o = get_random_operator()

        current_tree = ProcessTree(operator=o)
        if o == Operator.SEQUENCE:
            n_min = 2
            n_max = 6
            selected_n = random.randrange(n_min, n_max)
            for i in range(selected_n):
                child = apply(parameters=next_parameters)
                child.parent = current_tree
                current_tree.children.append(child)
        elif o == Operator.LOOP:
            do = apply(parameters=next_parameters)
            do.parent = current_tree
            current_tree.children.append(do)
            redo = apply(parameters=next_parameters)
            redo.parent = current_tree
            current_tree.children.append(redo)
            exit = ProcessTree(parent=current_tree)
            current_tree.children.append(exit)
        elif o == Operator.XOR:
            n_min = 2
            n_max = 5
            selected_n = random.randrange(n_min, n_max)
            for i in range(selected_n):
                child = apply(parameters=next_parameters)
                child.parent = current_tree
                current_tree.children.append(child)
        elif o == Operator.PARALLEL:
            n_min = 2
            n_max = 4
            selected_n = random.randrange(n_min, n_max)
            for i in range(selected_n):
                child = apply(parameters=next_parameters)
                child.parent = current_tree
                current_tree.children.append(child)
    return current_tree
Ejemplo n.º 15
0
def import_tree_from_xml_object(root, parameters=None):
    """
    Imports a process tree from the XML object

    Parameters
    ---------------
    root
        Root of the XML object
    parameters
        Possible parameters

    Returns
    ---------------
    tree
        Process tree
    """
    if parameters is None:
        parameters = {}

    nodes = {}

    for c0 in root:
        root = c0.get("root")
        for child in c0:
            tag = child.tag
            id = child.get("id")
            name = child.get("name")
            sourceId = child.get("sourceId")
            targetId = child.get("targetId")
            if name is not None:
                # node
                if tag == "and":
                    operator = Operator.PARALLEL
                    label = None
                elif tag == "sequence":
                    operator = Operator.SEQUENCE
                    label = None
                elif tag == "xor":
                    operator = Operator.XOR
                    label = None
                elif tag == "xorLoop":
                    operator = Operator.LOOP
                    label = None
                elif tag == "or":
                    operator = Operator.OR
                    label = None
                elif tag == "manualTask":
                    operator = None
                    label = name
                elif tag == "automaticTask":
                    operator = None
                    label = None
                else:
                    raise Exception("unknown tag: " + tag)
                tree = ProcessTree(operator=operator, label=label)
                nodes[id] = tree
            else:
                nodes[sourceId].children.append(nodes[targetId])
                nodes[targetId].parent = nodes[sourceId]

    # make sure that .PTML files having loops with 3 children are imported
    # into the PM4Py process tree structure
    # we want loops to have two children
    for node in nodes.values():
        if node.operator == Operator.LOOP and len(node.children) == 3:
            if not (node.children[2].operator is None
                    and node.children[2].label is None):
                parent_node = node.parent
                new_parent_node = ProcessTree(operator=Operator.SEQUENCE,
                                              label=None)
                node.parent = new_parent_node
                new_parent_node.children.append(node)
                node.children[2].parent = new_parent_node
                new_parent_node.children.append(node.children[2])
                if parent_node is not None:
                    new_parent_node.parent = parent_node
                    del parent_node.children[parent_node.children.index(node)]
                    parent_node.children.append(new_parent_node)
            del node.children[2]

    root = nodes[root]
    tree_sort(root)
    return root