File size: 4,690 Bytes
e60e568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
'''
    This file is part of PM4Py (More Info: https://pm4py.fit.fraunhofer.de).

    PM4Py is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PM4Py is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PM4Py.  If not, see <https://www.gnu.org/licenses/>.
'''
from pm4py.objects.process_tree.obj import Operator
from pm4py.util import exec_utils, constants, xes_constants
from pm4py.objects.log.obj import Trace, Event
from enum import Enum
import random
import time

from typing import Optional, Dict, Any, Union
from pm4py.objects.log.obj import EventLog
from pm4py.objects.process_tree.obj import ProcessTree


class Parameters(Enum):
    ACTIVITY_KEY = constants.PARAMETER_CONSTANT_ACTIVITY_KEY
    NO_TRACES = "num_traces"


def apply(tree: ProcessTree, parameters: Optional[Dict[Union[str, Parameters], Any]] = None) -> EventLog:
    """
    Gets the top-bottom playout of a process tree

    Parameters
    ---------------
    tree
        Process tree
    parameters
        Parameters of the algorithm, including:
            - Parameters.ACTIVITY_KEY: activity key
            - Parameters.NO_TRACES: number of traces that should be returned

    Returns
    ---------------
    log
        Event log
    """
    if parameters is None:
        parameters = {}

    activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY)
    no_traces = exec_utils.get_param_value(Parameters.NO_TRACES, parameters, 1000)

    execution_sequences = get_num_ex_sequences(tree, no_traces)

    log = EventLog()
    for seq in execution_sequences:
        trace = Trace()
        for el in seq:
            if el.label is not None:
                event = Event({activity_key: el.label})
                trace.append(event)
        log.append(trace)

    return log


def get_ex_seq_in_time(tree, ex_time):
    """
    Gets the maximum number of execution sequences, doing the playout,
    in the given amount of time

    Parameters
    ----------------
    tree
        Process tree
    ex_time
        Maximum execution time

    Returns
    ----------------
    ex_sec
        Execution sequences
    """
    ex_sec = []
    aa = time.time()
    while time.time() - aa < ex_time:
        ex_sec.append(tuple(get_ex_seq(tree)))
    return ex_sec


def get_num_ex_sequences(tree, num):
    """
    Gets the specified amount of execution sequences

    Parameters
    ---------------
    tree
        Process tree
    num
        Number of execution sequences

    Returns
    ---------------
    ex_sec
        Execution sequences
    """
    ret = []
    for i in range(num):
        ret.append(tuple(get_ex_seq(tree)))
    return ret


def get_ex_seq(tree):
    """
    Gets a trace from a process tree (top-bottom)

    Parameters
    --------------
    tree
        Process tree

    Returns
    -------------
    ex_seq
        Execution sequence
    """
    if tree.operator is None:
        return [tree]
    elif tree.operator is Operator.XOR:
        child = random.choice(tree.children)
        return get_ex_seq(child)
    elif tree.operator is Operator.SEQUENCE:
        ret = []
        for child in tree.children:
            ret = ret + get_ex_seq(child)
        return ret
    elif tree.operator is Operator.INTERLEAVING:
        random.shuffle(tree.children)
        ret = []
        for child in tree.children:
            ret = ret + get_ex_seq(child)
        return ret
    elif tree.operator is Operator.LOOP:
        ret = []
        cont = True
        while cont:
            cont = False
            ret = ret + get_ex_seq(tree.children[0])
            r = random.random()
            if r <= 0.5:
                ret = ret + get_ex_seq(tree.children[1])
                cont = True
        return ret
    elif tree.operator is Operator.PARALLEL:
        ret = []
        children_traces = []
        list_choices = []
        for index, child in enumerate(tree.children):
            trace = get_ex_seq(child)
            children_traces.append(trace)
            list_choices += [index] * len(trace)
        random.shuffle(list_choices)
        for c in list_choices:
            act = children_traces[c].pop(0)
            ret.append(act)
        return ret