morphata 2.0.0__tar.gz → 2.0.1__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 (131) hide show
  1. {morphata-2.0.0 → morphata-2.0.1}/.claude/settings.local.json +5 -1
  2. {morphata-2.0.0 → morphata-2.0.1}/.envrc +8 -4
  3. morphata-2.0.1/.gitattributes +5 -0
  4. {morphata-2.0.0 → morphata-2.0.1}/.gitignore +3 -0
  5. {morphata-2.0.0 → morphata-2.0.1}/AGENTS.md +39 -0
  6. {morphata-2.0.0 → morphata-2.0.1}/CHANGELOG.md +44 -1
  7. {morphata-2.0.0 → morphata-2.0.1}/CONTRIBUTING.md +16 -10
  8. {morphata-2.0.0 → morphata-2.0.1}/PKG-INFO +2 -2
  9. {morphata-2.0.0 → morphata-2.0.1}/docs/api/modules.rst +2 -0
  10. morphata-2.0.1/docs/api/morphata.logic.psl.rst +15 -0
  11. morphata-2.0.1/docs/api/morphata.logic.sere.rst +9 -0
  12. {morphata-2.0.0 → morphata-2.0.1}/docs/conf.py +1 -1
  13. {morphata-2.0.0 → morphata-2.0.1}/docs/index.rst +9 -1
  14. morphata-2.0.1/justfile +70 -0
  15. morphata-2.0.1/pixi.lock +5923 -0
  16. morphata-2.0.1/pixi.toml +114 -0
  17. {morphata-2.0.0 → morphata-2.0.1}/pyproject.toml +3 -2
  18. morphata-2.0.1/src/morphata/logic/_common.py +72 -0
  19. morphata-2.0.1/src/morphata/logic/ltl.py +499 -0
  20. morphata-2.0.1/src/morphata/logic/psl.py +495 -0
  21. morphata-2.0.1/src/morphata/logic/sere.py +403 -0
  22. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/operators/matrix.py +3 -1
  23. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/operators/polynomial.py +3 -1
  24. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/symbolic/automaton.py +1 -1
  25. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/symbolic/bdd.py +224 -14
  26. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/symbolic/transforms.py +77 -68
  27. {morphata-2.0.0/tests/symbolic → morphata-2.0.1/tests}/conftest.py +2 -2
  28. {morphata-2.0.0 → morphata-2.0.1}/tests/logic/test_ltl.py +122 -69
  29. morphata-2.0.1/tests/logic/test_psl.py +230 -0
  30. morphata-2.0.1/tests/logic/test_sere.py +236 -0
  31. {morphata-2.0.0 → morphata-2.0.1}/tests/operators/test_matrix_from_ltl.py +7 -6
  32. {morphata-2.0.0 → morphata-2.0.1}/tests/operators/test_polynomial_from_ir.py +5 -4
  33. morphata-2.0.1/tests/symbolic/test_bdd_helpers.py +277 -0
  34. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_from_hoaf.py +2 -2
  35. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_ltlf2dfa_equivalence.py +1 -1
  36. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_step.py +8 -7
  37. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_symbolic_automaton.py +26 -1
  38. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_symbolic_from_ir.py +7 -6
  39. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_transforms.py +47 -0
  40. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_transforms_ir.py +5 -4
  41. {morphata-2.0.0 → morphata-2.0.1}/tests/symbolic/test_transforms_properties.py +45 -21
  42. {morphata-2.0.0 → morphata-2.0.1}/uv.lock +105 -81
  43. morphata-2.0.0/.gitattributes +0 -3
  44. morphata-2.0.0/docs/changelog.md +0 -4
  45. morphata-2.0.0/justfile +0 -54
  46. morphata-2.0.0/src/morphata/logic/ltl.py +0 -448
  47. morphata-2.0.0/tests/symbolic/test_bdd_helpers.py +0 -143
  48. {morphata-2.0.0 → morphata-2.0.1}/.basedpyright/baseline.json +0 -0
  49. {morphata-2.0.0 → morphata-2.0.1}/.dockerignore +0 -0
  50. {morphata-2.0.0 → morphata-2.0.1}/.editorconfig +0 -0
  51. {morphata-2.0.0 → morphata-2.0.1}/.envrc.recommended +0 -0
  52. {morphata-2.0.0 → morphata-2.0.1}/.fdignore +0 -0
  53. {morphata-2.0.0 → morphata-2.0.1}/.mailmap +0 -0
  54. {morphata-2.0.0 → morphata-2.0.1}/.python-version +0 -0
  55. {morphata-2.0.0 → morphata-2.0.1}/.rstcheck.cfg +0 -0
  56. {morphata-2.0.0 → morphata-2.0.1}/CLAUDE.md +0 -0
  57. {morphata-2.0.0 → morphata-2.0.1}/LICENSE +0 -0
  58. {morphata-2.0.0 → morphata-2.0.1}/README.md +0 -0
  59. {morphata-2.0.0 → morphata-2.0.1}/ci/make-release +0 -0
  60. {morphata-2.0.0 → morphata-2.0.1}/cliff.toml +0 -0
  61. {morphata-2.0.0 → morphata-2.0.1}/docs/_static/navigation.html +0 -0
  62. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.acceptance.rst +0 -0
  63. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.alphabet.rst +0 -0
  64. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.automaton.rst +0 -0
  65. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.builder.rst +0 -0
  66. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.hoa.rst +0 -0
  67. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.logic.ltl.rst +0 -0
  68. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.logic.strel.rst +0 -0
  69. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.operators.matrix.rst +0 -0
  70. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.operators.polynomial.rst +0 -0
  71. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.operators.rst +0 -0
  72. {morphata-2.0.0 → morphata-2.0.1}/docs/api/morphata.symbolic.rst +0 -0
  73. {morphata-2.0.0 → morphata-2.0.1}/docs/concepts/acceptance.rst +0 -0
  74. {morphata-2.0.0 → morphata-2.0.1}/docs/concepts/hoa.rst +0 -0
  75. {morphata-2.0.0 → morphata-2.0.1}/docs/concepts/index.rst +0 -0
  76. {morphata-2.0.0 → morphata-2.0.1}/docs/concepts/operators.rst +0 -0
  77. {morphata-2.0.0 → morphata-2.0.1}/docs/concepts/spec.rst +0 -0
  78. {morphata-2.0.0 → morphata-2.0.1}/docs/concepts/weights.rst +0 -0
  79. {morphata-2.0.0 → morphata-2.0.1}/docs/quick-start.rst +0 -0
  80. {morphata-2.0.0 → morphata-2.0.1}/docs/symbolic-transforms.rst +0 -0
  81. {morphata-2.0.0 → morphata-2.0.1}/mypy.ini +0 -0
  82. {morphata-2.0.0 → morphata-2.0.1}/project.utf-8.add +0 -0
  83. {morphata-2.0.0 → morphata-2.0.1}/project.utf-8.add.spl +0 -0
  84. {morphata-2.0.0 → morphata-2.0.1}/pyrefly.toml +0 -0
  85. {morphata-2.0.0 → morphata-2.0.1}/pyrightconfig.json +0 -0
  86. {morphata-2.0.0 → morphata-2.0.1}/pytest.toml +0 -0
  87. {morphata-2.0.0 → morphata-2.0.1}/ruff.toml +0 -0
  88. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/__init__.py +0 -0
  89. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/acceptance.py +0 -0
  90. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/alphabet.py +0 -0
  91. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/automaton.py +0 -0
  92. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/builder.py +0 -0
  93. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/hoa/__init__.py +0 -0
  94. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/hoa/__main__.py +0 -0
  95. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/hoa/acc_expr.py +0 -0
  96. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/hoa/exporter.py +0 -0
  97. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/hoa/hoa.lark +0 -0
  98. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/hoa/parser.py +0 -0
  99. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/logic/__init__.py +0 -0
  100. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/logic/strel.py +0 -0
  101. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/operators/__init__.py +0 -0
  102. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/operators/_backend.py +0 -0
  103. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/py.typed +0 -0
  104. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/symbolic/__init__.py +0 -0
  105. {morphata-2.0.0 → morphata-2.0.1}/src/morphata/symbolic/equivalence.py +0 -0
  106. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut1.hoa +0 -0
  107. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut11.hoa +0 -0
  108. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut2.hoa +0 -0
  109. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut3.2.hoa +0 -0
  110. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut3.hoa +0 -0
  111. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut4.hoa +0 -0
  112. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut5.hoa +0 -0
  113. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut6.hoa +0 -0
  114. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut7.hoa +0 -0
  115. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/aut8.hoa +0 -0
  116. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/finite_aut.hoa +0 -0
  117. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/gen_buchi_3.hoa +0 -0
  118. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/gen_cobuchi_2.hoa +0 -0
  119. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/rabin_2pair.hoa +0 -0
  120. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/streett_2pair.hoa +0 -0
  121. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/test_exporter_basic.py +0 -0
  122. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/test_exporter_roundtrip.py +0 -0
  123. {morphata-2.0.0 → morphata-2.0.1}/tests/hoa/test_parser.py +0 -0
  124. {morphata-2.0.0 → morphata-2.0.1}/tests/logic/__init__.py +0 -0
  125. {morphata-2.0.0 → morphata-2.0.1}/tests/logic/test_strel.py +0 -0
  126. {morphata-2.0.0 → morphata-2.0.1}/tests/operators/test_matrix_from_ir.py +0 -0
  127. {morphata-2.0.0 → morphata-2.0.1}/tests/test_alphabet.py +0 -0
  128. {morphata-2.0.0 → morphata-2.0.1}/tests/test_automaton.py +0 -0
  129. {morphata-2.0.0 → morphata-2.0.1}/tests/test_builder.py +0 -0
  130. {morphata-2.0.0 → morphata-2.0.1}/tests/test_from_parsed.py +0 -0
  131. {morphata-2.0.0 → morphata-2.0.1}/ty.toml +0 -0
@@ -11,7 +11,11 @@
11
11
  "Bash(just test *)",
12
12
  "Bash(rg *)",
13
13
  "Bash(uv run pytest *)",
14
- "Bash(uv run mypy *)"
14
+ "Bash(uv run mypy *)",
15
+ "Bash(.venv/bin/python -m pytest *)",
16
+ "Skill(superpowers:writing-plans)",
17
+ "Skill(superpowers:subagent-driven-development)",
18
+ "Bash(grep -v \"AssertionError\\\\|Traceback\\\\|File \\\\|^\\\\s*$\")"
15
19
  ]
16
20
  }
17
21
  }
@@ -12,15 +12,19 @@ if [[ -z "${DEVJAIL:-}" ]] && nvidia_smi="$(type -p "nvidia-smi")" && [[ -n "$nv
12
12
  if [[ -n "${cuda_major_version:-}" ]]; then
13
13
  info "Detected CUDA version: $cuda_major_version"
14
14
  export CUDA_VERSION="$cuda_major_version"
15
+ PIXI_ENV="cu$CUDA_VERSION"
15
16
  fi
16
17
  else
17
18
  info "Did not detect nvidia-smi, using non-GPU environment"
19
+ PIXI_ENV="default"
18
20
  fi
21
+ export PIXI_ENV
19
22
 
20
23
  dotenv_if_exists
21
24
 
22
- if [[ -z "${DEVJAIL:-}" ]] || [[ ! -e ".venv/bin/activate" ]]; then
23
- uvx --from rust-just just dev
25
+ watch_file pixi.lock
26
+ eval "$(pixi shell-hook -e "$PIXI_ENV")"
27
+
28
+ if [[ -d "$CONDA_PREFIX" ]]; then
29
+ export VIRTUAL_ENV="$CONDA_PREFIX"
24
30
  fi
25
- source ./.venv/bin/activate
26
- watch_file pyproject.toml
@@ -0,0 +1,5 @@
1
+ # GitHub syntax highlighting
2
+ pixi.lock linguist-language=YAML
3
+
4
+ # SCM syntax highlighting & preventing 3-way merges
5
+ pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
@@ -257,3 +257,6 @@ $RECYCLE.BIN/
257
257
  *.lnk
258
258
 
259
259
  # End of https://www.toptal.com/developers/gitignore/api/macos,windows,linux
260
+ # pixi environments
261
+ .pixi/*
262
+ !.pixi/config.toml
@@ -4,6 +4,14 @@
4
4
  It packages structural automaton representations together with semiring-valued
5
5
  *operators* that turn an automaton into a computable interpretation.
6
6
 
7
+ ## Development Environment
8
+
9
+ The development shell already has the project virtual environment activated,
10
+ so `pytest`, `mypy`, `ruff`, `sphinx-build`, etc. are on `PATH` directly.
11
+ **Do not** prefix commands with `uv run`, `pixi run`, `poetry run`, or similar.
12
+ Just invoke the tool. If a tool is missing, stop and tell the user rather than
13
+ trying to bootstrap or reinstall the environment.
14
+
7
15
  ## Core Architecture
8
16
 
9
17
  ### IR layer (`morphata.automaton`, `morphata.alphabet`, `morphata.acceptance`)
@@ -85,6 +93,21 @@ delta - the transition consumes the labelled graph eagerly, so STREL
85
93
  automata are not symbolically liftable. Operators: Reach, Escape,
86
94
  Somewhere, Everywhere. Boolean-only.
87
95
 
96
+ **`morphata.logic.sere.sere_to_automaton(expr)`** : SERE -> alternating
97
+ finite automaton. Supports ``Concat``, ``Fusion``, ``Repeat`` (bounded
98
+ and unbounded), ``Inter``, ``Alt``, and Boolean leaves over AP.
99
+ Acceptance is always ``Finite``; the accepting-state set is exactly
100
+ the *nullable* states (those that match the empty word).
101
+
102
+ **`morphata.logic.psl.psl_to_automaton(phi, *, finite=False)`** : PSL ->
103
+ alternating automaton. Wraps pure-LTL subformulas in an internal
104
+ ``_LTL`` tag and dispatches to the LTL expansion rule; closure
105
+ operators (``{r}!``, ``{r}``, ``!{r}``, ``{r}<>-> f``, ``{r}[]-> f``)
106
+ become their own tagged states with SERE-step expansion. Suffix
107
+ implications follow Spot's overlapping semantics: the last symbol of
108
+ ``r`` and the first position of ``f`` coincide. ``finite=True`` ->
109
+ ``Finite`` acceptance (PSLf); ``finite=False`` -> ``Buchi``.
110
+
88
111
  Hand-written automata are built with ``AutomatonBuilder``; the package
89
112
  has no separate ``constructions`` namespace.
90
113
 
@@ -211,6 +234,18 @@ is backend-agnostic via `backend=`.
211
234
  sets of transitions. The HOA parser ingests ``{n}`` markers from
212
235
  ``State:`` declarations; per-edge ``{n}`` markers are ignored. Convert
213
236
  transition-based HOA files to state-based form before loading them.
237
+ - ``psl_to_automaton`` requires the continuation of any
238
+ ``SuffixImpliesExist`` / ``SuffixImpliesUniv`` to be a pure-LTL
239
+ formula in v1. Nested PSL closures inside a suffix-implication
240
+ continuation raise ``NotImplementedError``. Likewise, LTL temporal
241
+ operators wrapping a PSL closure at the top level
242
+ (e.g. ``Always(StrongClosure(r))``) are not yet decomposed; lift the
243
+ PSL fragment out of the LTL temporal operator before calling.
244
+ - The PSL Buchi acceptance classification is the natural per-tag rule
245
+ (strong-closure non-accepting, weak-closure accepting, etc.). It has
246
+ not been cross-checked against a published reference for every
247
+ combination of operators; consult ``docs/superpowers/specs/`` before
248
+ relying on omega-language semantics in production.
214
249
 
215
250
  ## Testing
216
251
 
@@ -334,6 +369,10 @@ matrix_product = algebraic.matmul(arr1, arr2)
334
369
  - `src/morphata/builder.py` : ``AutomatonBuilder``.
335
370
  - `src/morphata/acceptance.py` : expression-based acceptance conditions.
336
371
  - `src/morphata/logic/ltl.py` : LTL/LTLf -> AFA conversion.
372
+ - `src/morphata/logic/sere.py` : SERE -> AFA conversion.
373
+ - `src/morphata/logic/psl.py` : PSL -> AFA conversion.
374
+ - `src/morphata/logic/_common.py` : shared BDD scratch-space setup used
375
+ by all three logic converters.
337
376
  - `src/morphata/logic/strel.py` : STREL automaton (``Step`` delta).
338
377
  - `src/morphata/hoa/` : HOA v1 parser, exporter, grammar.
339
378
  - `src/morphata/operators/matrix.py` : ``MatrixOperator``.
@@ -1,6 +1,49 @@
1
1
  # Changelog
2
2
 
3
- ## 2.0.0 — [Unreleased]
3
+ ## Unreleased
4
+
5
+ ### Added
6
+
7
+ - `morphata.logic.sere.sere_to_automaton(formula)` — converts a
8
+ SERE expression to an alternating finite automaton. Supports
9
+ `Concat`, `Fusion`, `Alt`, `Inter` (length-matching), `Repeat`
10
+ (bounded and unbounded), and Boolean leaves (`Literal`, `Variable`,
11
+ `Not`, `And`, `Or`).
12
+ - `morphata.logic.psl.psl_to_automaton(phi, *, finite=False)` —
13
+ converts a PSL expression to an alternating automaton, with
14
+ `Finite` acceptance for PSLf (`finite=True`) and `Büchi` acceptance
15
+ for full PSL (`finite=False`). Supports the strong / weak /
16
+ negated-strong closure operators and existential / universal
17
+ suffix implication. Suffix implications follow Spot's overlapping
18
+ semantics: the last symbol matched by the SERE prefix is shared
19
+ with the first position at which the continuation is evaluated.
20
+
21
+ ### Changed
22
+
23
+ - `morphata.logic.ltl` factored its per-call BDD scratch-space
24
+ construction into a shared helper
25
+ `morphata.logic._common.make_logic_context`, reused by the SERE
26
+ and PSL converters. Two LTL helpers (`_aut_symbolic_expansion`,
27
+ `_empty_trace_value`) were renamed to `ltl_symbolic_expansion` /
28
+ `ltl_empty_trace_value` so PSL can delegate to them for pure-LTL
29
+ subformulas.
30
+
31
+ ### Known limitations
32
+
33
+ - `psl_to_automaton` does not yet decompose LTL temporal operators
34
+ that wrap PSL closures at the top level
35
+ (e.g. `Always(StrongClosure(r))`). Lift the PSL fragment out of
36
+ the surrounding LTL temporal operator before calling.
37
+ - The continuation of a `SuffixImpliesExist` / `SuffixImpliesUniv`
38
+ must be a pure-LTL formula; nested PSL closures inside a
39
+ continuation raise `NotImplementedError`.
40
+ - The Büchi acceptance classification for PSL has not been
41
+ cross-checked against a published reference for every operator
42
+ combination; finite-trace (PSLf) acceptance is exercised end-to-end
43
+ via `SymbolicAutomaton.accepts` and is high-confidence, but Büchi
44
+ is currently only smoke-tested for construction.
45
+
46
+ ## 2.0.0 — 2026-05-23
4
47
 
5
48
  The major version bump folds the old `automatix` package into `morphata`
6
49
  and replaces the constellation automata classes with a single typed intermediate
@@ -6,24 +6,30 @@ The `justfile` defines a set of build, lint, and test commands, which can direct
6
6
  run as below:
7
7
 
8
8
 
9
+ The examples below assume the project virtual environment is activated (either
10
+ via `direnv` and `.envrc`, or by sourcing `.venv/bin/activate` manually). With
11
+ the venv active the tools are on `PATH` directly; no `uv run` prefix is needed.
12
+ If you'd rather not activate, prefix each command with `uv run --dev --frozen`
13
+ (or use the `just` recipes, which handle this for you).
14
+
9
15
  **Testing** :
10
16
  ```bash
11
17
  # Run all tests (uses --lf for last-failed)
12
18
  just test
13
19
  # OR
14
- uv run --dev --frozen pytest --lf
20
+ pytest --lf
15
21
 
16
22
  # Run all tests verbosely without --lf
17
- uv run --dev --frozen pytest -v
23
+ pytest -v
18
24
 
19
25
  # Run a single test file
20
- uv run --dev --frozen pytest tests/test_weights.py -v
26
+ pytest tests/test_alphabet.py -v
21
27
 
22
28
  # Run a single test function
23
- uv run --dev --frozen pytest tests/test_weights.py::TestWeightFunctionBasics::test_constant_weight_function -v
29
+ pytest tests/test_alphabet.py::TestBooleanAlphabet::test_powerset_alphabet -v
24
30
 
25
31
  # Run with coverage
26
- uv run --dev --frozen pytest --cov=morphata --cov-report=term
32
+ pytest --cov=morphata --cov-report=term
27
33
  ```
28
34
 
29
35
  **Linting and Formatting** :
@@ -31,8 +37,8 @@ uv run --dev --frozen pytest --cov=morphata --cov-report=term
31
37
  # Format and lint (fixes issues automatically)
32
38
  just fmt
33
39
  # OR
34
- uv run --frozen ruff format
35
- uv run --frozen ruff check --output-format concise --fix --exit-non-zero-on-fix
40
+ ruff format
41
+ ruff check --output-format concise --fix --exit-non-zero-on-fix
36
42
 
37
43
  # Format + type check
38
44
  just lint
@@ -44,9 +50,9 @@ just lint
44
50
  just type-check
45
51
 
46
52
  # Run specific type checkers
47
- uv run --frozen mypy --strict
48
- uv run --frozen ty check --output-format concise
49
- uv run --frozen pyrefly check --output-format min-text
53
+ mypy --strict
54
+ ty check --output-format concise
55
+ pyrefly check --output-format min-text
50
56
  ```
51
57
 
52
58
  **Development Setup** :
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphata
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Representation theory for automata, made practical.
5
5
  Project-URL: Documentation, https://docs.anandb.dev/morphata
6
6
  Project-URL: Repository, https://git.anandb.dev/morphata.git
@@ -16,7 +16,7 @@ Requires-Dist: attrs>=25.4.0
16
16
  Requires-Dist: dd>=0.6.0
17
17
  Requires-Dist: jaxtyping>=0.3
18
18
  Requires-Dist: lark>=1.3.1
19
- Requires-Dist: logic-asts>=1.4.1
19
+ Requires-Dist: logic-asts>=1.6.0
20
20
  Requires-Dist: networkx
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: types-networkx
@@ -13,6 +13,8 @@
13
13
  morphata.acceptance
14
14
  morphata.hoa
15
15
  morphata.logic.ltl
16
+ morphata.logic.sere
17
+ morphata.logic.psl
16
18
  morphata.logic.strel
17
19
  morphata.operators
18
20
  morphata.operators.matrix
@@ -0,0 +1,15 @@
1
+ PSL
2
+ ===
3
+
4
+ Property Specification Language to Alternating Automaton conversion.
5
+
6
+ Finite-trace (PSLf) and omega-trace (Büchi) acceptance are both
7
+ supported via the ``finite`` keyword argument to
8
+ :func:`~morphata.logic.psl.psl_to_automaton`. Suffix implications
9
+ follow Spot's overlapping semantics: the last symbol matched by the
10
+ SERE prefix is shared with the first position at which the
11
+ continuation is evaluated.
12
+
13
+ .. automodule:: morphata.logic.psl
14
+ :members:
15
+ :show-inheritance:
@@ -0,0 +1,9 @@
1
+ SERE
2
+ ====
3
+
4
+ Sequential Extended Regular Expression to Alternating Finite Automaton
5
+ conversion.
6
+
7
+ .. automodule:: morphata.logic.sere
8
+ :members:
9
+ :show-inheritance:
@@ -27,7 +27,7 @@ extensions = [
27
27
  ]
28
28
 
29
29
  templates_path = ["_templates"]
30
- exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
30
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "superpowers"]
31
31
 
32
32
  autodoc_default_options = {
33
33
  "members": True,
@@ -30,6 +30,15 @@ Features
30
30
  automata.
31
31
  - LTL/LTLf to alternating Büchi / finite automata in
32
32
  :mod:`morphata.logic.ltl`.
33
+ - SERE (Sequential Extended Regular Expressions) to alternating
34
+ finite automata in :mod:`morphata.logic.sere`. Supports
35
+ concatenation, fusion, alternation, length-matching intersection,
36
+ bounded and unbounded repetition, and Boolean leaves.
37
+ - PSL (Property Specification Language) to alternating automata in
38
+ :mod:`morphata.logic.psl`. Both finite-trace (PSLf) and Büchi
39
+ semantics, covering strong / weak / negated-strong closures and
40
+ existential / universal suffix implication (Spot overlapping
41
+ semantics).
33
42
  - Spatio-Temporal Reach and Escape Logic (STREL) over labelled
34
43
  graphs in :mod:`morphata.logic.strel`.
35
44
 
@@ -128,4 +137,3 @@ For alternating weighted automata in multi-agent systems:
128
137
  symbolic-transforms
129
138
  concepts/index
130
139
  api/modules
131
- changelog
@@ -0,0 +1,70 @@
1
+ # Set shell options for safety
2
+
3
+ set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
4
+ set unstable
5
+
6
+ # If we want to use CUDA, the CUDA_VERSION variable should not be empty and contain the
7
+ # version number (either 12 or 13)
8
+
9
+ CUDA_VERSION := env("CUDA_VERSION", "12")
10
+ [private]
11
+ _env := if which("nvidia-smi") == "" { "default" } else { "cu" + CUDA_VERSION }
12
+ PIXI_ENV := env("PIXI_ENV", _env)
13
+ DEFAULT_PIXI_ARGS := "--environment " + PIXI_ENV
14
+
15
+ export PIXI_FROZEN := env("PIXI_FROZEN", "true")
16
+
17
+ # Default: create the dev environment
18
+ default: dev
19
+
20
+ # Set up development environment
21
+ dev: sync-venv
22
+
23
+ # Format and lint code
24
+ [no-cd]
25
+ fmt:
26
+ ruff format
27
+ ruff check --output-format concise --fix --exit-non-zero-on-fix .
28
+
29
+ # Run type checkers
30
+ [no-cd]
31
+ [private]
32
+ ty-check:
33
+ ty check --output-format concise
34
+
35
+ [no-cd]
36
+ [private]
37
+ pyrefly-check:
38
+ pyrefly check --output-format min-text
39
+
40
+ [no-cd]
41
+ [private]
42
+ mypy-check:
43
+ mypy --strict
44
+
45
+ [no-cd]
46
+ [private]
47
+ pyright-check:
48
+ basedpyright
49
+
50
+ # [parallel]
51
+ type-check: mypy-check
52
+
53
+ # pyright-check
54
+ # ty-check pyrefly-check
55
+
56
+ # Run both formatting and type checking
57
+ [no-cd]
58
+ lint: fmt type-check
59
+
60
+ # Run tests
61
+ [no-cd]
62
+ test:
63
+ pytest --lf
64
+
65
+ docs:
66
+ sphinx-build -b html docs/ docs/_build/html
67
+
68
+ # Sync virtual environment
69
+ sync-venv:
70
+ pixi install {{ DEFAULT_PIXI_ARGS }}