Skip to content

Commit

Permalink
Merge pull request #513 from process-intelligence-solutions/dev
Browse files Browse the repository at this point in the history
pm4py 2.7.13
  • Loading branch information
fit-daniel-schuster authored Jan 10, 2025
2 parents 91f8c26 + f1e42d1 commit fc13d12
Show file tree
Hide file tree
Showing 39 changed files with 923 additions and 136 deletions.
123 changes: 123 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,127 @@
# Changelog of pm4py


## pm4py 2.7.14 (2024.XX.YY)

### Added

### Changed

### Deprecated

### Fixed

### Removed

### Other


---


## pm4py 2.7.13 (2024.07.11)

### Added

### Changed
* 75c893999e32b3a1a6081db854b9a3cd10eaaa44
* Dockerfile refactoring
* 7b80dad1fcc6955730357f46754c4a511b83ee58
* updating requirements list
* 52459f95d42e2fc39568b0d685bd794c319f205a
* refactoring dependencies generation script
* 928ecf5f8192ff1ef7944c5b0a7be7c530814ad9
* refactoring OpenAI query interface
* 5fee9b4ac61c227ac77cbd28b888a7321ba401bf
* refactor OCEL object repr
* 6c1ea7a38b3ef18fe9d490164ecebd85c432915f
* possibility to set the title in pm4py visualizations

### Deprecated

### Fixed
* 954c2fbdc258b90bcba85001592a5d2950a79724
* bug fix temporal profile conformance checking
* cd8f9fb9f49a5955f0a26f547770aefa8ff222b8
* issue with closing in-memory files when parsing a XES from string
* d51bd9e24aed442f011917d6b77793b118bbf89f
* minor fix OCEL interleavings computation
* 39d769cad1327c47d5948b0c40be4a90e41fcce7
* removed indeterminism in TBR with duplicate transitions
* 2fb8e6bffcac11b14fe13f152ac0b096cdc0d03a
* penwidth assignation in DFG edges
* c753425ffd63da55fc0d3e71ab5b5fb62a2bf359
* OCEL exporters consistency check
* e98d795c977348dcbe7495d62c8975fae0b9499c
* LTL filters documentation in the simplified interface

### Removed

### Other
* ed708047252f96f3bf103ba81d6139b433c39b85
* printing Python versions in tests and examples
* c48882b88326608dc5c6a4101b8123c71a852e18
* parameter to enable/disable visualizations
* 607d2eb601299a23335f8c1976cc59f63bcae5f2
* added example for Inductive Miner LC

---


## pm4py 2.7.12.1 (2024.04.17)

### Added

### Changed
* 5641f9f2c830b567c138524a0b5e705a3836102a
* minor change OCEL names_stripping
* c48882b88326608dc5c6a4101b8123c71a852e18
* parameter to enable/disable visualizations' view

### Deprecated

### Fixed
* 1c6887fda74d2b0a36f483351a6978738517e61e
* bug fix inductive miner infreuent
* e7e8ebf6894d9bc85febc43c82613d185e16ee3b
* solving performance bottleneck in IM
* 4811bbde07f6639deb7c87bdda61504de0889873
* resolved indeterminism in IM fallthroughs
* df1db968adf8bb5f483410be0ceef2928c2b3e6c
* missing tree sort in IM
* 4958e2b8407c01923e5b65c7e46a5f89d8f927dc
* missing fold of PT objects in IM
* 8e404c6c2b53cf14687d1f82d53a4a0fc4ac99d6
* fixed folding of PTs
* a871cbc4bdeaa81013fbfa7a6ec5054d494cb329
* fixed parsing of PTs
* a72cd92410653bf2f0b2ff35ab5d06bf73a95305
eddae51259114caf4e1447beee4981f2e00bcb9c
69dcf7a836a5af3ab5da64701f43e3d8cf6b07aa
* fixed WF-net-to-PT conversion
* 0980ac460d69beb9ede4403a3ed002c1cd30536e
* fixed docstring OCEL flattening
* 6f9c67f48ad89e88d58c2481e85c6f3de9e6e1a5
* fix small issues with stochastic Petri net
* 6781a90df2ba8d90155e7b5135520076843cac33
* bug fix DECLARE discovery and conformance checking
* 7330d5100c8b8916eba9e4b0f31e8fa1f9157c98
* bug fix log skeleton discovery (always after, always before)
* ec2f0b5b43d83a7b9fa154456241e3c685fcb721
* bug fix log-to-prefix-tree discovery (final nodes)
* d580fedd4b770ed85f6864cd6d435db2477684f2
* bumping release number. forcing numpy<2 and pandas<3
* 4f8bbf6d884e25c5474479fd86fe7331076ac2fe
* bug fixes for Pandas >= 3.0 future support

### Removed

### Other


---


## pm4py 2.7.12 (2024.03.21)

### Added
Expand Down Expand Up @@ -34,8 +155,10 @@

### Other


---


## pm4py 2.7.11 (2024.03.01)

### Added
Expand Down
2 changes: 1 addition & 1 deletion pm4py/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
'''

__name__ = 'pm4py'
VERSION = '2.7.12.4'
VERSION = '2.7.13'
__version__ = VERSION
__doc__ = 'Process mining for Python'
__author__ = 'Process Intelligence Solutions (PIS)'
Expand Down
6 changes: 2 additions & 4 deletions pm4py/objects/bpmn/importer/variants/lxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,15 +305,13 @@ def parse_element(bpmn_graph, counts, curr_el, parents, incoming_dict, outgoing_
incoming_dict[seq_flow_id][3], incoming_dict[seq_flow_id][4])
for seq_flow_id in outgoing_dict:
if outgoing_dict[seq_flow_id][0] in nodes_dict:
outgoing_dict[seq_flow_id] = (
nodes_dict[outgoing_dict[seq_flow_id][0]], outgoing_dict[seq_flow_id][1], outgoing_dict[seq_flow_id][2],
outgoing_dict[seq_flow_id][3], outgoing_dict[seq_flow_id][4])
outgoing_dict[seq_flow_id] = (nodes_dict[outgoing_dict[seq_flow_id][0]], outgoing_dict[seq_flow_id][1], outgoing_dict[seq_flow_id][2], outgoing_dict[seq_flow_id][3], outgoing_dict[seq_flow_id][4])

# also supports flows without waypoints
flows_without_waypoints = set(flow_info).union(set(outgoing_dict).intersection(set(incoming_dict)))
for flow_id in flows_without_waypoints:
flow_info[flow_id] = []

for flow_id in flow_info:
if flow_id in outgoing_dict and flow_id in incoming_dict:
flow = None
Expand Down
33 changes: 23 additions & 10 deletions pm4py/objects/ocel/obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from pm4py.util import exec_utils, pandas_utils
import pandas as pd
import numpy as np
from collections import Counter
from copy import copy, deepcopy


Expand All @@ -39,7 +40,8 @@ class Parameters(Enum):


class OCEL(object):
def __init__(self, events=None, objects=None, relations=None, globals=None, parameters=None, o2o=None, e2e=None, object_changes=None):
def __init__(self, events=None, objects=None, relations=None, globals=None, parameters=None, o2o=None, e2e=None,
object_changes=None):
if parameters is None:
parameters = {}

Expand All @@ -54,10 +56,12 @@ def __init__(self, events=None, objects=None, relations=None, globals=None, para
self.event_timestamp = exec_utils.get_param_value(Parameters.EVENT_TIMESTAMP, parameters,
constants.DEFAULT_EVENT_TIMESTAMP)
self.qualifier = exec_utils.get_param_value(Parameters.QUALIFIER, parameters, constants.DEFAULT_QUALIFIER)
self.changed_field = exec_utils.get_param_value(Parameters.CHANGED_FIELD, parameters, constants.DEFAULT_CHNGD_FIELD)
self.changed_field = exec_utils.get_param_value(Parameters.CHANGED_FIELD, parameters,
constants.DEFAULT_CHNGD_FIELD)

if events is None:
events = pandas_utils.instantiate_dataframe({self.event_id_column: [], self.event_activity: [], self.event_timestamp: []})
events = pandas_utils.instantiate_dataframe(
{self.event_id_column: [], self.event_activity: [], self.event_timestamp: []})
if objects is None:
objects = pandas_utils.instantiate_dataframe({self.object_id_column: [], self.object_type_column: []})
if relations is None:
Expand All @@ -67,11 +71,15 @@ def __init__(self, events=None, objects=None, relations=None, globals=None, para
if globals is None:
globals = {}
if o2o is None:
o2o = pandas_utils.instantiate_dataframe({self.object_id_column: [], self.object_id_column+"_2": [], self.qualifier: []})
o2o = pandas_utils.instantiate_dataframe(
{self.object_id_column: [], self.object_id_column + "_2": [], self.qualifier: []})
if e2e is None:
e2e = pandas_utils.instantiate_dataframe({self.event_id_column: [], self.event_id_column+"_2": [], self.qualifier: []})
e2e = pandas_utils.instantiate_dataframe(
{self.event_id_column: [], self.event_id_column + "_2": [], self.qualifier: []})
if object_changes is None:
object_changes = pandas_utils.instantiate_dataframe({self.object_id_column: [], self.object_type_column: [], self.event_timestamp: [], self.changed_field: []})
object_changes = pandas_utils.instantiate_dataframe(
{self.object_id_column: [], self.object_type_column: [], self.event_timestamp: [],
self.changed_field: []})
if self.qualifier not in relations:
relations[self.qualifier] = [None] * len(relations)

Expand Down Expand Up @@ -111,10 +119,13 @@ def get_summary(self) -> str:
ret.append(", number of object types: %d" % (self.objects[self.object_type_column].nunique()))
ret.append(", events-objects relationships: %d)" % (len(self.relations)))
ret.append("\n")
ret.append("Activities occurrences: " + str(self.events[self.event_activity].value_counts().to_dict()))
ret.append("Activities occurrences: " + str(Counter(self.events[self.event_activity].value_counts().to_dict())))
ret.append("\n")
ret.append("Object types occurrences (number of objects): " + str(
self.objects[self.object_type_column].value_counts().to_dict()))
Counter(self.objects[self.object_type_column].value_counts().to_dict())))
ret.append("\n")
ret.append("Unique activities per object type: " + str(
Counter(self.relations.groupby(self.object_type_column)[self.event_activity].nunique().to_dict())))
ret.append("\n")
ret.append(
"Please use <THIS>.get_extended_table() to get a dataframe representation of the events related to the objects.")
Expand All @@ -123,7 +134,8 @@ def get_summary(self) -> str:
def is_ocel20(self):
unique_qualifiers = []
if self.qualifier in self.relations.columns:
unique_qualifiers = [x for x in pandas_utils.format_unique(self.relations[self.qualifier].unique()) if not self.__check_is_nan(x)]
unique_qualifiers = [x for x in pandas_utils.format_unique(self.relations[self.qualifier].unique()) if
not self.__check_is_nan(x)]

return len(self.o2o) > 0 or len(self.object_changes) > 0 or len(unique_qualifiers) > 0

Expand All @@ -143,7 +155,8 @@ def __repr__(self):
return str(self.get_summary())

def __copy__(self):
return OCEL(self.events, self.objects, self.relations, copy(self.globals), copy(self.parameters), copy(self.o2o), copy(self.e2e), copy(self.object_changes))
return OCEL(self.events, self.objects, self.relations, copy(self.globals), copy(self.parameters),
copy(self.o2o), copy(self.e2e), copy(self.object_changes))

def __deepcopy__(self, memo):
return OCEL(self.events.copy(), self.objects.copy(), self.relations.copy(), deepcopy(self.globals),
Expand Down
23 changes: 17 additions & 6 deletions pm4py/objects/ocel/util/ocel_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from pm4py.objects.ocel.obj import OCEL
from typing import Optional, Dict, Any
import warnings


def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) -> OCEL:
Expand All @@ -45,12 +46,12 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) -> OCEL:
parameters = {}

fields = {
"events": ["ocel:eid", "ocel:activity"],
"objects": ["ocel:oid", "ocel:type"],
"relations": ["ocel:eid", "ocel:oid", "ocel:activity", "ocel:type"],
"o2o": ["ocel:oid", "ocel:oid_2"],
"e2e": ["ocel:eid", "ocel:eid_2"],
"object_changes": ["ocel:oid"]
"events": [ocel.event_id_column, ocel.event_activity],
"objects": [ocel.object_id_column, ocel.object_type_column],
"relations": [ocel.event_id_column, ocel.object_id_column, ocel.event_activity, ocel.object_type_column],
"o2o": [ocel.object_id_column, ocel.object_id_column+"_2"],
"e2e": [ocel.event_id_column, ocel.event_id_column+"_2"],
"object_changes": [ocel.object_id_column]
}

for tab in fields:
Expand All @@ -62,4 +63,14 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) -> OCEL:
df = df[df[fie].str.len() > 0]
setattr(ocel, tab, df)

# check if the event IDs or object IDs are unique
num_ev_ids = ocel.events[ocel.event_id_column].nunique()
num_obj_ids = ocel.objects[ocel.object_id_column].nunique()

if num_ev_ids < len(ocel.events):
warnings.warn("The event identifiers in the OCEL are not unique!")

if num_obj_ids < len(ocel.objects):
warnings.warn("The object identifiers in the OCEL are not unique!")

return ocel
19 changes: 19 additions & 0 deletions pm4py/objects/trie/obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,22 @@ def _get_depth(self):
label = property(_get_label, _set_label)
final = property(_get_final, _set_final)
depth = property(_get_depth, _set_depth)

def repr_trie(self, indent_level=0):
stri = []

if self.label:
stri.append("\t"*indent_level + self.label)
indent_level += 1
for child in self.children:
stri.append(child.repr_trie(indent_level=indent_level))
if self.final:
stri.append("\t"*indent_level + "-- END --")

return "\n".join(stri)

def __repr__(self):
return self.repr_trie()

def __str__(self):
return self.repr_trie()
1 change: 1 addition & 0 deletions pm4py/util/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def get_default_is_aware_enabled():
OPENAI_EXEC_RESULT = True if get_param_from_env("PM4PY_OPENAI_EXEC_RESULT", "False").lower() == "true" else False
DEFAULT_GVIZ_VIEW = get_param_from_env("PM4PY_DEFAULT_GVIZ_VIEW", None)
DEFAULT_ENABLE_VISUALIZATIONS_VIEW = get_param_from_env("PM4PY_DEFAULT_ENABLE_VISUALIZATIONS_VIEW", True)
DEFAULT_ENABLE_GRAPH_TITLES = get_param_from_env("PM4PY_DEFAULT_ENABLE_GRAPH_TITLES", False)

JQUERY_LINK = "https://code.jquery.com/jquery-3.6.3.min.js"
GRAPHVIZJS_LINK = "https://github.com/mdaines/viz-js/releases/download/v1.8.2/viz.js"
Expand Down
Loading

0 comments on commit fc13d12

Please sign in to comment.