Skip to content

Commit 79cb32c

Browse files
committed
Add option to consider events as tasks or not
If events are considered as tasks, they are part of the reachability graph and the n-gram index as tasks. This means they are expected to be recorded in the trace-prefix. If not, events are considered as split points (i.e., no traversed unless needed to execute a task).
1 parent e1ee9ae commit 79cb32c

4 files changed

Lines changed: 359 additions & 7 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "ongoing-process-state"
3-
version = "2.0.3"
3+
version = "2.1.0"
44
description = "Build the n-gram index of a BPMN/Petri net process model to compute the state of an ongoing case in constant time."
55
authors = ["David Chapela de la Campa <david.chapela.delacampa@gmail.com>"]
66
readme = "README.md"

src/ongoing_process_state/bpmn_model.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def simulate_execution(self, node_id: str, marking: Set[str]) -> List[Set[str]]:
151151
152152
:param node_id: Identifier of the node to execute.
153153
:param marking: Current marking to simulate the execution over it.
154+
154155
:return: when it is possible to execute [node_id], list with the different markings result of such execution,
155156
otherwise, return empty list.
156157
"""
@@ -197,6 +198,7 @@ def get_enabled_nodes(self, marking: Set[str]) -> Set[str]:
197198
gateway, or event) is considered to be enabled when it can be fired.
198199
199200
:param marking: marking considered as reference to compute the enabled nodes.
201+
200202
:return: a set with the IDs of the enabled nodes (no start or end events).
201203
"""
202204
return {
@@ -213,6 +215,7 @@ def get_enabled_tasks_events(self, marking: Set[str]) -> Set[str]:
213215
Compute the set of enabled tasks or events (excluding start/end events) given the current [marking].
214216
215217
:param marking: marking considered as reference to compute the enabled nodes.
218+
216219
:return: a set with the IDs of the enabled tasks/events (no start or end events).
217220
"""
218221
return {
@@ -258,6 +261,7 @@ def advance_full_marking(
258261
self,
259262
marking: Set[str],
260263
explored_markings: Optional[Set[Tuple[str]]] = None,
264+
treat_event_as_task: bool = False
261265
) -> List[Tuple[str, Set[str]]]:
262266
"""
263267
Advance the current marking as much as possible without executing any task, i.e., execute gateways until there
@@ -268,6 +272,11 @@ def advance_full_marking(
268272
269273
:param marking: marking to consider as starting point to perform the advance operation.
270274
:param explored_markings: if recursive call, set of previously explored markings to avoid infinite loop.
275+
:param treat_event_as_task: if 'True', intermediate events are treated as tasks. This means there are edges
276+
in the reachability graph representing the execution of these events, and they are expected to be part of the
277+
n-gram. If 'False', intermediate events are considered as decision points, meaning that they would be traversed
278+
when necessary, without needing to be part of the n-gram.
279+
271280
:return: list of tuples with the ID of an enabled task/event as first element and the advanced marking that
272281
enabled it as second element.
273282
"""
@@ -276,7 +285,7 @@ def advance_full_marking(
276285
# First advance all branches at the same time until tasks, events, or decision points (XOR-split/OR-split)
277286
advanced_marking = self.advance_marking_until_decision_point(marking)
278287
# Advance all branches together (getting all combinations of advancements)
279-
tuples_fully_advanced_markings = self._advance_marking(advanced_marking, explored_markings)
288+
tuples_fully_advanced_markings = self._advance_marking(advanced_marking, explored_markings, treat_event_as_task)
280289
# Save only advanced marking that enabled new tasks/events
281290
for enabled_node_id, fully_advanced_marking in tuples_fully_advanced_markings:
282291
# Try to rollback the advancements in other branches as much as possible
@@ -290,6 +299,7 @@ def _advance_marking(
290299
self,
291300
marking: Set[str],
292301
explored_markings: Optional[Set[Tuple[str]]] = None,
302+
treat_event_as_task: bool = False
293303
) -> List[Tuple[str, Set[str]]]:
294304
"""
295305
Advance the current marking as much as possible without executing any task, i.e., execute gateways until there
@@ -301,6 +311,11 @@ def _advance_marking(
301311
302312
:param marking: marking to consider as starting point to perform the advance operation.
303313
:param explored_markings: if recursive call, set of previously explored markings to avoid infinite loop.
314+
:param treat_event_as_task: if 'True', intermediate events are treated as tasks. This means there are edges
315+
in the reachability graph representing the execution of these events, and they are expected to be part of the
316+
n-gram. If 'False', intermediate events are considered as decision points, meaning that they would be traversed
317+
when necessary, without needing to be part of the n-gram.
318+
304319
:return: list of tuples with the ID of the enabled task/event as first element, and the advanced marking that
305320
enabled it as second element.
306321
"""
@@ -327,9 +342,11 @@ def _advance_marking(
327342
enabled_gateways = [
328343
node_id
329344
for node_id in self.get_enabled_nodes(current_marking)
330-
if self.id_to_node[node_id].is_gateway()
345+
# Retain gateways, and events if they are not treated as tasks
346+
if (self.id_to_node[node_id].is_gateway() or
347+
(not treat_event_as_task and self.id_to_node[node_id].is_event()))
331348
]
332-
# If no enabled gateways, save fully advanced marking
349+
# If no enabled gateways (or events), save fully advanced marking
333350
if len(enabled_gateways) == 0:
334351
set_tuples_final_markings |= {
335352
(enabled_node_id, current_marking_key)
@@ -351,7 +368,7 @@ def _advance_marking(
351368
in self.advance_full_marking(advanced_marking, explored_markings)
352369
}
353370
else:
354-
# JOINs or XOR-split, execute and continue with advancement
371+
# JOINs or XOR-split (or event), execute and continue with advancement
355372
next_marking_stack += self.simulate_execution(gateway_id, current_marking)
356373
# Update new marking stack
357374
current_marking_stack = next_marking_stack
@@ -385,6 +402,7 @@ def _try_rollback(self, advanced_marking: Set[str], marking: Set[str], enabled_n
385402
:param advanced_marking: advanced marking result of advancing the branches in [marking] as much as possible.
386403
:param marking: marking considered as starting point.
387404
:param enabled_node_id: identifier of the node that is enabled and must remain enabled.
405+
388406
:return: rollbacked marking.
389407
"""
390408
rollbacked_marking = set()
@@ -437,6 +455,7 @@ def _advance_combination(self, combination: Set[str]) -> List[Set[str]]:
437455
branches until no more gateways are enabled (storing all markings reached during this expansion).
438456
439457
:param combination: marking to consider as starting point to perform the advance operation.
458+
440459
:return: list with the different markings result of such advancement.
441460
"""
442461
# If result in cache, retrieve, otherwise compute
@@ -478,12 +497,22 @@ def _advance_combination(self, combination: Set[str]) -> List[Set[str]]:
478497
# Return final set
479498
return final_markings
480499

481-
def get_reachability_graph(self, cached_search: bool = True) -> ReachabilityGraph:
500+
def get_reachability_graph(
501+
self,
502+
treat_event_as_task: bool = False,
503+
cached_search: bool = True
504+
) -> ReachabilityGraph:
482505
"""
483506
Compute the reachability graph of this BPMN model. Each marking in the reachability graph contains the enabled
484507
flows of that state, and corresponds to a state of the process where the only enabled elements are tasks,
485508
events, and decision points (XOR-split/OR-split).
486509
510+
:param treat_event_as_task: if 'True', intermediate events are treated as tasks. This means there are edges
511+
in the reachability graph representing the execution of these events, and they are expected to be part of the
512+
n-gram. If 'False', intermediate events are considered as decision points, meaning that they would be traversed
513+
when necessary, without needing to be part of the n-gram.
514+
:param cached_search: whether to cache expansion operations in the graph to save runtime.
515+
487516
:return: the reachability graph of this BPMN model.
488517
"""
489518
self._cached_search = cached_search
@@ -508,7 +537,10 @@ def get_reachability_graph(self, cached_search: bool = True) -> ReachabilityGrap
508537
# Advance the current marking, executing enabled gateways, obtaining:
509538
# An activity enabled by the advancement
510539
# The advanced marking needed to execute the activity
511-
tuples_advanced_markings = self.advance_full_marking(current_marking)
540+
tuples_advanced_markings = self.advance_full_marking(
541+
current_marking,
542+
treat_event_as_task=treat_event_as_task
543+
)
512544
# For each pair of enabled activity and advanced marking that enables it
513545
for enabled_node_id, advanced_marking in tuples_advanced_markings:
514546
enabled_node = self.id_to_node[enabled_node_id]

0 commit comments

Comments
 (0)