Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Among *procedural process models*, ``pm4py`` currently supports:
* :meth:`pm4py.discovery.discover_petri_net_inductive`; discovers a *Petri net* using the Inductive Miner algorithm.
* :meth:`pm4py.discovery.discover_petri_net_heuristics`; discovers a *Petri net* using the Heuristics Miner algorithm.
* :meth:`pm4py.discovery.discover_petri_net_ilp`; discovers a *Petri net* using the ILP Miner algorithm.
* :meth:`pm4py.discovery.discover_petri_net_genetic`; discovers a *Petri net* using the Genetic Miner algorithm.
* :meth:`pm4py.discovery.discover_process_tree_inductive`; discovers a *process tree* using the Inductive Miner algorithm.
* :meth:`pm4py.discovery.discover_bpmn_inductive`; discovers a *BPMN model* using the Inductive Miner algorithm.
* :meth:`pm4py.discovery.discover_heuristics_net`; discovers a *heuristics net* using the Heuristics Miner algorithm.
Expand Down Expand Up @@ -466,6 +467,7 @@ List of Methods
pm4py.discovery.discover_petri_net_inductive
pm4py.discovery.discover_petri_net_heuristics
pm4py.discovery.discover_petri_net_ilp
pm4py.discovery.discover_petri_net_genetic
pm4py.discovery.discover_process_tree_inductive
pm4py.discovery.discover_heuristics_net
pm4py.discovery.derive_minimum_self_distance
Expand Down
17 changes: 17 additions & 0 deletions examples/genetic_miner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pm4py
import os
import importlib.util
from examples import examples_conf
from pm4py.algo.discovery.genetic.algorithm import Parameters


def execute_script():
log = pm4py.read_xes(os.path.join("..", "tests", "input_data", "running-example.xes"))
net, im, fm = pm4py.discover_petri_net_genetic(log, population_size = 20, generations = 30)

if importlib.util.find_spec("graphviz"):
pm4py.view_petri_net(net, im, fm, format=examples_conf.TARGET_IMG_FORMAT)


if __name__ == "__main__":
execute_script()
1 change: 1 addition & 0 deletions pm4py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
discover_petri_net_ilp,
discover_petri_net_heuristics,
discover_petri_net_inductive,
discover_petri_net_genetic,
discover_process_tree_inductive,
discover_heuristics_net,
discover_dfg,
Expand Down
1 change: 1 addition & 0 deletions pm4py/algo/discovery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
heuristics,
ilp,
inductive,
genetic,
log_skeleton,
minimum_self_distance,
ocel,
Expand Down
22 changes: 22 additions & 0 deletions pm4py/algo/discovery/genetic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'''
PM4Py – A Process Mining Library for Python
Copyright (C) 2026 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
'''
from pm4py.algo.discovery.genetic import variants, algorithm
77 changes: 77 additions & 0 deletions pm4py/algo/discovery/genetic/algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
'''
PM4Py – A Process Mining Library for Python
Copyright (C) 2026 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
'''
from enum import Enum
from pm4py.util import exec_utils
from pm4py.algo.discovery.genetic.variants import classic
from typing import Union, Optional, Dict, Any, Tuple
from pm4py.objects.petri_net.obj import PetriNet, Marking
from pm4py.objects.log.obj import EventLog, EventStream
import pandas as pd
from pm4py.util import constants


class Parameters(Enum):
ACTIVITY_KEY = constants.PARAMETER_CONSTANT_ACTIVITY_KEY
TIMESTAMP_KEY = constants.PARAMETER_CONSTANT_TIMESTAMP_KEY
CASE_ID_KEY = constants.PARAMETER_CONSTANT_CASEID_KEY
POPULATION_SIZE = "population_size"
ELITISM_RATE = "elitism_rate"
CROSSOVER_RATE = "crossover_rate"
MUTATION_RATE = "mutation_rate"
GENERATIONS = "generations"
ELITISM_MIN_SAMPLE = "elitism_min_sample"
TOURNAMENT_TIMEOUT = "tournament_timeout"
LOG_CSV = "log_csv"


class Variants(Enum):
CLASSIC = classic


def apply(
log: Union[EventLog, EventStream, pd.DataFrame],
variant=Variants.CLASSIC,
parameters: Optional[Dict[Any, Any]] = None,
) -> Tuple[PetriNet, Marking, Marking]:
"""
Discovers a Petri net using the genetic miner.

Parameters
---------------
log
Event log / Event stream / Pandas dataframe
variant
Variant of the algorithm to be used, possible values:
- Variants.CLASSIC
parameters
Variant-specific parameters

Returns
---------------
net
Petri net
im
Initial marking
fm
Final marking
"""
return exec_utils.get_variant(variant).apply(log, parameters)
87 changes: 87 additions & 0 deletions pm4py/algo/discovery/genetic/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'''
PM4Py – A Process Mining Library for Python
Copyright (C) 2026 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
'''

# Author: Maximilian Josef Frank (https://orcid.org/0000-0002-0714-7748)

import random
import itertools

# typing
from collections.abc import Iterable
InputMap = dict[str,list[frozenset]]
OutputMap = dict[str,list[frozenset]]
Individual = tuple[InputMap,OutputMap]

class iset(frozenset):
"Indexable frozenset printing as set, i.e. without `frozenset(…)`"
def __repr__(self):
return "{" + repr(sorted(self))[1:-1] + "}"

@staticmethod
def flat(item: Iterable) -> Self:
return iset(itertools.chain(*item))

def rand_partition(pool: Iterable) -> list[set]:
pool = set(pool)
# also ensures no activity in two partitions
# s. 4. Causal Matrix, Def. 4; https://doi.org/10.1007/11494744_5
partition = []
while pool:
draw = iset(random.sample(
tuple(pool),
random.randint(1, len(pool))
))
partition.append(draw)
pool -= draw
return partition

def get_src_sink_sets_for_wfnet(I: InputMap, O: OutputMap, T: list[str]) -> tuple[list[str],list[str]]:
"""Determines input set and output set, which need to be connected by a place to create a WF-net"""
def add2graphs(graphs, t, nextT):
# find graph
graph = next((g for g in graphs if t in g), None)
if graph is None:
graph = [t]
graphs.append(graph)
# append plain/grouped T
successors = []
for S in nextT[t]:
if type(S) == str:
successors.append(S)
else:
successors.extend(S)
graph += successors
# merge if end = start
for tn in successors:
for g2 in graphs[:]: # [:] = copy
if g2[0] == tn and g2 != graph:
graph += g2
graphs.remove(g2)
break
return graphs
graphsI, graphsO = [], []
for t in T:
graphsI = add2graphs(graphsI, t, I)
graphsO = add2graphs(graphsO, t, O)
first = [g[0] for g in graphsO] # ⋃first = reachable via O[∀t]
last = [g[0] for g in graphsI] # ⋃first = reachable via I[∀t]
return first, last
22 changes: 22 additions & 0 deletions pm4py/algo/discovery/genetic/variants/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'''
PM4Py – A Process Mining Library for Python
Copyright (C) 2026 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
'''
from pm4py.algo.discovery.genetic.variants import classic
Loading