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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ReForma
3
- Version: 0.1.0
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 — Python bindings for the RePA/ReForma tool
16
+ # ReForma — Reconfigurable Formal Automata in Python
17
17
 
18
- A clean Python library that wraps the `ReFormaTool.jar` CLI via subprocess,
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 export.
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
- # From the project root (where pyproject.toml lives)
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 ReForma import ReForma
44
+ from reforma import ReForma
39
45
 
40
- # Point to your compiled JAR
41
- ReForma = ReForma("path/to/ReFormaTool.jar")
46
+ modelo = ReForma()
42
47
 
43
48
  # Load a model
44
- state = ReForma.load_file("examples/recommender.r")
49
+ state = modelo.load_file("recommender.r")
45
50
 
46
- print(state.current_states) # ['Home']
47
- print(state.enabled) # [Transition('go_work': Home → Office, p=0.500), ...]
51
+ # Get a beautiful printout of the current state and probabilities
52
+ print(state.summary())
48
53
 
49
54
  # Simulate
50
- state = ReForma.step("go_work")
51
- state = ReForma.step("easy_task")
52
- state = ReForma.undo() # undo last step
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
- ReForma.reset()
62
+ modelo.reset()
56
63
  ```
57
64
 
58
65
  ---
59
66
 
60
- ## Simulation
67
+ ## Visualization (Jupyter & Offline)
68
+
69
+ ReForma provides powerful graphing tools directly integrated into your workflow.
61
70
 
62
71
  ```python
63
- state = ReForma.load_file("model.r")
72
+ from reforma import ReForma
64
73
 
65
- # Check what's enabled
66
- for t in state.enabled:
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
- # Take a step by label
70
- state = ReForma.step("go_work")
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
- # Undo / reset
73
- state = ReForma.undo()
74
- state = ReForma.reset()
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(ReForma.history) # ['go_work']
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
- ReForma.train([
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
- ReForma.train_from_file("logs/sessions.txt")
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
- ReForma.save_source("model_trained.r")
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 = ReForma.check_pdl_value("Home", "{P=?[F Office]}")
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 = ReForma.check_pdl_value("Home", "{P>=0.4[F Office]}")
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 = ReForma.check_pdl_value("Home", "<go_work>Office")
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 = ReForma.check_pdl("Home", "{P=?[F Office]}")
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 = ReForma.export_prism()
148
- ReForma.save_prism("output/model.pm")
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 = ReForma.export_glts()
168
+ glts_code = modelo.export_glts()
155
169
 
156
170
  # Mermaid diagram (initial state)
157
- diagram = ReForma.export_mermaid()
171
+ diagram = modelo.export_mermaid()
158
172
 
159
173
  # Mermaid diagram (full LTS — all reachable states)
160
- full_diagram = ReForma.export_mermaid(full_lts=True)
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 = ReForma.load(source, name="MyModel")
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 ReForma.jar_bridge import JarError
199
+ from reforma.jar_bridge import JarError
210
200
 
211
201
  try:
212
- result = ReForma.check_pdl("Home", "{P=?[F Office]}")
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 — Python bindings for the RePA/ReForma tool
1
+ # ReForma — Reconfigurable Formal Automata in Python
2
2
 
3
- A clean Python library that wraps the `ReFormaTool.jar` CLI via subprocess,
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 export.
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
- # From the project root (where pyproject.toml lives)
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 ReForma import ReForma
29
+ from reforma import ReForma
24
30
 
25
- # Point to your compiled JAR
26
- ReForma = ReForma("path/to/ReFormaTool.jar")
31
+ modelo = ReForma()
27
32
 
28
33
  # Load a model
29
- state = ReForma.load_file("examples/recommender.r")
34
+ state = modelo.load_file("recommender.r")
30
35
 
31
- print(state.current_states) # ['Home']
32
- print(state.enabled) # [Transition('go_work': Home → Office, p=0.500), ...]
36
+ # Get a beautiful printout of the current state and probabilities
37
+ print(state.summary())
33
38
 
34
39
  # Simulate
35
- state = ReForma.step("go_work")
36
- state = ReForma.step("easy_task")
37
- state = ReForma.undo() # undo last step
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
- ReForma.reset()
47
+ modelo.reset()
41
48
  ```
42
49
 
43
50
  ---
44
51
 
45
- ## Simulation
52
+ ## Visualization (Jupyter & Offline)
53
+
54
+ ReForma provides powerful graphing tools directly integrated into your workflow.
46
55
 
47
56
  ```python
48
- state = ReForma.load_file("model.r")
57
+ from reforma import ReForma
49
58
 
50
- # Check what's enabled
51
- for t in state.enabled:
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
- # Take a step by label
55
- state = ReForma.step("go_work")
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
- # Undo / reset
58
- state = ReForma.undo()
59
- state = ReForma.reset()
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(ReForma.history) # ['go_work']
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
- ReForma.train([
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
- ReForma.train_from_file("logs/sessions.txt")
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
- ReForma.save_source("model_trained.r")
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 = ReForma.check_pdl_value("Home", "{P=?[F Office]}")
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 = ReForma.check_pdl_value("Home", "{P>=0.4[F Office]}")
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 = ReForma.check_pdl_value("Home", "<go_work>Office")
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 = ReForma.check_pdl("Home", "{P=?[F Office]}")
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 = ReForma.export_prism()
133
- ReForma.save_prism("output/model.pm")
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 = ReForma.export_glts()
153
+ glts_code = modelo.export_glts()
140
154
 
141
155
  # Mermaid diagram (initial state)
142
- diagram = ReForma.export_mermaid()
156
+ diagram = modelo.export_mermaid()
143
157
 
144
158
  # Mermaid diagram (full LTS — all reachable states)
145
- full_diagram = ReForma.export_mermaid(full_lts=True)
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 = ReForma.load(source, name="MyModel")
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 ReForma.jar_bridge import JarError
184
+ from reforma.jar_bridge import JarError
195
185
 
196
186
  try:
197
- result = ReForma.check_pdl("Home", "{P=?[F Office]}")
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
  ```