Skip to content

Commit

Permalink
Hotfix release
Browse files Browse the repository at this point in the history
  • Loading branch information
fit-alessandro-berti committed Feb 11, 2022
2 parents c8b4102 + 173c111 commit aae0e0f
Show file tree
Hide file tree
Showing 28 changed files with 709 additions and 124 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# PM4Py Changelog

## PM4Py 2.2.19.1

### Added
* a193603e
* Event-Object Feature Extraction on OCEL
* 8da05972
* Prefixes and Suffixes filters for Event Logs + Exposition in Simplified Interface

### Changed

### Deprecated

### Fixed
* cbf848ef
* Bug fix BPMN importer
* ff0dfc4b
* Closed security issue within dependencies

### Removed

### Other

## PM4Py 2.2.19

### Added
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN apt-get -y install libtool flex bison pkg-config g++ libssl-dev automake
RUN apt-get -y install libjemalloc-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-regex-dev python3-dev autoconf flex bison cmake
RUN apt-get -y install libxml2-dev libxslt-dev libfreetype6-dev libsuitesparse-dev
RUN pip install -U wheel six pytest
RUN pip install backcall==0.2.0 colorama==0.4.4 cycler==0.11.0 decorator==5.1.1 deprecation==2.1.0 fonttools==4.28.5 graphviz==0.19.1 intervaltree==3.1.0 ipython==8.0.1 jedi==0.18.1 jinja2==3.0.3 joblib==1.1.0 jsonpickle==2.1.0 kiwisolver==1.3.2 lxml==4.7.1 MarkupSafe==2.0.1 matplotlib==3.5.1 matplotlib-inline==0.1.3 mpmath==1.2.1 networkx==2.6.3 numpy==1.21.5 packaging==21.3 pandas==1.4.0 parso==0.8.3 pickleshare==0.7.5 pillow==9.0.0 prompt-toolkit==3.0.24 pydotplus==2.0.2 pygments==2.11.2 pyparsing==3.0.7 python-dateutil==2.8.2 pytz==2021.3 pyvis==0.1.9 scipy==1.7.3 setuptools==60.5.0 setuptools-scm==6.4.2 six==1.16.0 sortedcontainers==2.4.0 stringdist==1.0.9 sympy==1.9 threadpoolctl==3.0.0 tomli==2.0.0 tqdm==4.62.3 traitlets==5.1.1 wcwidth==0.2.5
RUN pip install backcall==0.2.0 colorama==0.4.4 cycler==0.11.0 decorator==5.1.1 deprecation==2.1.0 fonttools==4.29.1 graphviz==0.19.1 intervaltree==3.1.0 ipython==8.0.1 jedi==0.18.1 jinja2==3.0.3 jsonpickle==2.1.0 kiwisolver==1.3.2 lxml==4.7.1 MarkupSafe==2.0.1 matplotlib==3.5.1 matplotlib-inline==0.1.3 mpmath==1.2.1 networkx==2.6.3 numpy==1.22.2 packaging==21.3 pandas==1.4.0 parso==0.8.3 pickleshare==0.7.5 pillow==9.0.1 prompt-toolkit==3.0.27 pydotplus==2.0.2 pygments==2.11.2 pyparsing==3.0.7 python-dateutil==2.8.2 pytz==2021.3 pyvis==0.1.9 scipy==1.8.0 setuptools==60.8.2 six==1.16.0 sortedcontainers==2.4.0 stringdist==1.0.9 sympy==1.9 tqdm==4.62.3 traitlets==5.1.1 wcwidth==0.2.5

COPY . /app
RUN cd /app && python setup.py install
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# The short X.Y version
version = '2.2'
# The full version, including alpha/beta/rc tags
release = '2.2.19'
release = '2.2.19.1'

# -- General configuration ---------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion pm4py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
filter_between, filter_case_size, filter_case_performance, filter_activities_rework, filter_paths_performance, \
filter_variants_by_coverage_percentage, filter_variants_top_k, filter_ocel_event_attribute, filter_ocel_object_attribute, \
filter_ocel_object_types_allowed_activities, filter_ocel_object_per_type_count, filter_ocel_start_events_per_object_type, \
filter_ocel_end_events_per_object_type, filter_ocel_events_timestamp
filter_ocel_end_events_per_object_type, filter_ocel_events_timestamp, filter_prefixes, filter_suffixes
from pm4py.hof import filter_log, filter_trace, sort_trace, sort_log
from pm4py.meta import __name__, __version__, __doc__, __author__, __author_email__, \
__maintainer__, __maintainer_email__
Expand Down
1 change: 1 addition & 0 deletions pm4py/algo/filtering/log/prefixes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from pm4py.algo.filtering.log.prefixes import prefix_filter
62 changes: 62 additions & 0 deletions pm4py/algo/filtering/log/prefixes/prefix_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from enum import Enum
from pm4py.util import exec_utils, xes_constants, constants
from pm4py.objects.log.obj import EventLog, EventStream, Trace
from typing import Dict, Optional, Any, Union
from pm4py.objects.conversion.log import converter as log_converter


class Parameters(Enum):
ACTIVITY_KEY = constants.PARAMETER_CONSTANT_ACTIVITY_KEY
STRICT = "strict"
FIRST_OR_LAST = "first_or_last"


def apply(log: Union[EventLog, EventStream], activity: str, parameters: Optional[Dict[Any, Any]] = None) -> EventLog:
"""
Filters the prefixes of an activity in the event log
Parameters
----------------
log
Event log
activity
Target activity
parameters
Parameters of the algorithm, including:
- Parameters.ACTIVITY_KEY => the activity.
- Parameters.STRICT => applies the filter strictly (cuts the occurrences of the selected activity).
- Parameters.FIRST_OR_LAST => decides if the first or last occurrence of an activity should be selected.
Returns
----------------
filtered_log
Filtered event log
"""
if parameters is None:
parameters = {}

log = log_converter.apply(log, parameters=parameters)

activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY)
first_or_last = exec_utils.get_param_value(Parameters.FIRST_OR_LAST, parameters, "first")
strict = exec_utils.get_param_value(Parameters.STRICT, parameters, True)

filtered_log = EventLog(attributes=log.attributes, extensions=log.extensions, globals=log._omni,
classifiers=log.classifiers, properties=log.properties)

for trace in log:
activities = [x[activity_key] if activity_key in x else None for x in trace]
if activity in activities:
if first_or_last == "first":
op = min
else:
op = max
idx_activity = op(i for i in range(len(activities)) if activities[i] == activity)
if not strict:
idx_activity = idx_activity + 1
filtered_trace = Trace(attributes=trace.attributes, properties=trace.properties)
for i in range(0, idx_activity):
filtered_trace.append(trace[i])
filtered_log.append(filtered_trace)

return filtered_log
1 change: 1 addition & 0 deletions pm4py/algo/filtering/log/suffixes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from pm4py.algo.filtering.log.suffixes import suffix_filter
62 changes: 62 additions & 0 deletions pm4py/algo/filtering/log/suffixes/suffix_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from enum import Enum
from pm4py.util import exec_utils, xes_constants, constants
from pm4py.objects.log.obj import EventLog, EventStream, Trace
from typing import Dict, Optional, Any, Union
from pm4py.objects.conversion.log import converter as log_converter


class Parameters(Enum):
ACTIVITY_KEY = constants.PARAMETER_CONSTANT_ACTIVITY_KEY
STRICT = "strict"
FIRST_OR_LAST = "first_or_last"


def apply(log: Union[EventLog, EventStream], activity: str, parameters: Optional[Dict[Any, Any]] = None) -> EventLog:
"""
Filters the suffixes of an activity in the event log
Parameters
----------------
log
Event log
activity
Target activity
parameters
Parameters of the algorithm, including:
- Parameters.ACTIVITY_KEY => the activity.
- Parameters.STRICT => applies the filter strictly (cuts the occurrences of the selected activity).
- Parameters.FIRST_OR_LAST => decides if the first or last occurrence of an activity should be selected.
Returns
----------------
filtered_log
Filtered event log
"""
if parameters is None:
parameters = {}

log = log_converter.apply(log, parameters=parameters)

activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY)
first_or_last = exec_utils.get_param_value(Parameters.FIRST_OR_LAST, parameters, "first")
strict = exec_utils.get_param_value(Parameters.STRICT, parameters, True)

filtered_log = EventLog(attributes=log.attributes, extensions=log.extensions, globals=log._omni,
classifiers=log.classifiers, properties=log.properties)

for trace in log:
activities = [x[activity_key] if activity_key in x else None for x in trace]
if activity in activities:
if first_or_last == "first":
op = min
else:
op = max
idx_activity = op(i for i in range(len(activities)) if activities[i] == activity)
if strict:
idx_activity = idx_activity + 1
filtered_trace = Trace(attributes=trace.attributes, properties=trace.properties)
for i in range(idx_activity, len(trace)):
filtered_trace.append(trace[i])
filtered_log.append(filtered_trace)

return filtered_log
19 changes: 1 addition & 18 deletions pm4py/algo/transformation/ocel/features/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
'''
This file is part of PM4Py (More Info: https://pm4py.fit.fraunhofer.de).
PM4Py is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PM4Py 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with PM4Py. If not, see <https://www.gnu.org/licenses/>.
'''
from pm4py.algo.transformation.ocel.features import objects, events

from pm4py.algo.transformation.ocel.features import objects, events, events_objects
18 changes: 1 addition & 17 deletions pm4py/algo/transformation/ocel/features/events/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1 @@
'''
This file is part of PM4Py (More Info: https://pm4py.fit.fraunhofer.de).
PM4Py is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PM4Py 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with PM4Py. If not, see <https://www.gnu.org/licenses/>.
'''
from pm4py.algo.transformation.ocel.features.events import algorithm, event_activity, event_timestamp, event_num_rel_objs_type, event_num_rel_objs, event_str_attributes, event_num_attributes, event_start_ot, event_end_ot, related_objects_features
from pm4py.algo.transformation.ocel.features.events import algorithm, event_activity, event_timestamp, event_num_rel_objs_type, event_num_rel_objs, event_str_attributes, event_num_attributes, event_start_ot, event_end_ot, related_objects_features, new_interactions
13 changes: 12 additions & 1 deletion pm4py/algo/transformation/ocel/features/events/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from typing import Optional, Dict, Any, List
from enum import Enum
from pm4py.util import exec_utils
from pm4py.algo.transformation.ocel.features.events import event_activity, event_num_rel_objs, event_num_rel_objs_type, event_timestamp, event_str_attributes, event_num_attributes, event_start_ot, event_end_ot, related_objects_features
from pm4py.algo.transformation.ocel.features.events import event_activity, event_num_rel_objs, event_num_rel_objs_type, event_timestamp, event_str_attributes, event_num_attributes, event_start_ot, event_end_ot, related_objects_features, new_interactions


class Parameters(Enum):
Expand All @@ -31,6 +31,7 @@ class Parameters(Enum):
ENABLE_EVENT_NUM_ATTRIBUTES = "enable_event_num_attributes"
ENABLE_EVENT_START_OT = "enable_event_start_ot"
ENABLE_EVENT_END_OT = "enable_event_end_ot"
ENABLE_NEW_INTERACTIONS = "enable_new_interactions"
ENABLE_RELATED_OBJECTS_FEATURES = "enable_related_objects_features"


Expand All @@ -57,6 +58,8 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None):
lifecycle of some objects of a type.
- Parameters.ENABLE_EVENT_END_OT => calculates some features which establish if the event completes the
lifecycle of some objects of a type.
- Parameters.ENABLE_NEW_INTERACTIONS => number of new interactions between the related objects which
appears in a given event.
- Parameters.ENABLE_RELATED_OBJECTS_FEATURES => associates to the event some features calculated on the
related objects.
Expand All @@ -79,6 +82,8 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None):
enable_event_num_attributes = exec_utils.get_param_value(Parameters.ENABLE_EVENT_NUM_ATTRIBUTES, parameters, enable_all)
enable_event_start_ot = exec_utils.get_param_value(Parameters.ENABLE_EVENT_START_OT, parameters, enable_all)
enable_event_end_ot = exec_utils.get_param_value(Parameters.ENABLE_EVENT_END_OT, parameters, enable_all)
enable_new_interactions = exec_utils.get_param_value(Parameters.ENABLE_NEW_INTERACTIONS, parameters, enable_all)

enable_related_objects_features = exec_utils.get_param_value(Parameters.ENABLE_RELATED_OBJECTS_FEATURES, parameters, False)

ordered_events = list(ocel.events[ocel.event_id_column])
Expand Down Expand Up @@ -134,6 +139,12 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None):
for i in range(len(data)):
datas[i] = datas[i] + data[i]

if enable_new_interactions:
data, feature_names = new_interactions.apply(ocel, parameters=parameters)
feature_namess = feature_namess + feature_names
for i in range(len(data)):
datas[i] = datas[i] + data[i]

if enable_related_objects_features:
data, feature_names = related_objects_features.apply(ocel, parameters=parameters)
feature_namess = feature_namess + feature_names
Expand Down
43 changes: 43 additions & 0 deletions pm4py/algo/transformation/ocel/features/events/new_interactions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from pm4py.objects.ocel.obj import OCEL
from typing import Optional, Dict, Any


def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None):
"""
Discovers the number of new interactions between the related objects which appears in a given event.
Parameters
---------------
ocel
OCEL
parameters
Parameters of the method
Returns
----------------
data
Extracted feature values
feature_names
Feature names
"""
if parameters is None:
parameters = {}

ordered_events = list(ocel.events[ocel.event_id_column])
rel_objs = ocel.relations.groupby(ocel.event_id_column)[ocel.object_id_column].agg(list).to_dict()

interactions = set()
data = []
feature_names = ["@@ev_new_interactions"]

for ev in ordered_events:
n = 0
if ev in rel_objs:
for o1 in rel_objs[ev]:
for o2 in rel_objs[ev]:
if o1 < o2:
if not (o1, o2) in interactions:
n = n + 1
data.append([n])

return data, feature_names
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from pm4py.algo.transformation.ocel.features.events_objects import algorithm, prefix_features
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from pm4py.objects.ocel.obj import OCEL
from typing import Optional, Dict, Any
from pm4py.algo.transformation.ocel.features.events import algorithm as event_feature_extraction
from pm4py.algo.transformation.ocel.features.events_objects import prefix_features
from pm4py.objects.ocel.util import explode
from copy import copy
from enum import Enum
from pm4py.util import exec_utils


class Parameters(Enum):
ENABLE_ALL_EO_FEATURES = "enable_all_eo_features"
ENABLE_EVENT_POINTWISE_FEATURES = "enable_event_pointwise_features"
ENABLE_PREFIX_FEATURES = "enable_prefix_features"


def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None):
"""
Extract features that are related to the different combinations of events and objects of the OCEL.
Parameters
-----------------
ocel
Object-centric event log
parameters
Parameters of the algorithm, including:
- Parameters.ENABLE_ALL_EO_FEATURES => enables all the belowmentioned features
- Parameters.ENABLE_EVENT_POINTWISE_FEATURES => enables the calculation of pointwise features for the events
- Parameters.ENABLE_PREFIX_FEATURES => enables the prefix features
Returns
-----------------
data
Values of the features
feature_names
Names of the features
"""
if parameters is None:
parameters = {}

enable_all = exec_utils.get_param_value(Parameters.ENABLE_ALL_EO_FEATURES, parameters, True)
enable_event_pointwise_features = exec_utils.get_param_value(Parameters.ENABLE_EVENT_POINTWISE_FEATURES, parameters, enable_all)
enable_prefix_features = exec_utils.get_param_value(Parameters.ENABLE_PREFIX_FEATURES, parameters, enable_all)

exploded_ocel = explode.apply(ocel)
ordered_events = list(exploded_ocel.events[exploded_ocel.event_id_column])

datas = []
features_namess = []
for i in range(len(ordered_events)):
datas.append([])

if enable_event_pointwise_features:
parameters_efe = copy(parameters)
parameters_efe["enable_all"] = False
parameters_efe["enable_related_objects_features"] = False
parameters_efe["enable_event_activity"] = True
parameters_efe["enable_event_timestamp"] = True
parameters_efe["enable_event_num_rel_objs_type"] = True
parameters_efe["enable_event_str_attributes"] = True
parameters_efe["enable_event_num_attributes"] = True
parameters_efe["enable_event_start_ot"] = True
data, feature_names = event_feature_extraction.apply(exploded_ocel, parameters=parameters_efe)
for i in range(len(data)):
datas[i] = datas[i] + data[i]
features_namess = features_namess + feature_names

if enable_prefix_features:
data, feature_names = prefix_features.apply(exploded_ocel, parameters=parameters)
for i in range(len(data)):
datas[i] = datas[i] + data[i]
features_namess = features_namess + feature_names

return datas, features_namess
Loading

0 comments on commit aae0e0f

Please sign in to comment.