Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/hotfixes' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
fit-alessandro-berti committed Feb 22, 2024
2 parents e715afe + 0cc10bc commit 1567582
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 60 deletions.
29 changes: 28 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog of pm4py

## pm4py 2.7.11 (2024.02.23)

### Added

### Changed

### Deprecated

### Fixed
* c2278110acbbbf36e8fe5055e0b76f867e833da4
* bug fix POWL package
* d36d0d2ff8133bc979638b7f3405f96225e06ced
* bug fix discover_dfg_clean
* 64ce3341d40c073f274bdda9842fd92a0798a33f
* fixed typing of get_variants method
* ffd0761e8f5490382b33de4fa8187f1ed80ce802
* fixed stochastic Petri net PNML importing

### Removed

### Other
* c4d24d54013e2a18856af840ffbad7c76e86c371
81fa8017fbd25352fd87961bc4dcc1406c4e0dda
* Process tree to POWL utility

---


## pm4py 2.7.10 (2024.01.29)

Expand All @@ -14,7 +41,7 @@
* refactoring Scikit-Learn usage throughout the project
* bd1ac4fd04019b3022bfff55553e590aefbd21cb
* refactoring NetworkX usage throughout the project
*

### Deprecated

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.12.1
FROM python:3.12.2

RUN apt-get update
RUN apt-get -y upgrade
Expand Down
2 changes: 1 addition & 1 deletion pm4py/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
'''

__name__ = 'pm4py'
VERSION = '2.7.10'
VERSION = '2.7.10.1'
__version__ = VERSION
__doc__ = 'Process mining for Python'
__author__ = 'Fraunhofer Institute for Applied Information Technology FIT'
Expand Down
3 changes: 3 additions & 0 deletions pm4py/objects/petri_net/importer/variants/pnml.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ def import_net_from_xml_object(root, parameters=None):
priority = int(value)
elif key == "weight":
weight = float(value)
elif key == "invisible":
if value.lower() == "true":
trans_visible = False

from pm4py.objects.random_variables.random_variable import RandomVariable

Expand Down
83 changes: 32 additions & 51 deletions pm4py/objects/powl/obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
from pm4py.objects.powl.constants import STRICT_PARTIAL_ORDER_LABEL
from pm4py.objects.process_tree.obj import ProcessTree, Operator
from typing import List as TList, Optional, Union
from abc import ABC, abstractmethod


class POWL(ProcessTree):
class POWL(ProcessTree, ABC):
def __str__(self) -> str:
return self.__repr__()

Expand All @@ -44,65 +45,25 @@ def validate_partial_orders(self):
for child in self.children:
child.validate_partial_orders()

def validate_partial_orders_with_missing_transitive_edges(self):
if isinstance(self, StrictPartialOrder):
if not self.order.is_irreflexive():
raise Exception("The irreflexivity of the partial order is violated!")
if not self.order.is_transitive():
self.order.add_transitive_edges()
if not self.order.is_irreflexive():
raise Exception("The transitive closure of the provided relation violates irreflexivity!")
if hasattr(self, 'children'):
for child in self.children:
child.validate_partial_orders_with_missing_transitive_edges()

def validate_unique_transitions(self) -> TList[Union["Transition", "SilentTransition"]]:
def _find_duplicates(lst):
counts = {}
duplicates = []
for item in lst:
if item in counts:
counts[item] += 1
if counts[item] == 2:
duplicates.append(item)
else:
counts[item] = 1
return duplicates

def _collect_leaves(node: "POWL"):
if isinstance(node, Transition) or isinstance(node, SilentTransition):
return [node]

elif hasattr(node, 'children'):
leaves = []
for child in node.children:
leaves = leaves + _collect_leaves(child)
return leaves
else:
raise Exception(
"Unknown model type! The following model is not a transition and has no children: " + str(node))

transitions = _collect_leaves(self)
duplicate_transitions = _find_duplicates(transitions)
if len(duplicate_transitions) > 0:
raise Exception("Each of the following transitions occurs in multiple submodels: "
+ str([t.label if t.label else "silent transition" for t in duplicate_transitions]))
return transitions

@staticmethod
def model_description() -> str:
descr = """A partially ordered workflow language (POWL) is a partially ordered graph representation of a process, extended with control-flow operators for modeling choice and loop structures. There are four types of POWL models:
- an activity (identified by its label, i.e., 'M' identifies the activity M). Silent activities (i.e., with empty labels) are also supported.
- an activity (identified by its label, i.e., 'M' identifies the activity M). Silent activities with empty labels (tau labels) are also supported.
- a choice of other POWL models (an exclusive choice between the sub-models A and B is identified by X ( A, B ) )
- a loop node between two POWL models (a loop between the sub-models A and B is identified by * ( A, B ) and tells that you execute A, then you either exit the loop or execute B and then A again, this is repeated until you exit the loop).
- a partial order over a set of POWL models. A partial order is a binary relation that is irreflexive, transitive, and asymmetric. A partial order sets an execution order between the sub-models (i.e., the target node cannot be executed before the source node is completed).
- a partial order over a set of POWL models. A partial order is a binary relation that is irreflexive, transitive, and asymmetric. A partial order sets an execution order between the sub-models (i.e., the target node cannot be executed before the source node is completed). Unconnected nodes in a partial order are considered to be concurrent. An example is PO=(nodes={ NODE1, NODE2 }, order={ })
where NODE1 and NODE2 are independent and can be executed in parallel. Another example is PO=(nodes={ NODE1, NODE2 }, order={ NODE1-->NODE2 }) where NODE2 can only be executed after NODE1 is completed.
A more advanced example: PO=(nodes={ NODE1, NODE2, NODE3, X ( NODE4, NODE5 ) }, order={ NODE1-->NODE2, NODE1-->X ( NODE4, NODE5 ), NODE2-->X ( NODE4, NODE5 ) }), in this case, NODE2 can be executed only after NODE1 is completed, while the choice between NODE4 and NODE5 needs to wait until both NODE1 and NODE2 are finalized.
You can specify a POWL model as follows:
PO=(nodes={ NODE1, NODE2, NODE3, X ( NODE4, NODE5 ) }, order={ NODE1-->NODE2, NODE1-->X ( NODE4, NODE5 ), NODE2-->X ( NODE4, NODE5 ) })
in this case, NODE2 can be executed only after NODE1 is completed, while the choice between NODE4 and NODE5 needs to wait until both NODE1 and NODE2 are finalized.
"""
return descr

@abstractmethod
def copy(self):
pass


class Transition(POWL):
transition_id: int = 0
Expand All @@ -113,6 +74,9 @@ def __init__(self, label: Optional[str] = None) -> None:
self._identifier = Transition.transition_id
Transition.transition_id = Transition.transition_id + 1

def copy(self):
return Transition(self._label)

def __eq__(self, other: object) -> bool:
if isinstance(other, Transition):
return self._label == other._label and self._identifier == other._identifier
Expand Down Expand Up @@ -142,6 +106,9 @@ class SilentTransition(Transition):
def __init__(self) -> None:
super().__init__(label=None)

def copy(self):
return SilentTransition()


class FrequentTransition(Transition):
def __init__(self, label, min_freq: Union[str, int], max_freq: Union[str, int]) -> None:
Expand All @@ -167,6 +134,16 @@ def __init__(self, nodes: TList[POWL]) -> None:
self._set_order(nodes)
self.additional_information = None

def copy(self):
copied_nodes = {n:n.copy() for n in self.order.nodes}
res = StrictPartialOrder(list(copied_nodes.values()))
for n1 in self.order.nodes:
for n2 in self.order.nodes:
if self.order.is_edge(n1, n2):
res.add_edge(copied_nodes[n1], copied_nodes[n2])
return res


def _set_order(self, nodes: TList[POWL]) -> None:
self.order = BinaryRelation(nodes)

Expand Down Expand Up @@ -327,6 +304,10 @@ def __init__(self, operator: Operator, children: TList[POWL]) -> None:
self.operator = operator
self.children = children

def copy(self):
copied_nodes = [n.copy() for n in self.children]
return OperatorPOWL(self.operator, copied_nodes)

def __lt__(self, other: object) -> bool:
if isinstance(other, OperatorPOWL):
return self.__repr__() < other.__repr__()
Expand Down
4 changes: 2 additions & 2 deletions pm4py/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def get_trace_attribute_values(log: Union[EventLog, pd.DataFrame], attribute: st
return ret


def get_variants(log: Union[EventLog, pd.DataFrame], activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name") -> Dict[Tuple[str], List[Trace]]:
def get_variants(log: Union[EventLog, pd.DataFrame], activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name") -> Union[Dict[Tuple[str], List[Trace]], Dict[Tuple[str], int]]:
"""
Gets the variants from the log
Expand All @@ -228,7 +228,7 @@ def get_variants(log: Union[EventLog, pd.DataFrame], activity_key: str = "concep
return get_variants_as_tuples(log, activity_key=activity_key, timestamp_key=timestamp_key, case_id_key=case_id_key)


def get_variants_as_tuples(log: Union[EventLog, pd.DataFrame], activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name") -> Dict[Tuple[str], List[Trace]]:
def get_variants_as_tuples(log: Union[EventLog, pd.DataFrame], activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name") -> Union[Dict[Tuple[str], List[Trace]], Dict[Tuple[str], int]]:
"""
Gets the variants from the log (where the keys are tuples and not strings)
Expand Down
8 changes: 4 additions & 4 deletions requirements_stable.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ colorama==0.4.6
contourpy==1.2.0
cycler==0.12.1
deprecation==2.1.0
fonttools==4.48.1
fonttools==4.49.0
graphviz==0.20.1
intervaltree==3.1.0
kiwisolver==1.4.5
lxml==5.1.0
matplotlib==3.8.2
matplotlib==3.8.3
networkx==3.2.1
numpy==1.26.4
packaging==23.2
Expand All @@ -21,5 +21,5 @@ scipy==1.12.0
six==1.16.0
sortedcontainers==2.4.0
StringDist==1.0.9
tqdm==4.66.1
tzdata==2023.4
tqdm==4.66.2
tzdata==2024.1
47 changes: 47 additions & 0 deletions safety_checks/20240222
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
+==============================================================================+

/$$$$$$ /$$
/$$__ $$ | $$
/$$$$$$$ /$$$$$$ | $$ \__//$$$$$$ /$$$$$$ /$$ /$$
/$$_____/ |____ $$| $$$$ /$$__ $$|_ $$_/ | $$ | $$
| $$$$$$ /$$$$$$$| $$_/ | $$$$$$$$ | $$ | $$ | $$
\____ $$ /$$__ $$| $$ | $$_____/ | $$ /$$| $$ | $$
/$$$$$$$/| $$$$$$$| $$ | $$$$$$$ | $$$$/| $$$$$$$
|_______/ \_______/|__/ \_______/ \___/ \____ $$
/$$ | $$
| $$$$$$/
by pyup.io \______/

+==============================================================================+

REPORT

Safety is using PyUp's free open-source vulnerability database. This
data is 30 days old and limited.
For real-time enhanced vulnerability data, fix recommendations, severity
reporting, cybersecurity support, team and project policy management and more
sign up at https://pyup.io or email [email protected]

Safety v2.3.5 is scanning for Vulnerabilities...
Scanning dependencies in your files:

-> requirements_stable.txt

Using non-commercial database
Found and scanned 25 packages
Timestamp 2024-02-22 07:09:34
0 vulnerabilities found
0 vulnerabilities ignored
+==============================================================================+

No known security vulnerabilities found.

+==============================================================================+

Safety is using PyUp's free open-source vulnerability database. This
data is 30 days old and limited.
For real-time enhanced vulnerability data, fix recommendations, severity
reporting, cybersecurity support, team and project policy management and more
sign up at https://pyup.io or email [email protected]

+==============================================================================+

0 comments on commit 1567582

Please sign in to comment.