Source code for pm4py.algo.simulation.tree_generator.variants.basic
'''
PM4Py – A Process Mining Library for Python
Copyright (C) 2024 Process Intelligence Solutions UG (haftungsbeschränkt)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see this software project's root or
visit <https://www.gnu.org/licenses/>.
Website: https://processintelligence.solutions
Contact: info@processintelligence.solutions
'''
import random
import string
from pm4py.objects.process_tree.obj import ProcessTree
from pm4py.objects.process_tree.obj import Operator
from enum import Enum
from pm4py.util import exec_utils
from typing import Optional, Dict, Any, Union
[docs]
class Parameters(Enum):
REC_DEPTH = "rec_depth"
MIN_REC_DEPTH = "min_rec_depth"
MAX_REC_DEPTH = "max_rec_depth"
PROB_LEAF = "prob_leaf"
[docs]
def generate_random_string(N):
"""
Generate a random string
Parameters
-------------
N
length of the string
Returns
-------------
random_string
Random string
"""
return "".join(
random.choice(string.ascii_uppercase + string.digits) for _ in range(N)
)
[docs]
def get_random_operator():
"""
Gets a random operator
Returns
------------
operator
Operator
"""
r = random.random()
if r < 0.25:
return Operator.SEQUENCE
elif r < 0.5:
return Operator.LOOP
elif r < 0.75:
return Operator.XOR
else:
return Operator.PARALLEL
[docs]
def apply(
parameters: Optional[Dict[Union[str, Parameters], Any]] = None
) -> ProcessTree:
"""
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