Skip to content

Commit 75cd2a3

Browse files
Merge pull request #541 from tmp3dko382i94nsk/release
Draft: Implementing the Genetic Miner
2 parents 3ebeab9 + 9b35600 commit 75cd2a3

27 files changed

Lines changed: 1561 additions & 11 deletions

docs/source/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Among *procedural process models*, ``pm4py`` currently supports:
9090
* :meth:`pm4py.discovery.discover_petri_net_inductive`; discovers a *Petri net* using the Inductive Miner algorithm.
9191
* :meth:`pm4py.discovery.discover_petri_net_heuristics`; discovers a *Petri net* using the Heuristics Miner algorithm.
9292
* :meth:`pm4py.discovery.discover_petri_net_ilp`; discovers a *Petri net* using the ILP Miner algorithm.
93+
* :meth:`pm4py.discovery.discover_petri_net_genetic`; discovers a *Petri net* using the Genetic Miner algorithm.
9394
* :meth:`pm4py.discovery.discover_process_tree_inductive`; discovers a *process tree* using the Inductive Miner algorithm.
9495
* :meth:`pm4py.discovery.discover_bpmn_inductive`; discovers a *BPMN model* using the Inductive Miner algorithm.
9596
* :meth:`pm4py.discovery.discover_heuristics_net`; discovers a *heuristics net* using the Heuristics Miner algorithm.
@@ -466,6 +467,7 @@ List of Methods
466467
pm4py.discovery.discover_petri_net_inductive
467468
pm4py.discovery.discover_petri_net_heuristics
468469
pm4py.discovery.discover_petri_net_ilp
470+
pm4py.discovery.discover_petri_net_genetic
469471
pm4py.discovery.discover_process_tree_inductive
470472
pm4py.discovery.discover_heuristics_net
471473
pm4py.discovery.derive_minimum_self_distance

examples/genetic_miner.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import pm4py
2+
import os
3+
import importlib.util
4+
from examples import examples_conf
5+
from pm4py.algo.discovery.genetic.algorithm import Parameters
6+
7+
8+
def execute_script():
9+
log = pm4py.read_xes(os.path.join("..", "tests", "input_data", "running-example.xes"))
10+
net, im, fm = pm4py.discover_petri_net_genetic(log, population_size = 20, generations = 30)
11+
12+
if importlib.util.find_spec("graphviz"):
13+
pm4py.view_petri_net(net, im, fm, format=examples_conf.TARGET_IMG_FORMAT)
14+
15+
16+
if __name__ == "__main__":
17+
execute_script()

pm4py/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
discover_petri_net_ilp,
139139
discover_petri_net_heuristics,
140140
discover_petri_net_inductive,
141+
discover_petri_net_genetic,
141142
discover_process_tree_inductive,
142143
discover_heuristics_net,
143144
discover_dfg,

pm4py/algo/discovery/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
heuristics,
3434
ilp,
3535
inductive,
36+
genetic,
3637
log_skeleton,
3738
minimum_self_distance,
3839
ocel,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'''
2+
PM4Py – A Process Mining Library for Python
3+
Copyright (C) 2026 Process Intelligence Solutions UG (haftungsbeschränkt)
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Affero General Public License as
7+
published by the Free Software Foundation, either version 3 of the
8+
License, or any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Affero General Public License for more details.
14+
15+
You should have received a copy of the GNU Affero General Public License
16+
along with this program. If not, see this software project's root or
17+
visit <https://www.gnu.org/licenses/>.
18+
19+
Website: https://processintelligence.solutions
20+
Contact: info@processintelligence.solutions
21+
'''
22+
from pm4py.algo.discovery.genetic import variants, algorithm
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
'''
2+
PM4Py – A Process Mining Library for Python
3+
Copyright (C) 2026 Process Intelligence Solutions UG (haftungsbeschränkt)
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Affero General Public License as
7+
published by the Free Software Foundation, either version 3 of the
8+
License, or any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Affero General Public License for more details.
14+
15+
You should have received a copy of the GNU Affero General Public License
16+
along with this program. If not, see this software project's root or
17+
visit <https://www.gnu.org/licenses/>.
18+
19+
Website: https://processintelligence.solutions
20+
Contact: info@processintelligence.solutions
21+
'''
22+
from enum import Enum
23+
from pm4py.util import exec_utils
24+
from pm4py.algo.discovery.genetic.variants import classic
25+
from typing import Union, Optional, Dict, Any, Tuple
26+
from pm4py.objects.petri_net.obj import PetriNet, Marking
27+
from pm4py.objects.log.obj import EventLog, EventStream
28+
import pandas as pd
29+
from pm4py.util import constants
30+
31+
32+
class Parameters(Enum):
33+
ACTIVITY_KEY = constants.PARAMETER_CONSTANT_ACTIVITY_KEY
34+
TIMESTAMP_KEY = constants.PARAMETER_CONSTANT_TIMESTAMP_KEY
35+
CASE_ID_KEY = constants.PARAMETER_CONSTANT_CASEID_KEY
36+
POPULATION_SIZE = "population_size"
37+
ELITISM_RATE = "elitism_rate"
38+
CROSSOVER_RATE = "crossover_rate"
39+
MUTATION_RATE = "mutation_rate"
40+
GENERATIONS = "generations"
41+
ELITISM_MIN_SAMPLE = "elitism_min_sample"
42+
TOURNAMENT_TIMEOUT = "tournament_timeout"
43+
LOG_CSV = "log_csv"
44+
45+
46+
class Variants(Enum):
47+
CLASSIC = classic
48+
49+
50+
def apply(
51+
log: Union[EventLog, EventStream, pd.DataFrame],
52+
variant=Variants.CLASSIC,
53+
parameters: Optional[Dict[Any, Any]] = None,
54+
) -> Tuple[PetriNet, Marking, Marking]:
55+
"""
56+
Discovers a Petri net using the genetic miner.
57+
58+
Parameters
59+
---------------
60+
log
61+
Event log / Event stream / Pandas dataframe
62+
variant
63+
Variant of the algorithm to be used, possible values:
64+
- Variants.CLASSIC
65+
parameters
66+
Variant-specific parameters
67+
68+
Returns
69+
---------------
70+
net
71+
Petri net
72+
im
73+
Initial marking
74+
fm
75+
Final marking
76+
"""
77+
return exec_utils.get_variant(variant).apply(log, parameters)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
'''
2+
PM4Py – A Process Mining Library for Python
3+
Copyright (C) 2026 Process Intelligence Solutions UG (haftungsbeschränkt)
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Affero General Public License as
7+
published by the Free Software Foundation, either version 3 of the
8+
License, or any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Affero General Public License for more details.
14+
15+
You should have received a copy of the GNU Affero General Public License
16+
along with this program. If not, see this software project's root or
17+
visit <https://www.gnu.org/licenses/>.
18+
19+
Website: https://processintelligence.solutions
20+
Contact: info@processintelligence.solutions
21+
'''
22+
23+
# Author: Maximilian Josef Frank (https://orcid.org/0000-0002-0714-7748)
24+
25+
import random
26+
import itertools
27+
28+
# typing
29+
from collections.abc import Iterable
30+
InputMap = dict[str,list[frozenset]]
31+
OutputMap = dict[str,list[frozenset]]
32+
Individual = tuple[InputMap,OutputMap]
33+
34+
class iset(frozenset):
35+
"Indexable frozenset printing as set, i.e. without `frozenset(…)`"
36+
def __repr__(self):
37+
return "{" + repr(sorted(self))[1:-1] + "}"
38+
39+
@staticmethod
40+
def flat(item: Iterable) -> Self:
41+
return iset(itertools.chain(*item))
42+
43+
def rand_partition(pool: Iterable) -> list[set]:
44+
pool = set(pool)
45+
# also ensures no activity in two partitions
46+
# s. 4. Causal Matrix, Def. 4; https://doi.org/10.1007/11494744_5
47+
partition = []
48+
while pool:
49+
draw = iset(random.sample(
50+
tuple(pool),
51+
random.randint(1, len(pool))
52+
))
53+
partition.append(draw)
54+
pool -= draw
55+
return partition
56+
57+
def get_src_sink_sets_for_wfnet(I: InputMap, O: OutputMap, T: list[str]) -> tuple[list[str],list[str]]:
58+
"""Determines input set and output set, which need to be connected by a place to create a WF-net"""
59+
def add2graphs(graphs, t, nextT):
60+
# find graph
61+
graph = next((g for g in graphs if t in g), None)
62+
if graph is None:
63+
graph = [t]
64+
graphs.append(graph)
65+
# append plain/grouped T
66+
successors = []
67+
for S in nextT[t]:
68+
if type(S) == str:
69+
successors.append(S)
70+
else:
71+
successors.extend(S)
72+
graph += successors
73+
# merge if end = start
74+
for tn in successors:
75+
for g2 in graphs[:]: # [:] = copy
76+
if g2[0] == tn and g2 != graph:
77+
graph += g2
78+
graphs.remove(g2)
79+
break
80+
return graphs
81+
graphsI, graphsO = [], []
82+
for t in T:
83+
graphsI = add2graphs(graphsI, t, I)
84+
graphsO = add2graphs(graphsO, t, O)
85+
first = [g[0] for g in graphsO] # ⋃first = reachable via O[∀t]
86+
last = [g[0] for g in graphsI] # ⋃first = reachable via I[∀t]
87+
return first, last
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'''
2+
PM4Py – A Process Mining Library for Python
3+
Copyright (C) 2026 Process Intelligence Solutions UG (haftungsbeschränkt)
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Affero General Public License as
7+
published by the Free Software Foundation, either version 3 of the
8+
License, or any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Affero General Public License for more details.
14+
15+
You should have received a copy of the GNU Affero General Public License
16+
along with this program. If not, see this software project's root or
17+
visit <https://www.gnu.org/licenses/>.
18+
19+
Website: https://processintelligence.solutions
20+
Contact: info@processintelligence.solutions
21+
'''
22+
from pm4py.algo.discovery.genetic.variants import classic

0 commit comments

Comments
 (0)