morphata 2.0.10__tar.gz → 2.2.0__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.
Files changed (211) hide show
  1. morphata-2.2.0/.basedpyright/baseline.json +3 -0
  2. {morphata-2.0.10 → morphata-2.2.0}/.envrc +2 -2
  3. {morphata-2.0.10 → morphata-2.2.0}/.rstcheck.cfg +2 -0
  4. morphata-2.2.0/AGENTS.md +40 -0
  5. {morphata-2.0.10 → morphata-2.2.0}/CHANGELOG.md +134 -20
  6. {morphata-2.0.10 → morphata-2.2.0}/CONTRIBUTING.md +10 -48
  7. morphata-2.2.0/PKG-INFO +134 -0
  8. morphata-2.2.0/README.rst +104 -0
  9. morphata-2.2.0/bench/conftest.py +32 -0
  10. {morphata-2.0.10 → morphata-2.2.0}/bench/test_equivalence_perf.py +11 -19
  11. morphata-2.2.0/bench/test_hoa_exporter_perf.py +151 -0
  12. {morphata-2.0.10 → morphata-2.2.0}/bench/test_hoa_parser_perf.py +26 -10
  13. morphata-2.2.0/bench/test_sere_nlm_perf.py +107 -0
  14. morphata-2.2.0/bench/test_transforms_perf.py +120 -0
  15. morphata-2.2.0/docs/Makefile +20 -0
  16. {morphata-2.0.10 → morphata-2.2.0}/docs/api/modules.rst +6 -11
  17. morphata-2.2.0/docs/api/morphata.acc_expr.rst +6 -0
  18. morphata-2.2.0/docs/api/morphata.acceptance.rst +6 -0
  19. morphata-2.2.0/docs/api/morphata.alphabet.rst +6 -0
  20. morphata-2.2.0/docs/api/morphata.builder.rst +6 -0
  21. morphata-2.2.0/docs/api/morphata.hoa.rst +43 -0
  22. morphata-2.2.0/docs/api/morphata.logic.rst +11 -0
  23. morphata-2.2.0/docs/api/morphata.operators.rst +12 -0
  24. morphata-2.2.0/docs/api/morphata.symbolic.rst +38 -0
  25. morphata-2.2.0/docs/changelog.md +2 -0
  26. {morphata-2.0.10 → morphata-2.2.0}/docs/concepts/acceptance.rst +26 -13
  27. morphata-2.2.0/docs/concepts/hoa.rst +138 -0
  28. {morphata-2.0.10 → morphata-2.2.0}/docs/concepts/index.rst +3 -1
  29. morphata-2.2.0/docs/concepts/operators.rst +229 -0
  30. morphata-2.2.0/docs/concepts/symbolic.rst +99 -0
  31. morphata-2.2.0/docs/concepts/weights.rst +150 -0
  32. morphata-2.2.0/docs/conf.py +186 -0
  33. morphata-2.2.0/docs/index.rst +135 -0
  34. morphata-2.2.0/docs/quick-start.rst +221 -0
  35. {morphata-2.0.10 → morphata-2.2.0}/justfile +8 -5
  36. {morphata-2.0.10 → morphata-2.2.0}/pixi.lock +3423 -1260
  37. {morphata-2.0.10 → morphata-2.2.0}/pixi.toml +26 -16
  38. {morphata-2.0.10 → morphata-2.2.0}/pyproject.toml +40 -10
  39. morphata-2.2.0/pyrightconfig.json +26 -0
  40. {morphata-2.0.10 → morphata-2.2.0}/pytest.toml +2 -1
  41. morphata-2.2.0/rules/no-derivative-multiarg.yml +11 -0
  42. morphata-2.2.0/rules/no-typing-as-ty.yml +8 -0
  43. morphata-2.2.0/sgconfig.yml +2 -0
  44. morphata-2.2.0/src/morphata/__init__.py +21 -0
  45. {morphata-2.0.10/src/morphata/hoa → morphata-2.2.0/src/morphata}/acc_expr.py +39 -8
  46. morphata-2.2.0/src/morphata/acceptance.py +1174 -0
  47. morphata-2.2.0/src/morphata/alphabet.py +92 -0
  48. morphata-2.2.0/src/morphata/builder.py +190 -0
  49. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/hoa/__init__.py +4 -8
  50. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/hoa/__main__.py +3 -1
  51. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/hoa/parser.py +121 -12
  52. morphata-2.2.0/src/morphata/logic/__init__.py +14 -0
  53. morphata-2.2.0/src/morphata/logic/__init__.pyi +25 -0
  54. morphata-2.2.0/src/morphata/logic/_common.py +383 -0
  55. morphata-2.2.0/src/morphata/logic/ltl.py +109 -0
  56. morphata-2.2.0/src/morphata/logic/psl.py +75 -0
  57. morphata-2.2.0/src/morphata/logic/sere.py +201 -0
  58. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/operators/_backend.py +8 -5
  59. morphata-2.2.0/src/morphata/operators/matrix.py +326 -0
  60. morphata-2.2.0/src/morphata/operators/polynomial.py +438 -0
  61. morphata-2.2.0/src/morphata/symbolic/__init__.py +14 -0
  62. morphata-2.2.0/src/morphata/symbolic/automaton.py +811 -0
  63. morphata-2.2.0/src/morphata/symbolic/bdd.py +1162 -0
  64. morphata-2.2.0/src/morphata/symbolic/utils.py +718 -0
  65. morphata-2.2.0/src/morphata/utils.py +200 -0
  66. {morphata-2.0.10 → morphata-2.2.0}/tests/conftest.py +64 -34
  67. morphata-2.2.0/tests/hoa/test_exporter.py +230 -0
  68. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/test_parser.py +5 -3
  69. morphata-2.2.0/tests/logic/test_ltl.py +315 -0
  70. morphata-2.2.0/tests/logic/test_psl.py +176 -0
  71. morphata-2.2.0/tests/logic/test_sere.py +381 -0
  72. morphata-2.2.0/tests/operators/test_matrix.py +328 -0
  73. morphata-2.2.0/tests/operators/test_polynomial.py +128 -0
  74. morphata-2.2.0/tests/symbolic/test_bdd_helpers.py +652 -0
  75. morphata-2.2.0/tests/symbolic/test_compose.py +177 -0
  76. {morphata-2.0.10 → morphata-2.2.0}/tests/symbolic/test_from_hoaf.py +31 -3
  77. morphata-2.2.0/tests/symbolic/test_language_equivalence.py +156 -0
  78. {morphata-2.0.10 → morphata-2.2.0}/tests/symbolic/test_ltlf2dfa_equivalence.py +75 -46
  79. morphata-2.2.0/tests/symbolic/test_symbolic_automaton.py +385 -0
  80. morphata-2.2.0/tests/symbolic/test_to_hoa.py +97 -0
  81. morphata-2.2.0/tests/symbolic/test_transforms.py +530 -0
  82. morphata-2.2.0/tests/test_acceptance_validation.py +79 -0
  83. morphata-2.2.0/tests/test_alphabet.py +50 -0
  84. morphata-2.2.0/tests/test_builder.py +138 -0
  85. morphata-2.2.0/uv.lock +3358 -0
  86. morphata-2.0.10/.basedpyright/baseline.json +0 -854
  87. morphata-2.0.10/.claude/settings.local.json +0 -35
  88. morphata-2.0.10/.codegraph/.gitignore +0 -16
  89. morphata-2.0.10/.codegraph/codegraph.db +0 -0
  90. morphata-2.0.10/.codegraph/codegraph.db-shm +0 -0
  91. morphata-2.0.10/.codegraph/codegraph.db-wal +0 -0
  92. morphata-2.0.10/.codegraph/daemon.pid +0 -6
  93. morphata-2.0.10/AGENTS.md +0 -421
  94. morphata-2.0.10/PKG-INFO +0 -137
  95. morphata-2.0.10/README.md +0 -106
  96. morphata-2.0.10/bench/conftest.py +0 -53
  97. morphata-2.0.10/bench/test_hoa_exporter_perf.py +0 -124
  98. morphata-2.0.10/bench/test_sere_nlm_perf.py +0 -84
  99. morphata-2.0.10/bench/test_successors_for_alphabet_perf.py +0 -124
  100. morphata-2.0.10/cliff.toml +0 -59
  101. morphata-2.0.10/docs/api/morphata.acceptance.rst +0 -8
  102. morphata-2.0.10/docs/api/morphata.alphabet.rst +0 -8
  103. morphata-2.0.10/docs/api/morphata.automaton.rst +0 -11
  104. morphata-2.0.10/docs/api/morphata.builder.rst +0 -8
  105. morphata-2.0.10/docs/api/morphata.hoa.rst +0 -29
  106. morphata-2.0.10/docs/api/morphata.logic.ltl.rst +0 -8
  107. morphata-2.0.10/docs/api/morphata.logic.psl.rst +0 -15
  108. morphata-2.0.10/docs/api/morphata.logic.sere.rst +0 -9
  109. morphata-2.0.10/docs/api/morphata.logic.strel.rst +0 -8
  110. morphata-2.0.10/docs/api/morphata.operators.matrix.rst +0 -8
  111. morphata-2.0.10/docs/api/morphata.operators.polynomial.rst +0 -9
  112. morphata-2.0.10/docs/api/morphata.operators.rst +0 -9
  113. morphata-2.0.10/docs/api/morphata.symbolic.rst +0 -48
  114. morphata-2.0.10/docs/concepts/hoa.rst +0 -119
  115. morphata-2.0.10/docs/concepts/operators.rst +0 -184
  116. morphata-2.0.10/docs/concepts/spec.rst +0 -133
  117. morphata-2.0.10/docs/concepts/weights.rst +0 -167
  118. morphata-2.0.10/docs/conf.py +0 -69
  119. morphata-2.0.10/docs/index.rst +0 -139
  120. morphata-2.0.10/docs/quick-start.rst +0 -139
  121. morphata-2.0.10/docs/symbolic-transforms.rst +0 -187
  122. morphata-2.0.10/pyrefly.toml +0 -2
  123. morphata-2.0.10/pyrightconfig.json +0 -14
  124. morphata-2.0.10/ruff.toml +0 -11
  125. morphata-2.0.10/src/morphata/__init__.py +0 -29
  126. morphata-2.0.10/src/morphata/acceptance.py +0 -421
  127. morphata-2.0.10/src/morphata/alphabet.py +0 -178
  128. morphata-2.0.10/src/morphata/automaton.py +0 -295
  129. morphata-2.0.10/src/morphata/builder.py +0 -155
  130. morphata-2.0.10/src/morphata/hoa/exporter.py +0 -756
  131. morphata-2.0.10/src/morphata/logic/__init__.py +0 -15
  132. morphata-2.0.10/src/morphata/logic/_common.py +0 -136
  133. morphata-2.0.10/src/morphata/logic/ltl.py +0 -363
  134. morphata-2.0.10/src/morphata/logic/psl.py +0 -372
  135. morphata-2.0.10/src/morphata/logic/sere.py +0 -517
  136. morphata-2.0.10/src/morphata/logic/strel.py +0 -545
  137. morphata-2.0.10/src/morphata/operators/matrix.py +0 -276
  138. morphata-2.0.10/src/morphata/operators/polynomial.py +0 -350
  139. morphata-2.0.10/src/morphata/symbolic/__init__.py +0 -52
  140. morphata-2.0.10/src/morphata/symbolic/automaton.py +0 -621
  141. morphata-2.0.10/src/morphata/symbolic/bdd.py +0 -822
  142. morphata-2.0.10/src/morphata/symbolic/compose.py +0 -462
  143. morphata-2.0.10/src/morphata/symbolic/equivalence.py +0 -187
  144. morphata-2.0.10/src/morphata/symbolic/persistence.py +0 -381
  145. morphata-2.0.10/src/morphata/symbolic/transforms.py +0 -674
  146. morphata-2.0.10/tests/hoa/test_exporter_basic.py +0 -125
  147. morphata-2.0.10/tests/hoa/test_exporter_roundtrip.py +0 -43
  148. morphata-2.0.10/tests/hoa/test_exporter_streaming.py +0 -298
  149. morphata-2.0.10/tests/logic/test_ltl.py +0 -346
  150. morphata-2.0.10/tests/logic/test_psl.py +0 -179
  151. morphata-2.0.10/tests/logic/test_sere.py +0 -489
  152. morphata-2.0.10/tests/logic/test_sere_properties.py +0 -132
  153. morphata-2.0.10/tests/logic/test_strel.py +0 -244
  154. morphata-2.0.10/tests/operators/test_matrix_from_ir.py +0 -241
  155. morphata-2.0.10/tests/operators/test_matrix_from_ltl.py +0 -62
  156. morphata-2.0.10/tests/operators/test_polynomial_from_ir.py +0 -102
  157. morphata-2.0.10/tests/symbolic/test_alphabet_aware_transitions.py +0 -168
  158. morphata-2.0.10/tests/symbolic/test_bdd_helpers.py +0 -277
  159. morphata-2.0.10/tests/symbolic/test_compose.py +0 -337
  160. morphata-2.0.10/tests/symbolic/test_composition_map.py +0 -264
  161. morphata-2.0.10/tests/symbolic/test_equivalence_naive_property.py +0 -130
  162. morphata-2.0.10/tests/symbolic/test_persistence.py +0 -251
  163. morphata-2.0.10/tests/symbolic/test_step.py +0 -73
  164. morphata-2.0.10/tests/symbolic/test_symbolic_automaton.py +0 -380
  165. morphata-2.0.10/tests/symbolic/test_symbolic_from_ir.py +0 -55
  166. morphata-2.0.10/tests/symbolic/test_to_hoa.py +0 -163
  167. morphata-2.0.10/tests/symbolic/test_transforms.py +0 -537
  168. morphata-2.0.10/tests/symbolic/test_transforms_ir.py +0 -41
  169. morphata-2.0.10/tests/symbolic/test_transforms_properties.py +0 -118
  170. morphata-2.0.10/tests/test_alphabet.py +0 -195
  171. morphata-2.0.10/tests/test_automaton.py +0 -208
  172. morphata-2.0.10/tests/test_builder.py +0 -124
  173. morphata-2.0.10/tests/test_from_parsed.py +0 -97
  174. morphata-2.0.10/ty.toml +0 -7
  175. morphata-2.0.10/uv.lock +0 -3271
  176. {morphata-2.0.10 → morphata-2.2.0}/.dockerignore +0 -0
  177. {morphata-2.0.10 → morphata-2.2.0}/.editorconfig +0 -0
  178. {morphata-2.0.10 → morphata-2.2.0}/.envrc.recommended +0 -0
  179. {morphata-2.0.10 → morphata-2.2.0}/.fdignore +0 -0
  180. {morphata-2.0.10 → morphata-2.2.0}/.gitattributes +0 -0
  181. {morphata-2.0.10 → morphata-2.2.0}/.gitignore +0 -0
  182. {morphata-2.0.10 → morphata-2.2.0}/.mailmap +0 -0
  183. {morphata-2.0.10 → morphata-2.2.0}/.python-version +0 -0
  184. {morphata-2.0.10 → morphata-2.2.0}/CLAUDE.md +0 -0
  185. {morphata-2.0.10 → morphata-2.2.0}/LICENSE +0 -0
  186. {morphata-2.0.10 → morphata-2.2.0}/bench/README.md +0 -0
  187. {morphata-2.0.10 → morphata-2.2.0}/bench/__init__.py +0 -0
  188. {morphata-2.0.10 → morphata-2.2.0}/ci/make-release +0 -0
  189. {morphata-2.0.10 → morphata-2.2.0}/docs/_static/navigation.html +0 -0
  190. {morphata-2.0.10 → morphata-2.2.0}/mypy.ini +0 -0
  191. {morphata-2.0.10 → morphata-2.2.0}/project.utf-8.add +0 -0
  192. {morphata-2.0.10 → morphata-2.2.0}/project.utf-8.add.spl +0 -0
  193. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/hoa/hoa.lark +0 -0
  194. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/operators/__init__.py +0 -0
  195. {morphata-2.0.10 → morphata-2.2.0}/src/morphata/py.typed +0 -0
  196. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut1.hoa +0 -0
  197. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut11.hoa +0 -0
  198. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut2.hoa +0 -0
  199. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut3.2.hoa +0 -0
  200. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut3.hoa +0 -0
  201. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut4.hoa +0 -0
  202. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut5.hoa +0 -0
  203. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut6.hoa +0 -0
  204. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut7.hoa +0 -0
  205. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/aut8.hoa +0 -0
  206. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/finite_aut.hoa +0 -0
  207. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/gen_buchi_3.hoa +0 -0
  208. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/gen_cobuchi_2.hoa +0 -0
  209. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/rabin_2pair.hoa +0 -0
  210. {morphata-2.0.10 → morphata-2.2.0}/tests/hoa/streett_2pair.hoa +0 -0
  211. {morphata-2.0.10 → morphata-2.2.0}/tests/logic/__init__.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ "files": {}
3
+ }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- set -euo pipefail
3
+ # set -euo pipefail
4
4
 
5
5
  info() {
6
6
  DIRENV_LOG_FORMAT="envrc: %s" log_status "$@"
@@ -23,4 +23,4 @@ export PIXI_ENV
23
23
  dotenv_if_exists
24
24
 
25
25
  watch_file pixi.lock
26
- eval "$(pixi shell-hook -e "$PIXI_ENV")"
26
+ eval "$(pixi shell-hook --as-is -e "$PIXI_ENV")"
@@ -3,6 +3,8 @@ ignore_directives =
3
3
  automodule,
4
4
  autoclass,
5
5
  autofunction,
6
+ autotype,
7
+ autoexception,
6
8
  ignore_roles =
7
9
  external:py:mod,
8
10
  report_level = WARNING
@@ -0,0 +1,40 @@
1
+ # Morphata: Agent Context
2
+
3
+ `morphata` does representation theory for automata, and makes it practical.
4
+ It packages structural automaton representations together with semiring-valued
5
+ *operators* that turn an automaton into a computable interpretation.
6
+
7
+ ## What Agents Are for Here
8
+
9
+ This codebase is written and maintained by a single, highly opinionated author.
10
+ The default mode for an LLM here is **read-only**: understand the code, explain it,
11
+ answer questions, and locate things.
12
+ That is the job.
13
+
14
+ **Do not write or restructure code.**
15
+ Assume every design decision was made deliberately.
16
+ If you think something should change, say so and stop — do not implement it.
17
+ In particular, never:
18
+
19
+ - introduce new modules, abstractions, or layers of indirection;
20
+ - refactor, rename, or "clean up" working code;
21
+ - add compatibility shims, fallbacks, or defensive scaffolding;
22
+ - broaden an API or generalize past what was asked;
23
+ - follow a tangent into a rabbit hole.
24
+ When the task grows past a line or two of obvious change,
25
+ stop and report instead of chasing it.
26
+
27
+ The narrow exception: a **surgical, already-decided edit** the author has spelled out
28
+ (a typo, a one-line fix, a mechanical sweep).
29
+ Do exactly that and nothing more.
30
+ When unsure whether a change qualifies, treat it as out of scope and ask.
31
+
32
+ ## Development Environment
33
+
34
+ The development shell already has the project virtual environment activated,
35
+ so `pytest`, `zuban`, `basedpyright`, `ruff`, `sphinx-build`,
36
+ etc. are on `PATH` directly.
37
+ **Do not** prefix commands with `uv run`, `pixi run`, `poetry run`, or similar.
38
+ Just invoke the tool.
39
+ If a tool is missing, stop and tell the user rather than trying to bootstrap
40
+ or reinstall the environment.
@@ -1,5 +1,125 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.2.0 — 2026-08-19
4
+
5
+ This is a major release as it cleans up a lot of bad code,
6
+ attempts to make the design choices more consistent,
7
+ and increase the surface area of properly typed code.
8
+
9
+ ### Added
10
+
11
+ - Add finite-word composition directly to `SymbolicAutomaton`: `&`, `|`, `^`,
12
+ and `~` implement intersection, union, symmetric difference, and complement.
13
+ The variadic `compose_automata`, `is_language_equivalent`,
14
+ and `forward_bisim_reduction` helpers cover composition, equivalence checking,
15
+ and language-preserving quotienting without leaving the symbolic representation.
16
+ - Add a typed `BDDManager`/`Function` API and symbolic utilities for replacing a
17
+ manager, reindexing or quotienting states, materializing sinks, traversing reachable
18
+ states, and constructing universal acceptors and rejectors.
19
+ - Support arbitrary HOA v1 acceptance expressions through `GenericCondition`,
20
+ in addition to the concrete finite, Büchi, co-Büchi, generalized Büchi/co-Büchi,
21
+ Rabin, and Streett conditions.
22
+ Omega acceptance remains structural only:
23
+ run evaluation and transforms still implement finite-word semantics.
24
+
25
+ ### Changed
26
+
27
+ - **The primary automaton API is now `SymbolicAutomaton`.**
28
+ The intermediate `morphata.automaton.Automaton` representation has been removed.
29
+ Logic conversion, hand construction, transforms, composition, HOA conversion,
30
+ and operators now work directly with the BDD-backed type.
31
+ Migrate logic calls to `formula_to_automaton(...)`
32
+ or `SymbolicAutomaton.from_specification(...)`,
33
+ and use the instance methods `remove_alternation()`, `determinize()`,
34
+ and `to_min_dfa()` instead of the old transform functions.
35
+ - `AutomatonBuilder` now accepts integer state identifiers
36
+ and `build()` returns a `SymbolicAutomaton`; pass a `labeling_fn`
37
+ (and optionally a shared `BDDManager`).
38
+ Set-valued successors are disjunctions;
39
+ use a Boolean state expression for an alternating conjunction.
40
+ The old `variant`/`DeltaKind` construction API is gone.
41
+ - Alphabets now separate symbol labeling from guard weighting.
42
+ `BooleanAlphabet.labeling` returns an `AP -> bool` mapping, while operator weight
43
+ functions receive guards in sum-of-products form. `Alphabet`, `WeightedAlphabet`,
44
+ and `weighted_alphabet` are replaced by `BooleanAlphabet`, `SemiringAlphabet`,
45
+ `powerset_alphabet`, and `finite_alphabet`.
46
+ - `MatrixOperator` and `PolynomialOperator` are constructed with
47
+ `from_symbolic_automaton` or `from_specification`.
48
+ Pass `weight_fn` directly rather than an alphabet;
49
+ matrix construction also requires `backend`.
50
+ Their `accepts()` methods return a scalar `AlgebraicArray`,
51
+ and transition generation is exposed as `op.delta(symbol)`.
52
+ - HOA conversion now goes through `ParsedAutomaton`:
53
+ use `SymbolicAutomaton.from_hoaf(parsed, alphabet=...)` and `str(aut.to_hoaf())`.
54
+ State IDs need not be dense, and states without outgoing edges survive round trips.
55
+
56
+ ### Fixed
57
+
58
+ - Correct symbolic derivatives for negated variables and SERE nodes.
59
+ - Fix breadth-first traversal ordering, symbolic language equivalence, and transition
60
+ partitioning when multiple guards have the same residual.
61
+ - Correct `step()` labeling and the structural checks for deterministic and
62
+ forward-progressing automata.
63
+ - Make builders, HOA conversion, and both operators handle sparse external state IDs
64
+ consistently by using dense indices only internally.
65
+
66
+ ### Removed
67
+
68
+ - Remove the old `morphata.automaton` IR, STREL translator,
69
+ BDD-JSON persistence/cache API, and the former `symbolic.transforms`,
70
+ `symbolic.equivalence`, and `symbolic.compose` modules.
71
+ Their surviving operations now live on `SymbolicAutomaton` or in `morphata.symbolic`;
72
+ there is no replacement for STREL or BDD-JSON persistence in this release.
73
+ - Remove the specialized composition-map/transition-enumeration APIs and structural
74
+ `prune`; use general symbolic composition and `forward_bisim_reduction` where those
75
+ semantics fit.
76
+
77
+ ## 2.1.0 — 2026-06-11
78
+
79
+ ### Added
80
+
81
+ - Add `morphata.symbolic.prune` that does a cheap,
82
+ language-preserving structural pruning of an AFA.
83
+ The idea here is to try and reduce the number of states in the AFA
84
+ (no guarantees)
85
+ by performing a forward reachability pass, dead-state pruning,
86
+ and a parameterized number of passes for one-step acceptance-partition deduplication.
87
+
88
+ ### Changed
89
+
90
+ - `MatrixOperator` and `PolynomialOperator` are generic now —
91
+ `MatrixOperator[Symbol, AP]` and `PolynomialOperator[Symbol, AP]`,
92
+ just like `SymbolicAutomaton`.
93
+ When I first banged these out I left them un-parameterized
94
+ (read: `Any` smeared everywhere),
95
+ so now the symbol and AP types actually flow through
96
+ and `MatrixOperator[frozenset[str], str]` means something.
97
+ Nothing changes at runtime;
98
+ the one thing you might notice is your type-checker nudging you to fill in the params
99
+ if you were annotating a bare `MatrixOperator` or `PolynomialOperator`.
100
+ - The BDD-JSON sidecar cache jumped to schema **v2**.
101
+ Acceptance conditions now (de)serialize through `cattrs` instead of the hand-rolled
102
+ `meta.get(...)` dance, and Rabin/Streett pairs are written as objects
103
+ (`{"rejecting": ..., "accepting": ...}`) rather than nested lists.
104
+ Heads up: old `v1` `.bdd.json` caches will politely refuse to load
105
+ (clean error, not a silent miscompile) --- just regenerate them and you're good.
106
+ Remember, this is a *cache*, not a portable format,
107
+ so this shouldn't bite anyone hard.
108
+ - STREL conversion shed ~120 lines.
109
+ All the timed-interval unrolling
110
+ (`G[a,b]`, `F[a,b]`, `U[t1,t2]`, `X[n]`)
111
+ and the spatial `Somewhere`/`Everywhere` desugaring used to be hand-rolled in
112
+ `strel.py`, but `logic-asts` already does all of it in `.expand()` — so I ripped them
113
+ out and just lean on the upstream rules.
114
+ This needs the newer `logic-asts`
115
+ (the one with the spatial `expand()` rules), so that dep gets bumped along with it.
116
+
117
+ ### Miscellaneous
118
+
119
+ - Housekeeping, but worth saying:
120
+ the whole package now type-checks clean under *both* `zuban` and `basedpyright`
121
+ (0 errors, 0 warnings), so contributing should be a bit less whack-a-mole.
122
+
3
123
  ## 2.0.10 — 2026-06-08
4
124
 
5
125
  ### Fixed
@@ -10,8 +130,8 @@
10
130
 
11
131
  ### Performance
12
132
 
13
- - The HOA grammar is now LALR compatible! This means we get a huge performance boost
14
- even for pretty large automata.
133
+ - The HOA grammar is now LALR compatible!
134
+ This means we get a huge performance boost even for pretty large automata.
15
135
  - Similar thing was done in `logic-asts` and thus, the version will be bumped.
16
136
 
17
137
  ## 2.0.9 — 2026-06-04
@@ -87,7 +207,7 @@
87
207
  ### Fixed
88
208
 
89
209
  - A major regression where the streaming `to_hoa` stuff changed the label enumeration
90
- semantics to be _minterms_ instead of _cubes_.
210
+ semantics to be *minterms* instead of *cubes*.
91
211
  This is now fixed.
92
212
 
93
213
  ### Added
@@ -308,8 +428,7 @@ which will be summarized below.
308
428
  The reverse direction is deliberately omitted —
309
429
  recovering Boolean semantics from arbitrary `V` needs an ordering and a cut (cf.
310
430
  STL), and pretending otherwise would silently produce garbage.
311
- - **Ergonomic construction.**
312
- `AutomatonBuilder` replaces the old NFA builder.
431
+ - **Ergonomic construction.** `AutomatonBuilder` replaces the old NFA builder.
313
432
  Add states, add transitions with a guard and a successor
314
433
  (single state, set of states, or a raw `BoolExpr` for full alternation),
315
434
  and `build()` cleans up by merging rows that share a successor.
@@ -337,11 +456,9 @@ which will be summarized below.
337
456
  The BDD cofactor path works for any `BooleanAlphabet`,
338
457
  so you can feed a `SymbolicAutomaton` over integers, graph nodes, whatever —
339
458
  as long as you can write a labeling.
340
- - **The AFA-to-min-DFA pipeline actually exists now.**
341
- `nfa_from_afa` (dealternation), `determinize`
342
- (subset construction with a sink),
343
- `minimize` (Hopcroft) — all share one BDD manager
344
- and successively tighten the invariants on successor BDDs.
459
+ - **The AFA-to-min-DFA pipeline actually exists now.** `nfa_from_afa` (dealternation),
460
+ `determinize` (subset construction with a sink), `minimize` (Hopcroft) —
461
+ all share one BDD manager and successively tighten the invariants on successor BDDs.
345
462
  `SymbolicAutomaton.to_min_dfa` chains the three.
346
463
  Finite-word only for now; omega-regular determinisation is a different beast.
347
464
  - **DFA equivalence checks.**
@@ -352,19 +469,17 @@ which will be summarized below.
352
469
 
353
470
  ### Operators
354
471
 
355
- - **One per-step shape.**
356
- `SymbolicAutomaton`, `MatrixOperator`,
472
+ - **One per-step shape.** `SymbolicAutomaton`, `MatrixOperator`,
357
473
  and `PolynomialOperator` all expose the same `step(current, symbol)` / `run(word)` /
358
474
  `accepts(word)` shape.
359
475
  Each binds its alphabet at construction
360
476
  (matching how the semiring / algebra were already bound),
361
477
  so the per-call API is monomorphic and `V` is pinned end-to-end.
362
478
  Wanted symmetry between the layers; got it.
363
- - **`PolynomialOperator` evaluates lazily.**
364
- `step` evaluates guards against `alphabet.weight` on the fly,
365
- with no per-symbol precomputation
366
- important because the natural LTL alphabet is `Σ = 2^AP`,
367
- and you really don't want to materialise `2^|AP|` polynomials up front.
479
+ - **`PolynomialOperator` evaluates lazily.** `step` evaluates guards against
480
+ `alphabet.weight` on the fly, with no per-symbol precomputation — important because
481
+ the natural LTL alphabet is `Σ = 2^AP`, and you really don't want to materialise
482
+ `2^|AP|` polynomials up front.
368
483
  The AFA's row structure stays static
369
484
  (good for JAX tracing), and the alphabet decides whether to memoise.
370
485
  - **Polynomial performance.**
@@ -374,9 +489,8 @@ which will be summarized below.
374
489
 
375
490
  ### Tooling and Tests
376
491
 
377
- - **Hand-written changelogs.**
378
- `git cliff` was producing entries that needed enough editing that I might
379
- as well write them by hand.
492
+ - **Hand-written changelogs.** `git cliff` was producing entries
493
+ that needed enough editing that I might as well write them by hand.
380
494
  `ci/make-release` no longer touches `CHANGELOG.md` or tag messages.
381
495
  Run `git cliff` separately if you want a draft to crib from.
382
496
  - **Tests.**
@@ -39,20 +39,21 @@ just fmt
39
39
  # OR
40
40
  ruff format
41
41
  ruff check --output-format concise --fix --exit-non-zero-on-fix
42
-
43
- # Format + type check
44
- just lint
45
42
  ```
46
43
 
47
44
  **Type Checking** :
48
45
  ```bash
49
46
  # Run all type checkers
50
47
  just type-check
51
-
48
+ # OR
52
49
  # Run specific type checkers
53
- mypy --strict
54
- ty check --output-format concise
55
- pyrefly check --output-format min-text
50
+ zuban check
51
+ basedpyright
52
+ ```
53
+
54
+ **Formatting + Type Checking together**:
55
+ ```bash
56
+ just lint
56
57
  ```
57
58
 
58
59
  **Development Setup** :
@@ -60,7 +61,7 @@ pyrefly check --output-format min-text
60
61
  # Set up dev environment (sync dependencies)
61
62
  just dev
62
63
  # OR
63
- uv sync --frozen --inexact --dev
64
+ pixi install
64
65
 
65
66
  # For CUDA support (set CUDA_VERSION=12 or 13)
66
67
  CUDA_VERSION=12 just dev
@@ -74,7 +75,7 @@ One can also copy the included `.envrc.recommended` file to `.envrc` and use it
74
75
 
75
76
  ### Type Annotations
76
77
 
77
- - All code must pass `mypy --strict` . Use explicit type annotations.
78
+ - All code must pass `zuban` and `basedpyright`. Use explicit type annotations.
78
79
  - Use Python 3.12+ syntax: `type` aliases, `|` for unions, generic classes and functions
79
80
  with `[T]`
80
81
  - Always specify return types, including `-> None`
@@ -89,42 +90,3 @@ One can also copy the included `.envrc.recommended` file to `.envrc` and use it
89
90
  - Format: NumPy-style docstrings with sections: Parameters, Returns,
90
91
  Raises, Notes, Examples.
91
92
  - Inline comments should say _why_ something is done, not _what_.
92
-
93
- ## Source Layout
94
-
95
- ```
96
- morphata/
97
- ├── src/morphata/
98
- │ ├── automaton.py # Automaton IR + Outgoing/Step deltas
99
- │ ├── alphabet.py # Input alphabet + characteristic function
100
- │ ├── builder.py # AutomatonBuilder (mutable IR builder)
101
- │ ├── acceptance.py # Finite + omega-regular acceptance
102
- │ ├── weights.py # Guard-based weight predicates
103
- │ ├── logic/
104
- │ │ ├── ltl.py # LTL/LTLf -> AFA
105
- │ │ └── strel.py # STREL automaton (Step delta)
106
- │ ├── hoa/ # Extended HOA v1 parser
107
- │ │ ├── parser.py
108
- │ │ ├── exporter.py # placeholder; not yet implemented
109
- │ │ └── acc_expr.py
110
- │ ├── operators/ # Semiring-valued morphisms
111
- │ │ ├── matrix.py # MatrixOperator (weighted NFAs)
112
- │ │ ├── polynomial.py # PolynomialOperator (AFAs)
113
- │ │ └── _backend.py # backend resolution + JAX pytree aux
114
- │ └── symbolic/ # BDD-backed structural layer
115
- │ ├── automaton.py # SymbolicAutomaton
116
- │ ├── bdd.py # BoolExpr <-> dd.Function bridge
117
- │ ├── transforms.py # determinize, minimize, nfa_from_afa
118
- │ └── equivalence.py # language_equivalent, isomorphic, canonical_form
119
-
120
- └── tests/ # Mirrors the package layout
121
- ├── test_alphabet.py
122
- ├── test_automaton.py
123
- ├── test_builder.py
124
- ├── test_from_parsed.py
125
- ├── test_weights.py
126
- ├── hoa/
127
- ├── logic/
128
- ├── operators/
129
- └── symbolic/
130
- ```
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: morphata
3
+ Version: 2.2.0
4
+ Summary: Representation theory for automata, made practical.
5
+ Project-URL: Documentation, https://docs.anandb.dev/morphata
6
+ Project-URL: Repository, https://git.anandb.dev/morphata.git
7
+ Project-URL: Changelog, https://docs.anandb.dev/morphata/changelog.html
8
+ Author-email: Anand Balakrishnan <anandbala1597@gmail.com>
9
+ License-Expression: BSD-3-Clause
10
+ License-File: LICENSE
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Requires-Python: >=3.12
14
+ Requires-Dist: algebraic-arrays>=1.3.0
15
+ Requires-Dist: attrs>=25.4.0
16
+ Requires-Dist: cattrs>=26.1.0
17
+ Requires-Dist: dd>=0.6.0
18
+ Requires-Dist: jaxtyping>=0.3
19
+ Requires-Dist: lark>=1.3.1
20
+ Requires-Dist: logic-asts>=1.8
21
+ Requires-Dist: numpy
22
+ Requires-Dist: typing-extensions>=4.14
23
+ Provides-Extra: dot
24
+ Requires-Dist: pydot>=4.0.1; extra == 'dot'
25
+ Provides-Extra: jax
26
+ Requires-Dist: jax>=0.8; extra == 'jax'
27
+ Provides-Extra: torch
28
+ Requires-Dist: torch>=2.0; extra == 'torch'
29
+ Description-Content-Type: text/x-rst
30
+
31
+ Morphata
32
+ ========
33
+
34
+ **morphata** does representation theory for automata.
35
+ An automaton -- its states, transitions,
36
+ and acceptance condition -- is a *structural* object.
37
+ ``SymbolicAutomaton`` is the BDD-backed structural representation.
38
+ ``MatrixOperator`` and ``PolynomialOperator`` interpret that structure over
39
+ semiring and bounded-distributive-lattice domains.
40
+
41
+ It builds on `algebraic <https://docs.anandb.dev/algebraic>`_ for
42
+ backend-agnostic semiring algebra (NumPy, JAX, PyTorch).
43
+
44
+ To install the latest release of ``morphata``, install from
45
+ `PyPI <https://pypi.org/project/morphata/>`_:
46
+
47
+ .. code-block:: bash
48
+
49
+ pip install morphata
50
+
51
+ Or from the latest Git head:
52
+
53
+ .. code-block:: bash
54
+
55
+ pip install 'morphata @ git+https://git.anandb.dev/morphata.git@main'
56
+
57
+ For more, see the `documentation <https://docs.anandb.dev/morphata>`_.
58
+
59
+ .. code-block:: python
60
+
61
+ >>> import logic_asts as logic
62
+ >>> import logic_asts.ltl as ltl
63
+
64
+ >>> from morphata.alphabet import powerset_alphabet
65
+ >>> from morphata.logic import formula_to_automaton
66
+
67
+ >>> a = logic.Variable("a")
68
+ >>> aut = formula_to_automaton(
69
+ ... ltl.Eventually(a), alphabet=powerset_alphabet({"a"}), finite=True
70
+ ... )
71
+ >>> aut.accepts([set(), {"a"}])
72
+ True
73
+
74
+ Omega-regular conditions are supported structurally, but infinite-run acceptance
75
+ evaluation is not implemented. See the full documentation for details.
76
+
77
+ Citation
78
+ --------
79
+
80
+ To cite the use of this package or the papers
81
+ that are derived from it you can use the below BibTeX entries.
82
+
83
+ - For differentiable weighted automata in general:
84
+
85
+ .. code-block:: bibtex
86
+
87
+ @inproceedings{balakrishnan2024differentiable,
88
+ title = {Differentiable {{Weighted Automata}}},
89
+ booktitle = {{{ICML}} 2024 {{Workshop}} on {{Differentiable Almost Everything}}: {{Differentiable Relaxations}}, {{Algorithms}}, {{Operators}}, and {{Simulators}}},
90
+ author = {Balakrishnan, Anand and Deshmukh, Jyotirmoy V.},
91
+ year = 2024,
92
+ month = jun,
93
+ url = {https://openreview.net/forum?id=k2hIQYqHTh},
94
+ copyright = {All rights reserved},
95
+ langid = {english}
96
+ }
97
+
98
+ - For weighted automata in motion planning:
99
+
100
+ .. code-block:: bibtex
101
+
102
+ @inproceedings{balakrishnan2024motion,
103
+ title = {Motion {{Planning}} for {{Automata-based Objectives}} Using {{Efficient Gradient-based Methods}}},
104
+ booktitle = {2024 {{IEEE}}/{{RSJ International Conference}} on {{Intelligent Robots}} and {{Systems}} ({{IROS}})},
105
+ author = {Balakrishnan, Anand and Atasever, Merve and Deshmukh, Jyotirmoy V.},
106
+ year = 2024,
107
+ month = oct,
108
+ pages = {13734--13740},
109
+ issn = {2153-0866},
110
+ doi = {10.1109/IROS58592.2024.10802177}
111
+ }
112
+
113
+ - For alternating weighted automata in multi-agent systems:
114
+
115
+ .. code-block:: bibtex
116
+
117
+ @inproceedings{balakrishnan2025monitoring,
118
+ title = {Monitoring {{Spatially Distributed Cyber-Physical Systems}} with {{Alternating Finite Automata}}},
119
+ booktitle = {Proceedings of the 28th {{ACM International Conference}} on {{Hybrid Systems}}: {{Computation}} and {{Control}}},
120
+ author = {Balakrishnan, Anand and Paul, Sheryl and Silvetti, Simone and Nenzi, Laura and Deshmukh, Jyotirmoy V.},
121
+ year = 2025,
122
+ month = may,
123
+ pages = {1--11},
124
+ publisher = {ACM},
125
+ address = {Irvine CA USA},
126
+ doi = {10.1145/3716863.3718033},
127
+ isbn = {979-8-4007-1504-4},
128
+ langid = {english}
129
+ }
130
+
131
+ License
132
+ -------
133
+
134
+ See the ``LICENSE`` file for details.
@@ -0,0 +1,104 @@
1
+ Morphata
2
+ ========
3
+
4
+ **morphata** does representation theory for automata.
5
+ An automaton -- its states, transitions,
6
+ and acceptance condition -- is a *structural* object.
7
+ ``SymbolicAutomaton`` is the BDD-backed structural representation.
8
+ ``MatrixOperator`` and ``PolynomialOperator`` interpret that structure over
9
+ semiring and bounded-distributive-lattice domains.
10
+
11
+ It builds on `algebraic <https://docs.anandb.dev/algebraic>`_ for
12
+ backend-agnostic semiring algebra (NumPy, JAX, PyTorch).
13
+
14
+ To install the latest release of ``morphata``, install from
15
+ `PyPI <https://pypi.org/project/morphata/>`_:
16
+
17
+ .. code-block:: bash
18
+
19
+ pip install morphata
20
+
21
+ Or from the latest Git head:
22
+
23
+ .. code-block:: bash
24
+
25
+ pip install 'morphata @ git+https://git.anandb.dev/morphata.git@main'
26
+
27
+ For more, see the `documentation <https://docs.anandb.dev/morphata>`_.
28
+
29
+ .. code-block:: python
30
+
31
+ >>> import logic_asts as logic
32
+ >>> import logic_asts.ltl as ltl
33
+
34
+ >>> from morphata.alphabet import powerset_alphabet
35
+ >>> from morphata.logic import formula_to_automaton
36
+
37
+ >>> a = logic.Variable("a")
38
+ >>> aut = formula_to_automaton(
39
+ ... ltl.Eventually(a), alphabet=powerset_alphabet({"a"}), finite=True
40
+ ... )
41
+ >>> aut.accepts([set(), {"a"}])
42
+ True
43
+
44
+ Omega-regular conditions are supported structurally, but infinite-run acceptance
45
+ evaluation is not implemented. See the full documentation for details.
46
+
47
+ Citation
48
+ --------
49
+
50
+ To cite the use of this package or the papers
51
+ that are derived from it you can use the below BibTeX entries.
52
+
53
+ - For differentiable weighted automata in general:
54
+
55
+ .. code-block:: bibtex
56
+
57
+ @inproceedings{balakrishnan2024differentiable,
58
+ title = {Differentiable {{Weighted Automata}}},
59
+ booktitle = {{{ICML}} 2024 {{Workshop}} on {{Differentiable Almost Everything}}: {{Differentiable Relaxations}}, {{Algorithms}}, {{Operators}}, and {{Simulators}}},
60
+ author = {Balakrishnan, Anand and Deshmukh, Jyotirmoy V.},
61
+ year = 2024,
62
+ month = jun,
63
+ url = {https://openreview.net/forum?id=k2hIQYqHTh},
64
+ copyright = {All rights reserved},
65
+ langid = {english}
66
+ }
67
+
68
+ - For weighted automata in motion planning:
69
+
70
+ .. code-block:: bibtex
71
+
72
+ @inproceedings{balakrishnan2024motion,
73
+ title = {Motion {{Planning}} for {{Automata-based Objectives}} Using {{Efficient Gradient-based Methods}}},
74
+ booktitle = {2024 {{IEEE}}/{{RSJ International Conference}} on {{Intelligent Robots}} and {{Systems}} ({{IROS}})},
75
+ author = {Balakrishnan, Anand and Atasever, Merve and Deshmukh, Jyotirmoy V.},
76
+ year = 2024,
77
+ month = oct,
78
+ pages = {13734--13740},
79
+ issn = {2153-0866},
80
+ doi = {10.1109/IROS58592.2024.10802177}
81
+ }
82
+
83
+ - For alternating weighted automata in multi-agent systems:
84
+
85
+ .. code-block:: bibtex
86
+
87
+ @inproceedings{balakrishnan2025monitoring,
88
+ title = {Monitoring {{Spatially Distributed Cyber-Physical Systems}} with {{Alternating Finite Automata}}},
89
+ booktitle = {Proceedings of the 28th {{ACM International Conference}} on {{Hybrid Systems}}: {{Computation}} and {{Control}}},
90
+ author = {Balakrishnan, Anand and Paul, Sheryl and Silvetti, Simone and Nenzi, Laura and Deshmukh, Jyotirmoy V.},
91
+ year = 2025,
92
+ month = may,
93
+ pages = {1--11},
94
+ publisher = {ACM},
95
+ address = {Irvine CA USA},
96
+ doi = {10.1145/3716863.3718033},
97
+ isbn = {979-8-4007-1504-4},
98
+ langid = {english}
99
+ }
100
+
101
+ License
102
+ -------
103
+
104
+ See the ``LICENSE`` file for details.
@@ -0,0 +1,32 @@
1
+ """pytest fixtures for the morphata bench suite.
2
+
3
+ The bench/ tree is opt-in: invoke with `pytest bench/` (or
4
+ `pytest bench/test_sere_nlm_perf.py`). It is not collected by the
5
+ default `pytest` invocation.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import gc
11
+ from collections.abc import Iterator
12
+
13
+ import pytest
14
+
15
+ from morphata.symbolic.bdd import BDDManager
16
+
17
+
18
+ @pytest.fixture
19
+ def bench_mgr() -> Iterator[BDDManager[str, int]]:
20
+ """Shared BDD manager scoped to one bench test (= many benchmark rounds).
21
+
22
+ Bench tests pass this manager to ``sere_to_automaton(..., manager=mgr)``
23
+ so the per-call ``BDDManager()`` allocation is skipped. That path leaks
24
+ ~12 MB of CUDD-internal state per call, which compounds across the
25
+ ~100-1000 rounds pytest-benchmark runs per test and exhausts host
26
+ RAM. Sharing the manager keeps RSS flat.
27
+ """
28
+ manager = BDDManager[str, int]()
29
+ try:
30
+ yield manager
31
+ finally:
32
+ _ = gc.collect()