openprocess 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. cpnpy/__init__.py +46 -0
  2. openprocess/__init__.py +57 -0
  3. openprocess/analysis/__init__.py +0 -0
  4. openprocess/analysis/state_space.py +521 -0
  5. openprocess/analysis/state_space_process.py +251 -0
  6. openprocess/cli.py +742 -0
  7. openprocess/exercises/1 Petri nets/Exercise 1.1 Order handling/answer.pnml +31 -0
  8. openprocess/exercises/1 Petri nets/Exercise 1.1 Order handling/question.md +38 -0
  9. openprocess/exercises/2 Soundness/Exercise 2.1 Spot the flaw/answer.pnml +27 -0
  10. openprocess/exercises/2 Soundness/Exercise 2.1 Spot the flaw/net.pnml +29 -0
  11. openprocess/exercises/2 Soundness/Exercise 2.1 Spot the flaw/question.md +65 -0
  12. openprocess/exercises/3 Discovery/Exercise 3.1 The alpha-algorithm/log.txt +1 -0
  13. openprocess/exercises/3 Discovery/Exercise 3.1 The alpha-algorithm/question.md +67 -0
  14. openprocess/exercises/4 Regions/Exercise 4.1 Regions of a transition system/question.md +75 -0
  15. openprocess/exercises/4 Regions/Exercise 4.1 Regions of a transition system/ts.txt +5 -0
  16. openprocess/exercises/5 Markings/Exercise 5.1 Markings and matrices/net.pnml +27 -0
  17. openprocess/exercises/5 Markings/Exercise 5.1 Markings and matrices/question.md +65 -0
  18. openprocess/exercises/6 Inductive Miner/Exercise 6.1 Cuts and trees/log.txt +1 -0
  19. openprocess/exercises/6 Inductive Miner/Exercise 6.1 Cuts and trees/question.md +62 -0
  20. openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/log.txt +1 -0
  21. openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/m1.pnml +36 -0
  22. openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/m2.pnml +28 -0
  23. openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/m3.pnml +30 -0
  24. openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/net.pnml +36 -0
  25. openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/question.md +69 -0
  26. openprocess/exercises/pack.md +14 -0
  27. openprocess/flow/__init__.py +50 -0
  28. openprocess/flow/box.py +466 -0
  29. openprocess/flow/boxes/__init__.py +7 -0
  30. openprocess/flow/boxes/check.py +119 -0
  31. openprocess/flow/boxes/compare.py +16 -0
  32. openprocess/flow/boxes/cpn.py +53 -0
  33. openprocess/flow/boxes/discover.py +124 -0
  34. openprocess/flow/boxes/filter.py +80 -0
  35. openprocess/flow/boxes/input.py +124 -0
  36. openprocess/flow/boxes/output.py +52 -0
  37. openprocess/flow/boxes/predict.py +186 -0
  38. openprocess/flow/boxes/science.py +159 -0
  39. openprocess/flow/boxes/sweeps.py +18 -0
  40. openprocess/flow/convert.py +187 -0
  41. openprocess/flow/datasets.py +198 -0
  42. openprocess/flow/explain.py +115 -0
  43. openprocess/flow/library.py +222 -0
  44. openprocess/flow/record.py +385 -0
  45. openprocess/flow/runner.py +357 -0
  46. openprocess/flow/sweep.py +92 -0
  47. openprocess/flow/types.py +290 -0
  48. openprocess/flow/workflow.py +628 -0
  49. openprocess/gui/__init__.py +0 -0
  50. openprocess/gui/app.py +90 -0
  51. openprocess/gui/arc_editing.py +295 -0
  52. openprocess/gui/canvas.py +1414 -0
  53. openprocess/gui/flow/__init__.py +8 -0
  54. openprocess/gui/flow/canvas.py +854 -0
  55. openprocess/gui/flow/page.py +972 -0
  56. openprocess/gui/flow/templates.py +131 -0
  57. openprocess/gui/flow/viewers.py +665 -0
  58. openprocess/gui/items.py +1275 -0
  59. openprocess/gui/learn/answer_boxes.py +978 -0
  60. openprocess/gui/learn/concealment.py +91 -0
  61. openprocess/gui/learn/mode.py +1181 -0
  62. openprocess/gui/panning.py +241 -0
  63. openprocess/gui/resources/openprocess-icon.png +0 -0
  64. openprocess/gui/studio/__init__.py +1 -0
  65. openprocess/gui/studio/__main__.py +3 -0
  66. openprocess/gui/studio/app.py +4031 -0
  67. openprocess/gui/studio/charts.py +115 -0
  68. openprocess/gui/studio/compare_page.py +487 -0
  69. openprocess/gui/studio/cpn_page.py +1858 -0
  70. openprocess/gui/studio/definition_view.py +284 -0
  71. openprocess/gui/studio/derivation_view.py +421 -0
  72. openprocess/gui/studio/documents.py +152 -0
  73. openprocess/gui/studio/dotted_chart.py +1401 -0
  74. openprocess/gui/studio/file_dialogs.py +143 -0
  75. openprocess/gui/studio/filter_dialog.py +247 -0
  76. openprocess/gui/studio/graph_builders.py +176 -0
  77. openprocess/gui/studio/graph_view.py +682 -0
  78. openprocess/gui/studio/instances.py +413 -0
  79. openprocess/gui/studio/log_editor.py +675 -0
  80. openprocess/gui/studio/log_page.py +800 -0
  81. openprocess/gui/studio/markdown_view.py +127 -0
  82. openprocess/gui/studio/mathtext.py +260 -0
  83. openprocess/gui/studio/ml_highlighter.py +75 -0
  84. openprocess/gui/studio/model_page.py +760 -0
  85. openprocess/gui/studio/net_comparison.py +124 -0
  86. openprocess/gui/studio/notes_overlay.py +275 -0
  87. openprocess/gui/studio/petri_page.py +844 -0
  88. openprocess/gui/studio/regions_view.py +502 -0
  89. openprocess/gui/studio/sidebar.py +149 -0
  90. openprocess/gui/studio/style.py +503 -0
  91. openprocess/gui/studio/tool_icons.py +134 -0
  92. openprocess/gui/studio/updates.py +439 -0
  93. openprocess/gui/studio/widgets.py +899 -0
  94. openprocess/gui/studio/workers.py +60 -0
  95. openprocess/gui/studio/workspace.py +447 -0
  96. openprocess/gui/theme.py +394 -0
  97. openprocess/gui/tidy.py +86 -0
  98. openprocess/io/__init__.py +0 -0
  99. openprocess/io/cpn_reader.py +389 -0
  100. openprocess/io/cpn_writer.py +357 -0
  101. openprocess/learn/__init__.py +23 -0
  102. openprocess/learn/answers.py +188 -0
  103. openprocess/learn/checks.py +953 -0
  104. openprocess/learn/computed.py +1180 -0
  105. openprocess/learn/context.py +145 -0
  106. openprocess/learn/exam.py +169 -0
  107. openprocess/learn/exercise-packs.md +325 -0
  108. openprocess/learn/importer.py +216 -0
  109. openprocess/learn/notation.py +474 -0
  110. openprocess/learn/pack.py +511 -0
  111. openprocess/learn/sheet.py +296 -0
  112. openprocess/mining/__init__.py +73 -0
  113. openprocess/mining/analysis.py +689 -0
  114. openprocess/mining/columns.py +282 -0
  115. openprocess/mining/compare_nets.py +246 -0
  116. openprocess/mining/conformance/__init__.py +0 -0
  117. openprocess/mining/conformance/alignments.py +263 -0
  118. openprocess/mining/conformance/quality.py +145 -0
  119. openprocess/mining/conformance/token_replay.py +252 -0
  120. openprocess/mining/csv_import.py +222 -0
  121. openprocess/mining/definitions.py +584 -0
  122. openprocess/mining/dfg.py +187 -0
  123. openprocess/mining/discovery/__init__.py +0 -0
  124. openprocess/mining/discovery/alpha.py +168 -0
  125. openprocess/mining/discovery/heuristics.py +332 -0
  126. openprocess/mining/discovery/inductive.py +477 -0
  127. openprocess/mining/discovery/state_regions.py +62 -0
  128. openprocess/mining/filtering.py +237 -0
  129. openprocess/mining/footprint.py +183 -0
  130. openprocess/mining/invariants.py +191 -0
  131. openprocess/mining/layout.py +279 -0
  132. openprocess/mining/log.py +364 -0
  133. openprocess/mining/petrinet.py +354 -0
  134. openprocess/mining/playout.py +75 -0
  135. openprocess/mining/pm4py_bridge.py +82 -0
  136. openprocess/mining/pnml.py +223 -0
  137. openprocess/mining/processtree.py +216 -0
  138. openprocess/mining/regions.py +476 -0
  139. openprocess/mining/stats.py +160 -0
  140. openprocess/mining/structure.py +374 -0
  141. openprocess/mining/transition_system.py +409 -0
  142. openprocess/mining/xes.py +399 -0
  143. openprocess/ml/__init__.py +0 -0
  144. openprocess/ml/ast_nodes.py +332 -0
  145. openprocess/ml/builtins.py +364 -0
  146. openprocess/ml/colorsets.py +522 -0
  147. openprocess/ml/errors.py +60 -0
  148. openprocess/ml/evaluator.py +754 -0
  149. openprocess/ml/lexer.py +277 -0
  150. openprocess/ml/multiset.py +417 -0
  151. openprocess/ml/parser.py +737 -0
  152. openprocess/ml/values.py +319 -0
  153. openprocess/model/__init__.py +0 -0
  154. openprocess/model/declarations.py +617 -0
  155. openprocess/model/examples.py +98 -0
  156. openprocess/model/net.py +701 -0
  157. openprocess/model/plain.py +192 -0
  158. openprocess/references.py +280 -0
  159. openprocess/sim/__init__.py +0 -0
  160. openprocess/sim/binding.py +620 -0
  161. openprocess/sim/export.py +66 -0
  162. openprocess/sim/simulator.py +315 -0
  163. openprocess/teaching/__init__.py +4 -0
  164. openprocess/teaching/answers.py +4 -0
  165. openprocess/teaching/checks.py +5 -0
  166. openprocess/teaching/pack.py +4 -0
  167. openprocess/teaching/sheet.py +4 -0
  168. openprocess-0.7.0.dist-info/METADATA +927 -0
  169. openprocess-0.7.0.dist-info/RECORD +173 -0
  170. openprocess-0.7.0.dist-info/WHEEL +5 -0
  171. openprocess-0.7.0.dist-info/entry_points.txt +6 -0
  172. openprocess-0.7.0.dist-info/licenses/LICENSE +21 -0
  173. openprocess-0.7.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,584 @@
1
+ """Mathematical definitions of every property the analyses report.
2
+
3
+ This is the single source for
4
+
5
+ * ``docs/definitions.md`` -- generated from this module with
6
+ ``python -m openprocess.mining.definitions > docs/definitions.md`` (a test checks
7
+ that the file is up to date), where GitHub renders the maths; and
8
+ * the pop-ups in the app: hover over or click a property in an Analysis tab
9
+ to see its definition, typeset by :mod:`openprocess.gui.studio.mathtext`.
10
+
11
+ Formulas are written in a small subset of LaTeX that both GitHub (MathJax)
12
+ and the app's renderer understand; :mod:`openprocess.gui.studio.mathtext` lists it. Braces are
13
+ written ``\\lbrace`` / ``\\rbrace`` because GitHub's Markdown would otherwise
14
+ eat the backslash of ``\\{``.
15
+
16
+ The definitions follow W.M.P. van der Aalst, *Workflow Verification: Finding
17
+ Control-Flow Errors Using Petri-Net-Based Techniques* (2000) and *Process
18
+ Mining: Data Science in Action* (2016), with the notation of the course.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from dataclasses import dataclass, field
24
+
25
+ AALST_2000 = ("W.M.P. van der Aalst, *Workflow Verification: Finding Control-Flow Errors "
26
+ "Using Petri-Net-Based Techniques* (2000)")
27
+ AALST_2016 = "W.M.P. van der Aalst, *Process Mining: Data Science in Action* (2016)"
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class Definition:
32
+ #: Identifier used by the app (``"sound"``, ``"live"``, ...).
33
+ key: str
34
+ #: Heading, e.g. "Sound".
35
+ name: str
36
+ #: One or two sentences in words: what it means, why it matters.
37
+ summary: str
38
+ #: Display formulas, one per line, in the LaTeX subset.
39
+ formulas: tuple[str, ...]
40
+ #: Extra remarks in words (may contain inline maths between ``$``).
41
+ notes: tuple[str, ...] = ()
42
+ #: Where it comes from, e.g. "van der Aalst 2000, Definition 12".
43
+ source: str = ""
44
+ #: The section it belongs to (see :data:`SECTIONS`).
45
+ section: str = ""
46
+ #: Keys of definitions this one builds on.
47
+ uses: tuple[str, ...] = field(default=())
48
+
49
+
50
+ SECTIONS = [
51
+ ("notation", "Notation",
52
+ "The basic vocabulary every other definition is written in."),
53
+ ("behaviour", "Behavioural properties",
54
+ "Properties of a *marked* Petri net $(N, M_0)$: they depend on the initial "
55
+ "marking and are decided on the reachability (or coverability) graph."),
56
+ ("workflow", "Workflow nets and soundness",
57
+ "A WF-net models the life cycle of one case, from its start place $i$ to its end "
58
+ "place $o$."),
59
+ ("structure", "Structural properties",
60
+ "Properties of the drawing alone — places, transitions and arcs, no markings. They "
61
+ "are quick to check and point at the construct behind a problem."),
62
+ ("invariants", "Invariants",
63
+ "Linear algebra on the drawing: what firing does to each place, written as a "
64
+ "matrix, and the weightings and firing counts it leaves unchanged. Like the "
65
+ "structural properties they need no state space."),
66
+ ("footprint", "Footprints",
67
+ "The ordering relations of the α-algorithm, for an event log or for the behaviour "
68
+ "of a net."),
69
+ ("regions", "Transition systems and regions",
70
+ "Two-phase discovery: an event log becomes a transition system, and the transition "
71
+ "system's regions become the places of a Petri net. Throughout, "
72
+ "$TS = (S, E, T, s_{in})$ is a transition system."),
73
+ ]
74
+
75
+ MURATA_1989 = ("T. Murata, *Petri Nets: Properties, Analysis and Applications*, "
76
+ "Proceedings of the IEEE 77(4) (1989)")
77
+ CORTADELLA_1998 = ("J. Cortadella, M. Kishinevsky, L. Lavagno and A. Yakovlev, *Deriving Petri "
78
+ "Nets from Finite Transition Systems*, IEEE Transactions on Computers 47(8) "
79
+ "(1998)")
80
+
81
+
82
+ DEFINITIONS: tuple[Definition, ...] = (
83
+ # -- notation ----------------------------------------------------------------------
84
+ Definition(
85
+ "petri_net", "Petri net",
86
+ "A bipartite graph of places (circles, conditions) and transitions (boxes, "
87
+ "actions), connected by arcs.",
88
+ (r"N = (P, T, F)",
89
+ r"P \cap T = \emptyset, \quad F \subseteq (P \times T) \cup (T \times P)"),
90
+ ("Plain nets in the course have arc weight 1. The editor also allows a weight "
91
+ "$W(f) \\in \\mathbb{N}$ on an arc $f \\in F$; a transition then needs, and "
92
+ "produces, that many tokens.",),
93
+ f"{AALST_2000}, Definition 1", "notation"),
94
+ Definition(
95
+ "preset", "Pre-set and post-set",
96
+ "The input nodes and the output nodes of a node.",
97
+ (r"\bullet x = \lbrace y \mid (y, x) \in F \rbrace",
98
+ r"x \bullet = \lbrace y \mid (x, y) \in F \rbrace"),
99
+ ("For a transition $t$, $\\bullet t$ are its input places and $t \\bullet$ its "
100
+ "output places.",),
101
+ f"{AALST_2000}, Section 3", "notation", ("petri_net",)),
102
+ Definition(
103
+ "marking", "Marking",
104
+ "The state of a net: how many tokens each place holds.",
105
+ (r"M \colon P \to \mathbb{N}",
106
+ r"M_1 \geq M_2 \iff \forall p \in P \colon M_1(p) \geq M_2(p)"),
107
+ ("Markings are written as multisets: $[i]$ is one token in $i$, "
108
+ "$[p_1, 2 p_2]$ is one token in $p_1$ and two in $p_2$.",),
109
+ f"{AALST_2000}, Section 3", "notation", ("petri_net",)),
110
+ Definition(
111
+ "firing", "Enabling and firing",
112
+ "A transition is enabled when every input place has a token. Firing it takes one "
113
+ "token from each input place and puts one in each output place.",
114
+ (r"t \text{ enabled in } M \iff \forall p \in \bullet t \colon M(p) \geq 1",
115
+ r"M \xrightarrow{t} M' \iff t \text{ enabled in } M \land "
116
+ r"M' = M - \bullet t + t \bullet"),
117
+ (),
118
+ f"{AALST_2000}, Section 3", "notation", ("marking", "preset")),
119
+ Definition(
120
+ "reachability", "Reachable markings",
121
+ "The markings a net can get to by firing transitions, one after the other.",
122
+ (r"M \xrightarrow{\sigma} M' \iff \sigma = \langle t_1, \ldots, t_n \rangle "
123
+ r"\land M \xrightarrow{t_1} M_1 \xrightarrow{t_2} \cdots \xrightarrow{t_n} M'",
124
+ r"M \xrightarrow{*} M' \iff \exists \sigma \colon M \xrightarrow{\sigma} M'",
125
+ r"R(N, M_0) = \lbrace M \mid M_0 \xrightarrow{*} M \rbrace"),
126
+ ("The empty sequence is allowed, so $M \\xrightarrow{*} M$ always holds. The "
127
+ "reachability graph has the markings in $R(N, M_0)$ as nodes and an edge for "
128
+ "every firing between them.",),
129
+ f"{AALST_2000}, Section 3", "notation", ("firing",)),
130
+
131
+ # -- behaviour ---------------------------------------------------------------------
132
+ Definition(
133
+ "bounded", "Bounded",
134
+ "No place can ever hold more than some fixed number of tokens. Then the "
135
+ "reachability graph is finite.",
136
+ (r"(N, M_0) \text{ is } k\text{-bounded} \iff \forall M \in R(N, M_0) \; "
137
+ r"\forall p \in P \colon M(p) \leq k",
138
+ r"(N, M_0) \text{ is bounded} \iff \exists k \in \mathbb{N} \colon (N, M_0) "
139
+ r"\text{ is } k\text{-bounded}"),
140
+ ("If the net is unbounded, the app builds the coverability graph instead, where "
141
+ "$\\omega$ marks a place that can hold arbitrarily many tokens.",),
142
+ f"{AALST_2000}, Definition 3", "behaviour", ("reachability",)),
143
+ Definition(
144
+ "safe", "Safe",
145
+ "Every place holds at most one token, so a place is a condition that is either "
146
+ "true or false.",
147
+ (r"(N, M_0) \text{ is safe} \iff \forall M \in R(N, M_0) \; \forall p \in P "
148
+ r"\colon M(p) \leq 1",),
149
+ ("Safe is the same as 1-bounded. A sound free-choice WF-net and a sound "
150
+ "well-structured WF-net are always safe.",),
151
+ f"{AALST_2000}, Definition 3, Lemmas 1 and 3", "behaviour", ("bounded",)),
152
+ Definition(
153
+ "deadlock_free", "Deadlock-free",
154
+ "No reachable marking is dead, i.e. the net can never get stuck with nothing "
155
+ "enabled.",
156
+ (r"M \text{ is dead} \iff \forall t \in T \colon t \text{ is not enabled in } M",
157
+ r"(N, M_0) \text{ is deadlock-free} \iff \forall M \in R(N, M_0) \colon "
158
+ r"M \text{ is not dead}"),
159
+ ("A WF-net always stops in $[o]$, which is a dead marking, so for WF-nets the "
160
+ "question is asked about the short-circuited net $\\overline{N}$, where $[o]$ "
161
+ "enables $t^*$.",
162
+ "Deadlock-free is weaker than live: a net can keep firing in a loop while some "
163
+ "transition is dead. Live implies deadlock-free (when $T \\neq \\emptyset$), "
164
+ "not the other way round."),
165
+ "course lecture on Petri net properties", "behaviour",
166
+ ("reachability", "short_circuit")),
167
+ Definition(
168
+ "dead_transition", "Dead transition",
169
+ "A transition that can never fire, whatever happens first.",
170
+ (r"t \text{ is dead in } (N, M_0) \iff \neg \exists M \in R(N, M_0) \colon "
171
+ r"t \text{ enabled in } M",),
172
+ (),
173
+ f"{AALST_2000}, Section 5", "behaviour", ("reachability",)),
174
+ Definition(
175
+ "live", "Live",
176
+ "Whatever has happened so far, every transition can still fire again later.",
177
+ (r"(N, M_0) \text{ is live} \iff \forall t \in T \; \forall M \in R(N, M_0) \; "
178
+ r"\exists M' \in R(N, M) \colon t \text{ enabled in } M'",),
179
+ ("On a finite reachability graph: $t$ is live iff it can fire inside every "
180
+ "*bottom* strongly connected component (one with no edge leaving it), because "
181
+ "every run ends up trapped in one of those.",),
182
+ f"{AALST_2000}, Definition 2", "behaviour", ("reachability",)),
183
+ Definition(
184
+ "reversible", "Reversible",
185
+ "From every reachable marking the initial marking can be reached again.",
186
+ (r"(N, M_0) \text{ is reversible} \iff \forall M \in R(N, M_0) \colon "
187
+ r"M \xrightarrow{*} M_0",),
188
+ (),
189
+ "course lecture on Petri net properties", "behaviour", ("reachability",)),
190
+
191
+ # -- workflow nets and soundness ---------------------------------------------------
192
+ Definition(
193
+ "wf_net", "WF-net",
194
+ "A workflow net: one start place $i$, one end place $o$, and nothing that is "
195
+ "not on the way from $i$ to $o$.",
196
+ (r"\text{(i)} \; \exists! \, i \in P \colon \bullet i = \emptyset",
197
+ r"\text{(ii)} \; \exists! \, o \in P \colon o \bullet = \emptyset",
198
+ r"\text{(iii)} \; \forall x \in P \cup T \colon x \text{ is on a path from } i "
199
+ r"\text{ to } o"),
200
+ ("A case starts as the marking $[i]$ and should end as $[o]$.",),
201
+ f"{AALST_2000}, Definition 11", "workflow", ("preset",)),
202
+ Definition(
203
+ "short_circuit", "Short-circuited net",
204
+ "The WF-net with one extra transition $t^*$ that takes the token from $o$ back "
205
+ "to $i$, so that finishing a case starts the next one.",
206
+ (r"\overline{N} = (P, \; T \cup \lbrace t^* \rbrace, \; F \cup "
207
+ r"\lbrace (o, t^*), (t^*, i) \rbrace)",),
208
+ ("$N$ is a WF-net exactly when $\\overline{N}$ is strongly connected (every node "
209
+ "can reach every other).",),
210
+ f"{AALST_2000}, Section 5", "workflow", ("wf_net",)),
211
+ Definition(
212
+ "option_to_complete", "(i) Option to complete",
213
+ "From every marking a case can reach, it is still possible to finish.",
214
+ (r"\forall M \colon [i] \xrightarrow{*} M \Rightarrow M \xrightarrow{*} [o]",),
215
+ ("Violated by a deadlock (the case is stuck) or a livelock (the case can only "
216
+ "loop forever).",),
217
+ f"{AALST_2000}, Definition 12 (i)", "workflow", ("reachability", "wf_net")),
218
+ Definition(
219
+ "proper_completion", "(ii) Proper completion",
220
+ "The moment a token reaches $o$, every other place is empty: nothing is left "
221
+ "behind.",
222
+ (r"\forall M \colon [i] \xrightarrow{*} M \land M \geq [o] \Rightarrow M = [o]",),
223
+ (),
224
+ f"{AALST_2000}, Definition 12 (ii)", "workflow", ("reachability", "wf_net")),
225
+ Definition(
226
+ "no_dead_transitions", "(iii) No dead transitions",
227
+ "Every transition can fire in some run of the case.",
228
+ (r"\forall t \in T \; \exists M, M' \colon [i] \xrightarrow{*} M "
229
+ r"\xrightarrow{t} M'",),
230
+ (),
231
+ f"{AALST_2000}, Definition 12 (iii)", "workflow",
232
+ ("reachability", "dead_transition")),
233
+ Definition(
234
+ "sound", "Sound",
235
+ "A WF-net is sound when every case can always finish, finishes cleanly, and "
236
+ "every transition is useful.",
237
+ (r"N \text{ is sound} \iff \text{(i) option to complete} \land "
238
+ r"\text{(ii) proper completion} \land \text{(iii) no dead transitions}",),
239
+ ("Checked on the reachability graph from $[i]$. A sound WF-net is always "
240
+ "bounded, so an unbounded net is unsound straight away.",),
241
+ f"{AALST_2000}, Definition 12", "workflow",
242
+ ("option_to_complete", "proper_completion", "no_dead_transitions")),
243
+ Definition(
244
+ "soundness_theorem", "Soundness theorem",
245
+ "Soundness is the same as liveness plus boundedness of the short-circuited net.",
246
+ (r"N \text{ is sound} \iff (\overline{N}, [i]) \text{ is live and bounded}",),
247
+ ("Why: $t^*$ can only fire when a case has finished, so *live* includes "
248
+ "\"every case can finish\" (i) and \"no transition is dead\" (iii). If a case "
249
+ "could finish with tokens left behind, $t^*$ would start the next case on top "
250
+ "of them and tokens would pile up — so *bounded* rules out improper "
251
+ "completion (ii).",),
252
+ f"{AALST_2000}, Theorem 1", "workflow",
253
+ ("sound", "short_circuit", "live", "bounded")),
254
+
255
+ # -- structure ---------------------------------------------------------------------
256
+ Definition(
257
+ "free_choice", "Free-choice",
258
+ "Transitions that share an input place have exactly the same input places, so "
259
+ "every choice is free: it never depends on what happened in a parallel branch.",
260
+ (r"\forall t_1, t_2 \in T \colon \bullet t_1 \cap \bullet t_2 \neq \emptyset "
261
+ r"\Rightarrow \bullet t_1 = \bullet t_2",),
262
+ ("Soundness of a free-choice WF-net can be decided in polynomial time, and a "
263
+ "sound free-choice WF-net is safe.",),
264
+ f"{AALST_2000}, Definition 7, Corollary 1, Lemma 1", "structure", ("preset",)),
265
+ Definition(
266
+ "elementary_path", "Elementary path",
267
+ "A path along the arcs that visits no node twice.",
268
+ (r"C = \langle n_1, \ldots, n_k \rangle \text{ with } (n_j, n_{j+1}) \in F "
269
+ r"\text{ for } 1 \leq j < k",
270
+ r"C \text{ is elementary} \iff \forall j, l \colon j \neq l \Rightarrow "
271
+ r"n_j \neq n_l",
272
+ r"\alpha(C) = \lbrace n_1, \ldots, n_k \rbrace"),
273
+ (),
274
+ f"{AALST_2000}, Definition 5", "structure", ("petri_net",)),
275
+ Definition(
276
+ "well_handled", "Well-handled",
277
+ "No place and transition are joined by two separate routes. Such a pair is a "
278
+ "*handle*: a PT-handle is a choice that is later synchronised, a TP-handle is "
279
+ "parallel branches that are later merged as alternatives.",
280
+ (r"\forall x, y \text{ (one a place, the other a transition)} \; "
281
+ r"\forall \text{ elementary paths } C_1, C_2 \text{ from } x \text{ to } y "
282
+ r"\colon",
283
+ r"\alpha(C_1) \cap \alpha(C_2) = \lbrace x, y \rbrace \Rightarrow C_1 = C_2"),
284
+ ("The app finds handles as two internally disjoint paths from $x$ to $y$ "
285
+ "(Menger's theorem: a max-flow problem with capacity 1 on every node).",),
286
+ f"{AALST_2000}, Definition 13", "structure", ("elementary_path",)),
287
+ Definition(
288
+ "well_structured", "Well-structured",
289
+ "Every AND-split is closed by an AND-join and every OR-split by an OR-join, "
290
+ "also around the loop through $t^*$.",
291
+ (r"N \text{ is well-structured} \iff \overline{N} \text{ is well-handled}",),
292
+ ("Soundness of a well-structured WF-net can be decided in polynomial time, and a "
293
+ "sound well-structured WF-net is safe.",),
294
+ f"{AALST_2000}, Definition 14, Corollary 2, Lemma 3", "structure",
295
+ ("well_handled", "short_circuit")),
296
+ Definition(
297
+ "state_machine", "State machine",
298
+ "Every transition has exactly one input and one output place, so a single "
299
+ "token moves around.",
300
+ (r"\forall t \in T \colon |\bullet t| = |t \bullet| = 1",),
301
+ (),
302
+ f"{AALST_2000}, Definition 8", "structure", ("preset",)),
303
+ Definition(
304
+ "s_component", "S-component",
305
+ "A part of the net that behaves like one token moving around: a strongly "
306
+ "connected state machine that keeps every arc of its places.",
307
+ (r"N_s = (P_s, T_s, F_s) \text{ with } P_s \subseteq P, \; T_s \subseteq T, \; "
308
+ r"F_s \subseteq F",
309
+ r"N_s \text{ is strongly connected and a state machine}",
310
+ r"\forall q \in P_s \; \forall t \in T \colon ((q, t) \in F \Rightarrow "
311
+ r"(q, t) \in F_s) \land ((t, q) \in F \Rightarrow (t, q) \in F_s)"),
312
+ (),
313
+ f"{AALST_2000}, Definition 9", "structure", ("state_machine",)),
314
+ Definition(
315
+ "s_coverable", "S-coverable",
316
+ "Every node lies in some S-component of the short-circuited net: the net is "
317
+ "a set of threads (one \"document\" each) that synchronise on shared tasks.",
318
+ (r"N \text{ is S-coverable} \iff \forall x \in P \cup T \cup \lbrace t^* "
319
+ r"\rbrace \; \exists \text{ S-component } N_s \text{ of } \overline{N} \colon "
320
+ r"x \in N_s",),
321
+ ("Sound free-choice and sound well-structured WF-nets are S-coverable, and an "
322
+ "S-coverable WF-net is safe. Unsound nets are often not S-coverable, so a "
323
+ "node outside every S-component deserves a close look.",),
324
+ f"{AALST_2000}, Definitions 10 and 16, Corollaries 3 and 4", "structure",
325
+ ("s_component", "short_circuit")),
326
+ Definition(
327
+ "start_end_rule", "Start and end rule",
328
+ "A quick necessary condition for soundness: a transition that takes from $i$ "
329
+ "takes only from $i$, and one that puts into $o$ puts only into $o$.",
330
+ (r"N \text{ is sound} \Rightarrow \forall t \in T \colon (i \in \bullet t "
331
+ r"\Rightarrow \bullet t = \lbrace i \rbrace) \land (o \in t \bullet "
332
+ r"\Rightarrow t \bullet = \lbrace o \rbrace)",),
333
+ ("Otherwise $t$ needs $i$ (or $o$) marked together with another place, which "
334
+ "never happens in a sound net, so $t$ is dead.",),
335
+ f"{AALST_2000}, Lemma 4", "structure", ("sound",)),
336
+
337
+ # -- invariants --------------------------------------------------------------------
338
+ Definition(
339
+ "incidence_matrix", "Incidence matrix",
340
+ "What firing each transition does to each place: the tokens it puts in minus "
341
+ "the tokens it takes out.",
342
+ (r"C(p, t) = W(t, p) - W(p, t) \quad \text{for } p \in P, \; t \in T",
343
+ r"M \xrightarrow{\sigma} M' \Rightarrow M' = M + C \cdot \overline{\sigma}"),
344
+ ("$W(x, y)$ is the weight of the arc from $x$ to $y$, and $0$ if there is none. "
345
+ r"$\overline{\sigma}$, the *Parikh vector* of $\sigma$, counts how often each "
346
+ r"transition occurs in $\sigma$. This *marking equation* is only a necessary "
347
+ "condition: it ignores the order of the firings.",),
348
+ f"{MURATA_1989}, Section VII", "invariants", ("firing",)),
349
+ Definition(
350
+ "p_invariant", "P-invariant",
351
+ "A weighting of the places whose weighted token count never changes, "
352
+ "whatever fires: a conservation law of the net.",
353
+ (r"y \colon P \to \mathbb{N}, \quad y \neq 0, \quad y \cdot C = 0",
354
+ r"M_0 \xrightarrow{*} M \Rightarrow y \cdot M = y \cdot M_0"),
355
+ ("The app lists the *minimal* ones (no other uses a strict subset of their "
356
+ "places); every other invariant with non-negative weights is a sum of "
357
+ "multiples of these.",
358
+ "*Covered by P-invariants* (every place has a positive weight in some "
359
+ "P-invariant) implies that the net is bounded from every initial marking. In "
360
+ "a WF-net, $i + p + o = 1$ says: one token travels through these places."),
361
+ f"{MURATA_1989}, Section VII-A", "invariants", ("incidence_matrix", "bounded")),
362
+ Definition(
363
+ "t_invariant", "T-invariant",
364
+ "How often to fire each transition to end up in the marking you started from: "
365
+ "a cycle of the behaviour.",
366
+ (r"x \colon T \to \mathbb{N}, \quad x \neq 0, \quad C \cdot x = 0",
367
+ r"M \xrightarrow{\sigma} M' \land \overline{\sigma} = x \Rightarrow M' = M"),
368
+ ("A net that is live and bounded is *covered by T-invariants*: every transition "
369
+ "occurs in one. By the soundness theorem, a sound WF-net's short-circuited net "
370
+ r"$\overline{N}$ is live and bounded, so a transition in no T-invariant of "
371
+ r"$\overline{N}$ proves that the WF-net is not sound. (Covered does not imply "
372
+ "sound.)",),
373
+ f"{MURATA_1989}, Section VII-A", "invariants",
374
+ ("incidence_matrix", "live", "short_circuit", "soundness_theorem")),
375
+
376
+ # -- footprint ---------------------------------------------------------------------
377
+ Definition(
378
+ "footprint", "Footprint",
379
+ "The ordering relations between activities: which can directly follow which.",
380
+ (r"a >_L b \iff \exists \sigma = \langle t_1, \ldots, t_n \rangle \in L \; "
381
+ r"\exists j \colon t_j = a \land t_{j+1} = b",
382
+ r"a \rightarrow_L b \iff a >_L b \land \neg (b >_L a)",
383
+ r"a \leftarrow_L b \iff b \rightarrow_L a",
384
+ r"a \parallel_L b \iff a >_L b \land b >_L a",
385
+ r"a \#_L b \iff \neg (a >_L b) \land \neg (b >_L a)"),
386
+ ("For a net, $L$ is the set of its complete firing sequences (visible labels "
387
+ "only). Comparing a log's footprint with a model's is a simple conformance "
388
+ "check.",),
389
+ f"{AALST_2016}, Section 6.2", "footprint"),
390
+
391
+ # -- transition systems and regions ------------------------------------------------
392
+ Definition(
393
+ "transition_system", "Transition system",
394
+ "States, and arrows between them labelled with events. The simplest model of a "
395
+ "process: it has no concurrency, so two events in either order make a diamond.",
396
+ (r"TS = (S, E, T, s_{in})",
397
+ r"T \subseteq S \times E \times S, \quad s_{in} \in S"),
398
+ ("From an event log, the *state function* decides the state an event happens in: "
399
+ "it looks at the events before it (the prefix), after it (the postfix) or both, "
400
+ "keeps the last $k$ of them (the horizon) or all, and forgets their order (a "
401
+ "multiset) or also their frequency (a set). Every trace then walks from state to "
402
+ "state, one event at a time: with the prefix, $s_k = "
403
+ "\\text{rep}(\\text{last}_h \\langle e_1, \\ldots, e_k \\rangle)$ and "
404
+ "$(s_{k-1}, e_k, s_k) \\in T$.",
405
+ "A coarser abstraction (a set, a short horizon) merges states and so generalises; "
406
+ "the full sequence gives a tree that allows exactly the log."),
407
+ f"{AALST_2016}, Section 7.4.1", "regions"),
408
+ Definition(
409
+ "region", "Region",
410
+ "A set of states that every event treats the same way each time: all its arrows "
411
+ "enter the set, all exit it, or none crosses it.",
412
+ (r"R \subseteq S \text{ is a region} \iff \forall e \in E \colon "
413
+ r"\text{enter}(e, R) \lor \text{exit}(e, R) \lor \text{nocross}(e, R)",
414
+ r"\text{enter}(e, R) \iff \forall (s, e, s') \in T \colon s \notin R \land s' \in R",
415
+ r"\text{exit}(e, R) \iff \forall (s, e, s') \in T \colon s \in R \land s' \notin R",
416
+ r"\text{nocross}(e, R) \iff \forall (s, e, s') \in T \colon "
417
+ r"(s \in R \Leftrightarrow s' \in R)"),
418
+ ("$\\emptyset$ and $S$ are the *trivial* regions. The complement $S \\setminus R$ of "
419
+ "a region is a region too, with enter and exit swapped.",
420
+ "A region is a place in disguise: it is marked exactly in its states, an event "
421
+ "that enters it puts a token in, one that exits it takes the token out."),
422
+ f"{CORTADELLA_1998}; {AALST_2016}, Section 7.4.2", "regions", ("transition_system",)),
423
+ Definition(
424
+ "minimal_region", "Minimal region",
425
+ "A non-empty region with no smaller non-empty region inside it. The synthesised "
426
+ "net has one place per minimal region.",
427
+ (r"R \text{ is minimal} \iff R \neq \emptyset \land \neg \exists \text{ region } "
428
+ r"R' \colon \emptyset \neq R' \subsetneq R",),
429
+ (),
430
+ CORTADELLA_1998, "regions", ("region",)),
431
+ Definition(
432
+ "pre_region", "Pre-region and post-region",
433
+ "The regions an event leaves (its input places) and the regions it enters (its "
434
+ "output places).",
435
+ (r"R \in \text{pre}(e) \iff \text{exit}(e, R)",
436
+ r"R \in \text{post}(e) \iff \text{enter}(e, R)"),
437
+ ("Exam questions often ask for the *minimal* pre-regions: the minimal regions that "
438
+ "are pre-regions, i.e. the input places of $e$ in the synthesised net.",),
439
+ CORTADELLA_1998, "regions", ("region",)),
440
+ Definition(
441
+ "ger", "Generalised excitation region",
442
+ "The states in which an event is enabled.",
443
+ (r"\text{GER}(e) = \lbrace s \in S \mid \exists s' \colon (s, e, s') \in T \rbrace",),
444
+ ("Every pre-region of $e$ contains $\\text{GER}(e)$: $e$ exits it, so it starts "
445
+ "inside.",),
446
+ CORTADELLA_1998, "regions", ("transition_system",)),
447
+ Definition(
448
+ "state_separation", "State separation",
449
+ "Any two states are told apart by some region: in the net they will be different "
450
+ "markings.",
451
+ (r"\forall s_1, s_2 \in S \colon s_1 \neq s_2 \Rightarrow \exists \text{ region } "
452
+ r"R \colon s_1 \in R \land s_2 \notin R",),
453
+ ("Since the complement of a region is a region, it does not matter which of the two "
454
+ "is inside. Two states with the same event to the same state, as in "
455
+ "$s_1 \\xrightarrow{e} s$ and $s_2 \\xrightarrow{e} s$, can never be separated: a "
456
+ "region with $s_1$ but not $s_2$ would have one $e$-arrow cross it and the other "
457
+ "not.",),
458
+ CORTADELLA_1998, "regions", ("region",)),
459
+ Definition(
460
+ "forward_closure", "Forward closure",
461
+ "An event's input places are all marked only where the event really is enabled.",
462
+ (r"\forall e \in E \colon \bigcap_{R \in \text{pre}(e)} R = \text{GER}(e)",),
463
+ ("Also called *event/state separation*. When it fails, the net would enable $e$ in "
464
+ "a state where the transition system does not. With no pre-region at all, the "
465
+ "intersection is all of $S$.",),
466
+ CORTADELLA_1998, "regions", ("pre_region", "ger")),
467
+ Definition(
468
+ "elementary_ts", "Elementary transition system",
469
+ "A transition system that a Petri net can mimic exactly, with one place per "
470
+ "region.",
471
+ (r"TS \text{ is elementary} \iff \text{state separation} \land "
472
+ r"\text{forward closure}",),
473
+ ("A transition system that is not elementary can be made so by *label splitting*: "
474
+ "renaming some occurrences of an event (e.g. $a$ into $a_1$ and $a_2$), which the "
475
+ "net then shows as two transitions with the same label.",),
476
+ CORTADELLA_1998, "regions", ("state_separation", "forward_closure")),
477
+ Definition(
478
+ "region_synthesis", "Synthesis from regions",
479
+ "The Petri net of a transition system: a place per minimal region, the events as "
480
+ "transitions, and arcs from pre-regions and to post-regions.",
481
+ (r"P = \lbrace p_R \mid R \text{ is a minimal region} \rbrace, \quad T = E",
482
+ r"F = \lbrace (p_R, e) \mid R \in \text{pre}(e) \rbrace \cup "
483
+ r"\lbrace (e, p_R) \mid R \in \text{post}(e) \rbrace",
484
+ r"M_0 = [\, p_R \mid s_{in} \in R \,]",
485
+ r"TS \text{ elementary} \Rightarrow RG(N, M_0) \cong TS"),
486
+ ("$\\cong$: the reachability graph is the transition system with its states "
487
+ "renamed (isomorphic). For a transition system that is not elementary the net can "
488
+ "allow more.",),
489
+ f"{CORTADELLA_1998}; {AALST_2016}, Section 7.4.2", "regions",
490
+ ("minimal_region", "pre_region", "elementary_ts")),
491
+ )
492
+
493
+ BY_KEY = {definition.key: definition for definition in DEFINITIONS}
494
+
495
+ #: Property names as the analysis tabs show them -> definition key.
496
+ FOR_TITLE = {
497
+ "WF-net": "wf_net", "WF-net structure": "wf_net",
498
+ "Sound": "sound", "Not sound": "sound", "Undecided": "sound",
499
+ "(i) Option to complete": "option_to_complete", "Option to complete": "option_to_complete",
500
+ "(ii) Proper completion": "proper_completion", "Proper completion": "proper_completion",
501
+ "(iii) No dead transitions": "no_dead_transitions",
502
+ "No dead transitions": "dead_transition",
503
+ "Bounded": "bounded", "Safe": "safe", "Deadlock-free": "deadlock_free",
504
+ "Live": "live", "Reversible": "reversible",
505
+ "Live and bounded ⇒ sound": "soundness_theorem",
506
+ "Unbounded ⇒ not sound": "soundness_theorem",
507
+ "Not live ⇒ not sound": "soundness_theorem",
508
+ "Free-choice": "free_choice", "Well-structured": "well_structured",
509
+ "S-coverable": "s_coverable", "State machine": "state_machine",
510
+ "Covered by P-invariants": "p_invariant", "Covered by T-invariants": "t_invariant",
511
+ "Incidence matrix": "incidence_matrix",
512
+ "Transition system": "transition_system", "Region": "region", "Not a region": "region",
513
+ "Minimal regions": "minimal_region", "State separation": "state_separation",
514
+ "Forward closure": "forward_closure", "Elementary": "elementary_ts",
515
+ "Not elementary": "elementary_ts", "Reachability graph ≅ transition system":
516
+ "region_synthesis", "Reachability graph ≇ transition system": "region_synthesis",
517
+ }
518
+
519
+
520
+ def lookup(key_or_title: str | None) -> Definition | None:
521
+ """The definition with this key, or for this displayed property name."""
522
+ if not key_or_title:
523
+ return None
524
+ return BY_KEY.get(key_or_title) or BY_KEY.get(FOR_TITLE.get(key_or_title, ""))
525
+
526
+
527
+ # ---------------------------------------------------------------------------
528
+ # docs/definitions.md
529
+ # ---------------------------------------------------------------------------
530
+ def markdown() -> str:
531
+ """The reference page, with ``$$`` display maths as GitHub renders it."""
532
+ lines = [
533
+ "<!-- Generated by `python -m openprocess.mining.definitions > docs/definitions.md`.",
534
+ " Edit openprocess/mining/definitions.py, not this file. -->",
535
+ "",
536
+ "# Definitions",
537
+ "",
538
+ "Every property the analyses in OpenProcess report, defined precisely. In the app, "
539
+ "hover over a property in an **Analysis** tab to see its definition, or click "
540
+ "it to keep the definition open.",
541
+ "",
542
+ "Throughout, $N = (P, T, F)$ is a Petri net and, for WF-nets, $i$ and $o$ are "
543
+ "its start and end places.",
544
+ "",
545
+ ]
546
+ for section, title, _ in SECTIONS:
547
+ lines.append(f"- [{title}](#{_anchor(title)})")
548
+ lines.append("")
549
+ for section, title, intro in SECTIONS:
550
+ lines += [f"## {title}", "", intro, ""]
551
+ for definition in DEFINITIONS:
552
+ if definition.section != section:
553
+ continue
554
+ lines += [f"### {definition.name}", "", definition.summary, ""]
555
+ for formula in definition.formulas:
556
+ lines += ["$$", formula, "$$", ""]
557
+ for note in definition.notes:
558
+ lines += [note, ""]
559
+ if definition.uses:
560
+ links = ", ".join(f"[{BY_KEY[k].name}](#{_anchor(BY_KEY[k].name)})"
561
+ for k in definition.uses)
562
+ lines += [f"Builds on: {links}.", ""]
563
+ if definition.source:
564
+ lines += [f"*Source: {definition.source.replace('*', '')}.*", ""]
565
+ lines += ["## Sources", "",
566
+ f"- {AALST_2000}.", f"- {AALST_2016}.", f"- {CORTADELLA_1998}.", ""]
567
+ return "\n".join(lines)
568
+
569
+
570
+ def _anchor(title: str) -> str:
571
+ """GitHub's heading anchor: lower case, spaces to dashes, punctuation dropped."""
572
+ keep = []
573
+ for char in title.lower():
574
+ if char.isalnum() or char in "-_":
575
+ keep.append(char)
576
+ elif char == " ":
577
+ keep.append("-")
578
+ return "".join(keep)
579
+
580
+
581
+ if __name__ == "__main__":
582
+ import sys
583
+ sys.stdout.reconfigure(encoding="utf-8")
584
+ sys.stdout.write(markdown())