ReForma 0.1.2__tar.gz → 0.1.4__tar.gz

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.
@@ -0,0 +1,2 @@
1
+ include reforma/bin/*.jar
2
+ include reforma/bin/js/*.js
reforma-0.1.4/PKG-INFO ADDED
@@ -0,0 +1,390 @@
1
+ Metadata-Version: 2.4
2
+ Name: ReForma
3
+ Version: 0.1.4
4
+ Summary: Python bindings for the RePA/ReForma probabilistic automaton tool
5
+ Author-email: Joshua Dourado <joshuadourado@ua.pt>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Topic :: Scientific/Engineering
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: networkx
13
+ Requires-Dist: matplotlib
14
+
15
+
16
+ # ReForma — Reconfigurable Formal Automata in Python
17
+
18
+ **ReForma** is a powerful Python library that bridges the gap between Formal Methods (Model Checking, MDPs) and Data Science. It wraps the RePA/ReForma Java backend, providing a clean, Pythonic interface for simulating, training, visualizing, and verifying Reconfigurable Formal Automata.
19
+
20
+ With ReForma, you can define probabilistic systems where **rules dynamically change the transition weights** during execution, train these systems with real-world event logs, and verify complex properties using PDL/PCTL.
21
+
22
+ ## Acknowledgements
23
+
24
+ This project relies on and interacts with several excellent open-source projects and academic tools. We would like to thank their creators and maintainers:
25
+
26
+ **Graph Rendering & Visualization:**
27
+ * [Cytoscape.js](https://js.cytoscape.org/) (MIT License) - Used for interactive graph rendering.
28
+ * [dagre](https://github.com/dagrejs/dagre) & [cytoscape-dagre](https://github.com/cytoscape/cytoscape.js-dagre) (MIT License) - Used for directed graph layout.
29
+ * [Mermaid.js](https://mermaid.js.org/) - Used as an export format for LTS diagrams.
30
+
31
+ **Python Dependencies:**
32
+ * [NetworkX](https://networkx.org/) (BSD License) - Used for internal graph processing and layout calculation.
33
+ * [Matplotlib](https://matplotlib.org/) (Matplotlib License) - Used for offline high-resolution graph exports.
34
+
35
+ **Formal Verification Ecosystem:**
36
+ * [PRISM Model Checker](https://www.prismmodelchecker.org/) - The ReForma DSL heavily supports exporting DTMC models for verification in PRISM.
37
+
38
+ ---
39
+
40
+ ## Features
41
+
42
+ * **Interactive Visualizations:** Render drag-and-drop graphs (Base Model or Full LTS) directly inside Jupyter Notebooks.
43
+ * **Model Manipulation:** Merge models (union/intersection) and prune low-probability paths (`delta_cut`).
44
+ * **Advanced Analysis:** Find the most/least probable paths to states or variable conditions.
45
+ * **Formal Verification:** Evaluate PCTL and PDL formulas (e.g., *What is the probability of eventually reaching a Deadlock?*).
46
+ * **Training from Logs:** Automatically update transition weights by feeding real user sessions/traces.
47
+ * **Exports:** Export your models to PRISM, mCRL2, GLTS, or Mermaid.js.
48
+
49
+ ---
50
+
51
+ ## Installation & Requirements
52
+
53
+ **Requirements:**
54
+ 1. **Python 3.10+**
55
+ 2. **Java (JRE or JDK)**: ReForma relies on a high-performance Scala/Java backend. You *must* have `java` accessible in your system's `PATH`.
56
+
57
+ **Installation:**
58
+ ```bash
59
+ pip install reforma
60
+ ```
61
+
62
+ For **visualization features** (offline PNGs and interactive Jupyter graphs), install the required extras:
63
+ ```bash
64
+ pip install networkx matplotlib
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Quick Start
70
+
71
+ ```python
72
+ from reforma import ReForma
73
+
74
+ modelo = ReForma()
75
+
76
+ # 1. Load a model
77
+ modelo.load_file("recommender.r")
78
+
79
+ # 2. Get a beautiful printout of the current state and probabilities
80
+ print(modelo.state.summary())
81
+
82
+ # 3. Simulate steps
83
+ modelo.step("go_work")
84
+ modelo.step("easy_task")
85
+
86
+ # 4. Find the most probable path to a specific state
87
+ path = modelo.find_best_path(target_type="state", target_value="Home", criterion="max")
88
+ print(path)
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Visualizations (Jupyter & Offline)
94
+
95
+ ReForma provides powerful graphing tools directly integrated into your workflow. Active rules are rendered as solid lines, while disabled elements are rendered as dashed/transparent lines.
96
+
97
+ ```python
98
+ # 1. Interactive Jupyter View (Base Model)
99
+ # Renders a drag-and-drop Cytoscape.js graph right inside your Notebook!
100
+ modelo.show_interactive()
101
+
102
+ # 2. Interactive Jupyter View (Full LTS)
103
+ # Renders the full Labelled Transition System tree (all reachable states)
104
+ modelo.show_all_steps_interactive()
105
+
106
+ # 3. Offline Static Images
107
+ # Renders a high-res graph using Matplotlib/NetworkX (no browser needed)
108
+ modelo.save_image_plt("output/my_graph.png")
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Model Manipulation & Analysis
114
+
115
+ ReForma isn't just for reading models; you can actively manipulate and analyze them:
116
+
117
+ ```python
118
+ # --- Delta Cut (Pruning) ---
119
+ # Prunes all transitions and rules with a probability below 0.15
120
+ modelo.delta_cut(delta=0.15)
121
+
122
+ # --- Merge Models ---
123
+ # Merges the current model with another one, resolving conflicting weights
124
+ # by taking the maximum value ("max"), or average ("arith").
125
+ modelo.merge_models(other_model_source, op_type="union", agg="max")
126
+
127
+ # --- Stats & Sanity Checks ---
128
+ print(modelo.get_stats()) # Counts total reachable states and transitions
129
+ print(modelo.check_problems()) # Hunts for deadlocks, unreachability, and rule inconsistencies
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Training with Event Logs
135
+
136
+ Train the model on a batch of sessions (lists of event labels) to automatically update the transition weights. Useful for Process Mining.
137
+
138
+ ```python
139
+ # Train directly from a Python list
140
+ modelo.train([
141
+ ["go_work", "easy_task", "easy_task", "go_home"],
142
+ ["battery_low", "go_charge", "finish_charge", "socialize"],
143
+ ])
144
+
145
+ # Or train from a log file (one session per line, comma-separated)
146
+ modelo.train_from_file("logs/sessions.txt")
147
+
148
+ # Save the updated model with the new calculated weights
149
+ modelo.save_source("model_trained.r")
150
+ ```
151
+
152
+ ---
153
+
154
+ ## PDL / PCTL Verification
155
+
156
+ Evaluate probabilistic and dynamic logic formulas natively.
157
+
158
+ ```python
159
+ # Quantitative: Probability of eventually reaching the Office
160
+ prob = modelo.check_pdl_value("Home", "{P=?[F Office]}")
161
+ print(f"P(reach Office from Home) = {prob:.4f}")
162
+
163
+ # Qualitative: Is it probable? (Returns True/False)
164
+ holds = modelo.check_pdl_value("Home", "{P>=0.4[F Office]}")
165
+
166
+ # PDL: Is there a path via go_work to Office?
167
+ holds = modelo.check_pdl_value("Home", "<go_work>Office")
168
+ ```
169
+
170
+ ### Formula Syntax Reference
171
+
172
+ | Formula | Meaning |
173
+ |-----------------------------|------------------------------------------------|
174
+ | `{P=?[F target]}` | Probability of eventually reaching `target` |
175
+ | `{P=?[G safe]}` | Probability of staying in `safe` forever |
176
+ | `{P=?[X next]}` | Probability of reaching `next` in exactly 1 step|
177
+ | `{P=?[a U b]}` | Probability of `a` holding until `b` occurs |
178
+ | `{P>=0.5[F target]}` | Is the probability of reaching target ≥ 0.5? |
179
+ | `<action>state` | There exists a path via `action` to `state` |
180
+ | `[action]state` | All paths via `action` lead to `state` |
181
+
182
+ ---
183
+
184
+ ## Full API Reference
185
+
186
+ You can access the full API reference at any time in your Python console by running:
187
+
188
+ ```python
189
+ from reforma import ReForma
190
+ modelo = ReForma()
191
+ modelo.help()
192
+ ```
193
+
194
+ ### Main Methods:
195
+ * **Loading**: `load(source, name)`, `load_file(path)`, `reset()`
196
+ * **Simulation**: `step(label)`, `undo()`
197
+ * **Visualizations**: `show_interactive()`, `show_all_steps_interactive()`, `save_image_plt(path)`, `get_all_steps()`
198
+ * **Analysis**: `check_problems()`, `get_stats()`, `find_best_path(...)`
199
+ * **Manipulation**: `train(sessions)`, `train_from_file(path)`, `delta_cut(delta)`, `merge_models(...)`
200
+ * **Verification**: `check_pdl(state, form)`, `check_pdl_value(...)`
201
+ * **Exports**: `export_prism()`, `export_glts()`, `export_mcrl2()`, `save_source(path)`
202
+
203
+
204
+
205
+
206
+ # Re_lang — Reconfigurable Language Guide
207
+
208
+ **Re_lang** is the Domain-Specific Language (DSL) designed to define models for the ReForma library.
209
+ Its main innovation lies in its ability to define **Reconfigurable Probabilistic Automata**, where transitions are not static: executing an action can dynamically enable, disable, or alter the probability of other actions in the future.
210
+
211
+ ---
212
+
213
+ ## 1. Basic Structure and Global Definitions
214
+
215
+ Every model starts with a name, variables (optional), and the definition of the initial state. Optionally, you can configure the mathematical mode for weight distribution.
216
+
217
+ ```text
218
+ name MyModel
219
+
220
+ // (Optional) Defines how residual weights are redistributed after a rule modifies a probability.
221
+ // Options: normalize (default), equal, proportional
222
+ calibration proportional
223
+
224
+ // (Optional) Ignores hyper-rules math and calculates empirical frequencies instead
225
+ // training
226
+
227
+ // Integer variables declaration (Optional)
228
+ int counter = 0
229
+ int flag = 1
230
+
231
+ // Initial State (Required)
232
+ init s0
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 2. Base Transitions (Simple Actions)
238
+
239
+ Base transitions define the static behavioral graph of the system. You can define them using a shorthand syntax or a full syntax if you need to separate the transition's unique ID from its label.
240
+
241
+ **Shorthand Syntax:** `Source ---> Target: label (probability) [aggregation] [disabled]`
242
+ **Full Syntax (with ID):** `Source -act-> Target: label (probability) [aggregation] [disabled]`
243
+
244
+ ```text
245
+ // Shorthand: Transition ID and Label are both 'work'
246
+ s0 ---> s1: work (0.8)
247
+
248
+ // Full Syntax: Explicitly separating the act from the Label
249
+ a -b-> c: d (0.5)
250
+
251
+ // In the example above:
252
+ // 'a' = Source state
253
+ // 'b' = act
254
+ // 'c' = Target state
255
+ // 'd' = Label (Used by hyper-edges/dynamic rules to buff or debuff this action)
256
+
257
+ // Transition with implicit probability (assumes 1.0 or divides evenly among available options)
258
+ s1 ---> s2: rest
259
+
260
+ // Transition inactive by default (will need a dynamic rule to enable it later)
261
+ s2 ---> s3: emergency disabled
262
+ ```
263
+ *Why use full syntax?* It is extremely useful when you have multiple paths between the same (or different) states that should respond to the exact same dynamic rule (sharing the same `label`), but you need to uniquely identify each path (using the act).
264
+
265
+ ---
266
+
267
+ ---
268
+
269
+ ## 3. Hyper-Edges (Dynamic Rules)
270
+
271
+ The core of Re_lang. Rules define how the occurrence of an event alters the structure of the model itself. A hyper-edge links a **trigger label** to a **target label**.
272
+
273
+ **Syntax (Enable / Buff):** `Trigger ->> Target: RuleName (Strength)`
274
+ **Syntax (Disable / Debuff):** `Trigger --! Target: RuleName (Strength)`
275
+
276
+ ```text
277
+ // When 'battery_low' occurs, it enables and buffs the probability of 'go_charge' (strength 0.6)
278
+ battery_low ->> go_charge: chargeRule (0.6)
279
+
280
+ // When 'battery_low' occurs, it disables/debuffs the probability of 'go_work'
281
+ battery_low --! go_work: fatigueRule (0.4)
282
+ ```
283
+
284
+
285
+ ---
286
+
287
+ ## 4. Aggregations (Rule Mathematics)
288
+
289
+ When a rule acts upon a transition, the final probability is calculated using an aggregation function that combines 3 values: the original weight of the target, the strength of the rule, and the weight of the trigger.
290
+
291
+ By default, it uses the arithmetic mean (`arith`), but you can specify others:
292
+ * `arith` : Arithmetic mean (Default)
293
+ * `max` : Chooses the maximum value.
294
+ * `min` : Chooses the minimum value.
295
+ * `prod` : Product of probabilities.
296
+ * `geom` : Geometric mean.
297
+
298
+ **Example:**
299
+ ```text
300
+ // Uses 'max' to ensure that if the rule is very strong, it overrides the base probability.
301
+ stress ->> slack_off: ruleStress (0.9) max
302
+ ```
303
+
304
+ ---
305
+
306
+ ## 5. Guards and Updates
307
+
308
+ Any transition (simple or rule) can have conditions to occur and can alter global variables.
309
+
310
+ **Supported Operators:** `==`, `!=`, `<=`, `>=`, `<`, `>`, `AND`, `OR`.
311
+
312
+ ```text
313
+ int tasks = 0
314
+
315
+ // Transition with Guard and Update
316
+ office ---> home: go_home if (tasks >= 5 AND stress_level > 2) then {
317
+ tasks' := 0
318
+ stress_level' := stress_level - 1
319
+ }
320
+
321
+ // A dynamic rule can also be conditionally fired
322
+ finish_task ->> rest: reward if (tasks == 10)
323
+ ```
324
+ *(Note: The variable being modified must have a prime `'` before the assignment operator `:=`, e.g., `tasks'`)*
325
+
326
+ ---
327
+
328
+ ## 6. Modules (Sub-Automata)
329
+
330
+ For larger models, you can encapsulate logic inside `aut` (module) blocks, creating namespaces. This prevents state name collisions in complex systems.
331
+
332
+ ```text
333
+ name SecuritySystem
334
+
335
+ aut Sensor {
336
+ init idle
337
+ idle ---> active: detect_motion
338
+ }
339
+
340
+ aut Alarm {
341
+ init off
342
+ off ---> on: sound_alarm disabled
343
+ }
344
+
345
+ // Inter-modular rule: Motion in the Sensor enables the Alarm
346
+ Sensor.detect_motion ->> Alarm.sound_alarm: trigger_alert
347
+ ```
348
+
349
+ ---
350
+
351
+ ## 7. Full Example: The Modern Worker
352
+
353
+ A model that brings all the concepts together:
354
+
355
+ ```text
356
+ name AdvancedBot
357
+ calibration proportional
358
+
359
+ int energy = 10
360
+ int tasks_done = 0
361
+
362
+ init Home
363
+
364
+ // --- Base Behavior ---
365
+ Home ---> Office: go_work (0.5)
366
+ Home ---> Station: go_charge (0.5)
367
+
368
+ Office ---> Office: easy_task (0.7) if (energy > 0) then {
369
+ tasks_done' := tasks_done + 1
370
+ energy' := energy - 1
371
+ }
372
+ Office ---> Home: go_home (0.3)
373
+
374
+ // Maintenance states (Only available at Home)
375
+ Home ---> Home: battery_low
376
+ Station ---> Home: finish_charge (1.0) then {
377
+ energy' := 10
378
+ }
379
+
380
+ // --- Dynamic Rules (Adaptation) ---
381
+
382
+ // If battery is low, force going to the station and block going to work
383
+ battery_low ->> go_charge: buff_charge (0.9) max
384
+ battery_low --! go_work: block_work (0.8)
385
+
386
+ // Upon finishing the charge, reset/enable going back to work
387
+ finish_charge ->> go_work: reset_work (0.5)
388
+ ```
389
+ ```
390
+