ReForma 0.1.0__tar.gz → 0.1.2__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.
- {reforma-0.1.0 → reforma-0.1.2}/PKG-INFO +66 -75
- {reforma-0.1.0 → reforma-0.1.2}/README.md +65 -74
- {reforma-0.1.0 → reforma-0.1.2}/ReForma.egg-info/PKG-INFO +66 -75
- {reforma-0.1.0 → reforma-0.1.2}/ReForma.egg-info/SOURCES.txt +6 -1
- reforma-0.1.2/ReForma.egg-info/top_level.txt +1 -0
- {reforma-0.1.0 → reforma-0.1.2}/pyproject.toml +4 -5
- reforma-0.1.2/reforma/__init__.py +19 -0
- reforma-0.1.2/reforma/bin/RePATool.jar +0 -0
- reforma-0.1.2/reforma/client.py +536 -0
- reforma-0.1.2/reforma/jar_bridge.py +181 -0
- reforma-0.1.2/reforma/model.py +96 -0
- reforma-0.1.0/tests/test_pyRe.py → reforma-0.1.2/tests/test_reforma.py +6 -6
- reforma-0.1.0/ReForma.egg-info/top_level.txt +0 -1
- {reforma-0.1.0 → reforma-0.1.2}/MANIFEST.in +0 -0
- {reforma-0.1.0 → reforma-0.1.2}/ReForma.egg-info/dependency_links.txt +0 -0
- {reforma-0.1.0 → reforma-0.1.2}/ReForma.egg-info/requires.txt +0 -0
- {reforma-0.1.0 → reforma-0.1.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ReForma
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python bindings for the RePA/ReForma probabilistic automaton tool
|
|
5
5
|
Author-email: Joshua Dourado <joshuadourado@ua.pt>
|
|
6
6
|
License: MIT
|
|
@@ -13,21 +13,27 @@ Description-Content-Type: text/markdown
|
|
|
13
13
|
Requires-Dist: networkx
|
|
14
14
|
Requires-Dist: matplotlib
|
|
15
15
|
|
|
16
|
-
# ReForma —
|
|
16
|
+
# ReForma — Reconfigurable Formal Automata in Python
|
|
17
17
|
|
|
18
|
-
A clean Python library that wraps the `
|
|
18
|
+
A clean Python library that wraps the `RePATool.jar` CLI via subprocess,
|
|
19
19
|
giving you a Pythonic interface for simulation, training, PDL/PCTL
|
|
20
|
-
verification, and
|
|
20
|
+
verification, and interactive graph visualizations.
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
25
25
|
|
|
26
|
+
You can install it directly from PyPI (once published):
|
|
26
27
|
```bash
|
|
27
|
-
|
|
28
|
-
pip install -e .
|
|
28
|
+
pip install reforma
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
For **visualization features** (offline PNGs and interactive Jupyter graphs), install the required extras:
|
|
32
|
+
```bash
|
|
33
|
+
pip install networkx matplotlib
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
*(Local Development: Run `pip install -e .` from the project root).*
|
|
31
37
|
Requires **Python 3.10+** and a working `java` on your PATH.
|
|
32
38
|
|
|
33
39
|
---
|
|
@@ -35,73 +41,84 @@ Requires **Python 3.10+** and a working `java` on your PATH.
|
|
|
35
41
|
## Quick Start
|
|
36
42
|
|
|
37
43
|
```python
|
|
38
|
-
from
|
|
44
|
+
from reforma import ReForma
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
ReForma = ReForma("path/to/ReFormaTool.jar")
|
|
46
|
+
modelo = ReForma()
|
|
42
47
|
|
|
43
48
|
# Load a model
|
|
44
|
-
state =
|
|
49
|
+
state = modelo.load_file("recommender.r")
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
print(state.
|
|
51
|
+
# Get a beautiful printout of the current state and probabilities
|
|
52
|
+
print(state.summary())
|
|
48
53
|
|
|
49
54
|
# Simulate
|
|
50
|
-
state =
|
|
51
|
-
state =
|
|
52
|
-
|
|
55
|
+
state = modelo.step("go_work")
|
|
56
|
+
state = modelo.step("easy_task")
|
|
57
|
+
|
|
58
|
+
# Undo last step
|
|
59
|
+
state = modelo.undo()
|
|
53
60
|
|
|
54
61
|
# Reset to initial state
|
|
55
|
-
|
|
62
|
+
modelo.reset()
|
|
56
63
|
```
|
|
57
64
|
|
|
58
65
|
---
|
|
59
66
|
|
|
60
|
-
##
|
|
67
|
+
## Visualization (Jupyter & Offline)
|
|
68
|
+
|
|
69
|
+
ReForma provides powerful graphing tools directly integrated into your workflow.
|
|
61
70
|
|
|
62
71
|
```python
|
|
63
|
-
|
|
72
|
+
from reforma import ReForma
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
print(f"{t.label}: {t.from_state} → {t.to_state} (p={t.probability:.3f})")
|
|
74
|
+
modelo = ReForma()
|
|
75
|
+
modelo.load_file("model.r")
|
|
68
76
|
|
|
69
|
-
#
|
|
70
|
-
|
|
77
|
+
# 1. Interactive Jupyter View
|
|
78
|
+
# Renders a drag-and-drop Cytoscape.js graph right inside your Notebook!
|
|
79
|
+
modelo.show_interactive()
|
|
71
80
|
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
# 2. Offline Static Images
|
|
82
|
+
# Renders a high-res graph using Matplotlib/NetworkX (no browser needed)
|
|
83
|
+
modelo.save_image_plt("output/my_graph.png")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Simulation & State Inspection
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
state = modelo.load_file("model.r")
|
|
75
92
|
|
|
76
93
|
# Inspect variables
|
|
77
94
|
print(state.variables) # {'counter': 0, 'flag': 1}
|
|
78
95
|
|
|
96
|
+
# Check enabled transitions manually
|
|
97
|
+
for t in state.enabled:
|
|
98
|
+
print(f"{t.label}: {t.from_state} → {t.to_state} (p={t.probability:.3f})")
|
|
99
|
+
|
|
79
100
|
# History of labels taken
|
|
80
|
-
print(
|
|
101
|
+
print(modelo.history) # ['go_work', 'easy_task']
|
|
81
102
|
```
|
|
82
103
|
|
|
83
104
|
---
|
|
84
105
|
|
|
85
106
|
## Training
|
|
86
107
|
|
|
87
|
-
Train the model on a batch of sessions (lists of event labels):
|
|
108
|
+
Train the model on a batch of sessions (lists of event labels) to automatically update the weights:
|
|
88
109
|
|
|
89
110
|
```python
|
|
90
|
-
|
|
111
|
+
modelo.train([
|
|
91
112
|
["go_work", "easy_task", "easy_task", "go_home"],
|
|
92
113
|
["battery_low", "go_charge", "finish_charge", "socialize"],
|
|
93
114
|
["no_money", "go_work", "go_home"],
|
|
94
115
|
])
|
|
95
116
|
|
|
96
117
|
# Or train directly from a log file (one session per line, comma-separated)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
# sessions.txt format:
|
|
100
|
-
# go_work,easy_task,go_home
|
|
101
|
-
# battery_low,go_charge,finish_charge
|
|
118
|
+
modelo.train_from_file("logs/sessions.txt")
|
|
102
119
|
|
|
103
|
-
# Save the updated model with new weights
|
|
104
|
-
|
|
120
|
+
# Save the updated model with the new calculated weights
|
|
121
|
+
modelo.save_source("model_trained.r")
|
|
105
122
|
```
|
|
106
123
|
|
|
107
124
|
---
|
|
@@ -110,19 +127,19 @@ ReForma.save_source("model_trained.r")
|
|
|
110
127
|
|
|
111
128
|
```python
|
|
112
129
|
# Quantitative: probability of eventually reaching Office
|
|
113
|
-
prob =
|
|
130
|
+
prob = modelo.check_pdl_value("Home", "{P=?[F Office]}")
|
|
114
131
|
print(f"P(reach Office from Home) = {prob:.4f}")
|
|
115
132
|
|
|
116
133
|
# Qualitative: is it probable?
|
|
117
|
-
holds =
|
|
134
|
+
holds = modelo.check_pdl_value("Home", "{P>=0.4[F Office]}")
|
|
118
135
|
print(f"P>=0.4? {holds}") # True / False
|
|
119
136
|
|
|
120
137
|
# PDL: is there a path via go_work to Office?
|
|
121
|
-
holds =
|
|
138
|
+
holds = modelo.check_pdl_value("Home", "<go_work>Office")
|
|
122
139
|
print(holds) # True
|
|
123
140
|
|
|
124
141
|
# Get the raw string result
|
|
125
|
-
raw =
|
|
142
|
+
raw = modelo.check_pdl("Home", "{P=?[F Office]}")
|
|
126
143
|
print(raw) # "Result: 0.50000"
|
|
127
144
|
```
|
|
128
145
|
|
|
@@ -144,20 +161,17 @@ print(raw) # "Result: 0.50000"
|
|
|
144
161
|
|
|
145
162
|
```python
|
|
146
163
|
# PRISM DTMC
|
|
147
|
-
prism_code =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
# mCRL2
|
|
151
|
-
mcrl2_code = ReForma.export_mcrl2()
|
|
164
|
+
prism_code = modelo.export_prism()
|
|
165
|
+
modelo.save_prism("output/model.pm")
|
|
152
166
|
|
|
153
167
|
# GLTS (imperative translation)
|
|
154
|
-
glts_code =
|
|
168
|
+
glts_code = modelo.export_glts()
|
|
155
169
|
|
|
156
170
|
# Mermaid diagram (initial state)
|
|
157
|
-
diagram =
|
|
171
|
+
diagram = modelo.export_mermaid()
|
|
158
172
|
|
|
159
173
|
# Mermaid diagram (full LTS — all reachable states)
|
|
160
|
-
full_diagram =
|
|
174
|
+
full_diagram = modelo.export_mermaid(full_lts=True)
|
|
161
175
|
```
|
|
162
176
|
|
|
163
177
|
---
|
|
@@ -173,45 +187,22 @@ s0 ---> s2: b (0.4)
|
|
|
173
187
|
s1 ---> s0: back (1.0)
|
|
174
188
|
"""
|
|
175
189
|
|
|
176
|
-
state =
|
|
190
|
+
state = modelo.load(source, name="MyModel")
|
|
177
191
|
```
|
|
178
192
|
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## Running the tests
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
pip install pytest
|
|
185
|
-
pytest tests/ -v
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## Project structure
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
ReForma/
|
|
194
|
-
├── __init__.py # Public API exports
|
|
195
|
-
├── client.py # ReForma — high-level Python API
|
|
196
|
-
├── jar_bridge.py # JarBridge — low-level subprocess wrapper
|
|
197
|
-
└── model.py # ReFormaModel, SimulationState, Transition data classes
|
|
198
|
-
tests/
|
|
199
|
-
└── test_ReForma.py # Full test suite (mocked, no JAR needed)
|
|
200
|
-
pyproject.toml
|
|
201
|
-
README.md
|
|
202
|
-
```
|
|
203
193
|
|
|
204
194
|
---
|
|
205
195
|
|
|
206
196
|
## Error handling
|
|
207
197
|
|
|
208
198
|
```python
|
|
209
|
-
from
|
|
199
|
+
from reforma.jar_bridge import JarError
|
|
210
200
|
|
|
211
201
|
try:
|
|
212
|
-
result =
|
|
202
|
+
result = modelo.check_pdl("Home", "{P=?[F Office]}")
|
|
213
203
|
except JarError as e:
|
|
214
204
|
print(f"JAR error: {e}")
|
|
215
205
|
except RuntimeError as e:
|
|
216
206
|
print(f"Usage error: {e}") # e.g. no model loaded, invalid transition
|
|
217
207
|
```
|
|
208
|
+
```
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
# ReForma —
|
|
1
|
+
# ReForma — Reconfigurable Formal Automata in Python
|
|
2
2
|
|
|
3
|
-
A clean Python library that wraps the `
|
|
3
|
+
A clean Python library that wraps the `RePATool.jar` CLI via subprocess,
|
|
4
4
|
giving you a Pythonic interface for simulation, training, PDL/PCTL
|
|
5
|
-
verification, and
|
|
5
|
+
verification, and interactive graph visualizations.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
|
+
You can install it directly from PyPI (once published):
|
|
11
12
|
```bash
|
|
12
|
-
|
|
13
|
-
pip install -e .
|
|
13
|
+
pip install reforma
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
For **visualization features** (offline PNGs and interactive Jupyter graphs), install the required extras:
|
|
17
|
+
```bash
|
|
18
|
+
pip install networkx matplotlib
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
*(Local Development: Run `pip install -e .` from the project root).*
|
|
16
22
|
Requires **Python 3.10+** and a working `java` on your PATH.
|
|
17
23
|
|
|
18
24
|
---
|
|
@@ -20,73 +26,84 @@ Requires **Python 3.10+** and a working `java` on your PATH.
|
|
|
20
26
|
## Quick Start
|
|
21
27
|
|
|
22
28
|
```python
|
|
23
|
-
from
|
|
29
|
+
from reforma import ReForma
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
ReForma = ReForma("path/to/ReFormaTool.jar")
|
|
31
|
+
modelo = ReForma()
|
|
27
32
|
|
|
28
33
|
# Load a model
|
|
29
|
-
state =
|
|
34
|
+
state = modelo.load_file("recommender.r")
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
print(state.
|
|
36
|
+
# Get a beautiful printout of the current state and probabilities
|
|
37
|
+
print(state.summary())
|
|
33
38
|
|
|
34
39
|
# Simulate
|
|
35
|
-
state =
|
|
36
|
-
state =
|
|
37
|
-
|
|
40
|
+
state = modelo.step("go_work")
|
|
41
|
+
state = modelo.step("easy_task")
|
|
42
|
+
|
|
43
|
+
# Undo last step
|
|
44
|
+
state = modelo.undo()
|
|
38
45
|
|
|
39
46
|
# Reset to initial state
|
|
40
|
-
|
|
47
|
+
modelo.reset()
|
|
41
48
|
```
|
|
42
49
|
|
|
43
50
|
---
|
|
44
51
|
|
|
45
|
-
##
|
|
52
|
+
## Visualization (Jupyter & Offline)
|
|
53
|
+
|
|
54
|
+
ReForma provides powerful graphing tools directly integrated into your workflow.
|
|
46
55
|
|
|
47
56
|
```python
|
|
48
|
-
|
|
57
|
+
from reforma import ReForma
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
print(f"{t.label}: {t.from_state} → {t.to_state} (p={t.probability:.3f})")
|
|
59
|
+
modelo = ReForma()
|
|
60
|
+
modelo.load_file("model.r")
|
|
53
61
|
|
|
54
|
-
#
|
|
55
|
-
|
|
62
|
+
# 1. Interactive Jupyter View
|
|
63
|
+
# Renders a drag-and-drop Cytoscape.js graph right inside your Notebook!
|
|
64
|
+
modelo.show_interactive()
|
|
56
65
|
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
# 2. Offline Static Images
|
|
67
|
+
# Renders a high-res graph using Matplotlib/NetworkX (no browser needed)
|
|
68
|
+
modelo.save_image_plt("output/my_graph.png")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Simulation & State Inspection
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
state = modelo.load_file("model.r")
|
|
60
77
|
|
|
61
78
|
# Inspect variables
|
|
62
79
|
print(state.variables) # {'counter': 0, 'flag': 1}
|
|
63
80
|
|
|
81
|
+
# Check enabled transitions manually
|
|
82
|
+
for t in state.enabled:
|
|
83
|
+
print(f"{t.label}: {t.from_state} → {t.to_state} (p={t.probability:.3f})")
|
|
84
|
+
|
|
64
85
|
# History of labels taken
|
|
65
|
-
print(
|
|
86
|
+
print(modelo.history) # ['go_work', 'easy_task']
|
|
66
87
|
```
|
|
67
88
|
|
|
68
89
|
---
|
|
69
90
|
|
|
70
91
|
## Training
|
|
71
92
|
|
|
72
|
-
Train the model on a batch of sessions (lists of event labels):
|
|
93
|
+
Train the model on a batch of sessions (lists of event labels) to automatically update the weights:
|
|
73
94
|
|
|
74
95
|
```python
|
|
75
|
-
|
|
96
|
+
modelo.train([
|
|
76
97
|
["go_work", "easy_task", "easy_task", "go_home"],
|
|
77
98
|
["battery_low", "go_charge", "finish_charge", "socialize"],
|
|
78
99
|
["no_money", "go_work", "go_home"],
|
|
79
100
|
])
|
|
80
101
|
|
|
81
102
|
# Or train directly from a log file (one session per line, comma-separated)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# sessions.txt format:
|
|
85
|
-
# go_work,easy_task,go_home
|
|
86
|
-
# battery_low,go_charge,finish_charge
|
|
103
|
+
modelo.train_from_file("logs/sessions.txt")
|
|
87
104
|
|
|
88
|
-
# Save the updated model with new weights
|
|
89
|
-
|
|
105
|
+
# Save the updated model with the new calculated weights
|
|
106
|
+
modelo.save_source("model_trained.r")
|
|
90
107
|
```
|
|
91
108
|
|
|
92
109
|
---
|
|
@@ -95,19 +112,19 @@ ReForma.save_source("model_trained.r")
|
|
|
95
112
|
|
|
96
113
|
```python
|
|
97
114
|
# Quantitative: probability of eventually reaching Office
|
|
98
|
-
prob =
|
|
115
|
+
prob = modelo.check_pdl_value("Home", "{P=?[F Office]}")
|
|
99
116
|
print(f"P(reach Office from Home) = {prob:.4f}")
|
|
100
117
|
|
|
101
118
|
# Qualitative: is it probable?
|
|
102
|
-
holds =
|
|
119
|
+
holds = modelo.check_pdl_value("Home", "{P>=0.4[F Office]}")
|
|
103
120
|
print(f"P>=0.4? {holds}") # True / False
|
|
104
121
|
|
|
105
122
|
# PDL: is there a path via go_work to Office?
|
|
106
|
-
holds =
|
|
123
|
+
holds = modelo.check_pdl_value("Home", "<go_work>Office")
|
|
107
124
|
print(holds) # True
|
|
108
125
|
|
|
109
126
|
# Get the raw string result
|
|
110
|
-
raw =
|
|
127
|
+
raw = modelo.check_pdl("Home", "{P=?[F Office]}")
|
|
111
128
|
print(raw) # "Result: 0.50000"
|
|
112
129
|
```
|
|
113
130
|
|
|
@@ -129,20 +146,17 @@ print(raw) # "Result: 0.50000"
|
|
|
129
146
|
|
|
130
147
|
```python
|
|
131
148
|
# PRISM DTMC
|
|
132
|
-
prism_code =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
# mCRL2
|
|
136
|
-
mcrl2_code = ReForma.export_mcrl2()
|
|
149
|
+
prism_code = modelo.export_prism()
|
|
150
|
+
modelo.save_prism("output/model.pm")
|
|
137
151
|
|
|
138
152
|
# GLTS (imperative translation)
|
|
139
|
-
glts_code =
|
|
153
|
+
glts_code = modelo.export_glts()
|
|
140
154
|
|
|
141
155
|
# Mermaid diagram (initial state)
|
|
142
|
-
diagram =
|
|
156
|
+
diagram = modelo.export_mermaid()
|
|
143
157
|
|
|
144
158
|
# Mermaid diagram (full LTS — all reachable states)
|
|
145
|
-
full_diagram =
|
|
159
|
+
full_diagram = modelo.export_mermaid(full_lts=True)
|
|
146
160
|
```
|
|
147
161
|
|
|
148
162
|
---
|
|
@@ -158,45 +172,22 @@ s0 ---> s2: b (0.4)
|
|
|
158
172
|
s1 ---> s0: back (1.0)
|
|
159
173
|
"""
|
|
160
174
|
|
|
161
|
-
state =
|
|
175
|
+
state = modelo.load(source, name="MyModel")
|
|
162
176
|
```
|
|
163
177
|
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## Running the tests
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
pip install pytest
|
|
170
|
-
pytest tests/ -v
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## Project structure
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
ReForma/
|
|
179
|
-
├── __init__.py # Public API exports
|
|
180
|
-
├── client.py # ReForma — high-level Python API
|
|
181
|
-
├── jar_bridge.py # JarBridge — low-level subprocess wrapper
|
|
182
|
-
└── model.py # ReFormaModel, SimulationState, Transition data classes
|
|
183
|
-
tests/
|
|
184
|
-
└── test_ReForma.py # Full test suite (mocked, no JAR needed)
|
|
185
|
-
pyproject.toml
|
|
186
|
-
README.md
|
|
187
|
-
```
|
|
188
178
|
|
|
189
179
|
---
|
|
190
180
|
|
|
191
181
|
## Error handling
|
|
192
182
|
|
|
193
183
|
```python
|
|
194
|
-
from
|
|
184
|
+
from reforma.jar_bridge import JarError
|
|
195
185
|
|
|
196
186
|
try:
|
|
197
|
-
result =
|
|
187
|
+
result = modelo.check_pdl("Home", "{P=?[F Office]}")
|
|
198
188
|
except JarError as e:
|
|
199
189
|
print(f"JAR error: {e}")
|
|
200
190
|
except RuntimeError as e:
|
|
201
191
|
print(f"Usage error: {e}") # e.g. no model loaded, invalid transition
|
|
192
|
+
```
|
|
202
193
|
```
|