morphata 2.1.0__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.
- {morphata-2.1.0 → morphata-2.2.0}/.envrc +2 -2
- {morphata-2.1.0 → morphata-2.2.0}/.rstcheck.cfg +2 -0
- morphata-2.2.0/AGENTS.md +40 -0
- {morphata-2.1.0 → morphata-2.2.0}/CHANGELOG.md +122 -44
- morphata-2.2.0/PKG-INFO +134 -0
- morphata-2.2.0/README.rst +104 -0
- morphata-2.2.0/bench/conftest.py +32 -0
- {morphata-2.1.0 → morphata-2.2.0}/bench/test_equivalence_perf.py +11 -19
- {morphata-2.1.0 → morphata-2.2.0}/bench/test_hoa_exporter_perf.py +48 -37
- {morphata-2.1.0 → morphata-2.2.0}/bench/test_hoa_parser_perf.py +7 -5
- morphata-2.2.0/bench/test_sere_nlm_perf.py +107 -0
- morphata-2.2.0/bench/test_transforms_perf.py +120 -0
- morphata-2.2.0/docs/Makefile +20 -0
- {morphata-2.1.0 → morphata-2.2.0}/docs/api/modules.rst +6 -11
- morphata-2.2.0/docs/api/morphata.acc_expr.rst +6 -0
- morphata-2.2.0/docs/api/morphata.acceptance.rst +6 -0
- morphata-2.2.0/docs/api/morphata.alphabet.rst +6 -0
- morphata-2.2.0/docs/api/morphata.builder.rst +6 -0
- morphata-2.2.0/docs/api/morphata.hoa.rst +43 -0
- morphata-2.2.0/docs/api/morphata.logic.rst +11 -0
- morphata-2.2.0/docs/api/morphata.operators.rst +12 -0
- morphata-2.2.0/docs/api/morphata.symbolic.rst +38 -0
- morphata-2.2.0/docs/changelog.md +2 -0
- {morphata-2.1.0 → morphata-2.2.0}/docs/concepts/acceptance.rst +26 -13
- morphata-2.2.0/docs/concepts/hoa.rst +138 -0
- {morphata-2.1.0 → morphata-2.2.0}/docs/concepts/index.rst +3 -1
- morphata-2.2.0/docs/concepts/operators.rst +229 -0
- morphata-2.2.0/docs/concepts/symbolic.rst +99 -0
- morphata-2.2.0/docs/concepts/weights.rst +150 -0
- morphata-2.2.0/docs/conf.py +186 -0
- morphata-2.2.0/docs/index.rst +135 -0
- morphata-2.2.0/docs/quick-start.rst +221 -0
- {morphata-2.1.0 → morphata-2.2.0}/justfile +1 -0
- {morphata-2.1.0 → morphata-2.2.0}/pixi.lock +3098 -989
- {morphata-2.1.0 → morphata-2.2.0}/pixi.toml +10 -7
- {morphata-2.1.0 → morphata-2.2.0}/pyproject.toml +3 -5
- {morphata-2.1.0 → morphata-2.2.0}/pytest.toml +2 -1
- morphata-2.2.0/rules/no-derivative-multiarg.yml +11 -0
- morphata-2.2.0/rules/no-typing-as-ty.yml +8 -0
- morphata-2.2.0/sgconfig.yml +2 -0
- morphata-2.2.0/src/morphata/__init__.py +21 -0
- {morphata-2.1.0/src/morphata/hoa → morphata-2.2.0/src/morphata}/acc_expr.py +39 -8
- morphata-2.2.0/src/morphata/acceptance.py +1174 -0
- morphata-2.2.0/src/morphata/alphabet.py +92 -0
- morphata-2.2.0/src/morphata/builder.py +190 -0
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/hoa/__init__.py +4 -14
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/hoa/parser.py +102 -2
- morphata-2.2.0/src/morphata/logic/__init__.py +14 -0
- morphata-2.2.0/src/morphata/logic/__init__.pyi +25 -0
- morphata-2.2.0/src/morphata/logic/_common.py +383 -0
- morphata-2.2.0/src/morphata/logic/ltl.py +109 -0
- morphata-2.2.0/src/morphata/logic/psl.py +75 -0
- morphata-2.2.0/src/morphata/logic/sere.py +201 -0
- morphata-2.2.0/src/morphata/operators/matrix.py +326 -0
- morphata-2.2.0/src/morphata/operators/polynomial.py +438 -0
- morphata-2.2.0/src/morphata/symbolic/__init__.py +14 -0
- morphata-2.2.0/src/morphata/symbolic/automaton.py +811 -0
- morphata-2.2.0/src/morphata/symbolic/bdd.py +1162 -0
- morphata-2.2.0/src/morphata/symbolic/utils.py +718 -0
- morphata-2.2.0/src/morphata/utils.py +200 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/conftest.py +43 -29
- morphata-2.2.0/tests/hoa/test_exporter.py +230 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/logic/test_ltl.py +76 -159
- morphata-2.2.0/tests/logic/test_psl.py +176 -0
- morphata-2.2.0/tests/logic/test_sere.py +381 -0
- morphata-2.2.0/tests/operators/test_matrix.py +328 -0
- morphata-2.1.0/tests/operators/test_polynomial_from_ir.py → morphata-2.2.0/tests/operators/test_polynomial.py +51 -34
- morphata-2.2.0/tests/symbolic/test_bdd_helpers.py +652 -0
- morphata-2.2.0/tests/symbolic/test_compose.py +177 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/symbolic/test_from_hoaf.py +31 -3
- morphata-2.2.0/tests/symbolic/test_language_equivalence.py +156 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/symbolic/test_ltlf2dfa_equivalence.py +35 -37
- morphata-2.2.0/tests/symbolic/test_symbolic_automaton.py +385 -0
- morphata-2.2.0/tests/symbolic/test_to_hoa.py +97 -0
- morphata-2.2.0/tests/symbolic/test_transforms.py +530 -0
- morphata-2.2.0/tests/test_acceptance_validation.py +79 -0
- morphata-2.2.0/tests/test_alphabet.py +50 -0
- morphata-2.2.0/tests/test_builder.py +138 -0
- morphata-2.2.0/uv.lock +3358 -0
- morphata-2.1.0/AGENTS.md +0 -421
- morphata-2.1.0/PKG-INFO +0 -138
- morphata-2.1.0/README.md +0 -106
- morphata-2.1.0/bench/conftest.py +0 -55
- morphata-2.1.0/bench/test_sere_nlm_perf.py +0 -99
- morphata-2.1.0/bench/test_successors_for_alphabet_perf.py +0 -124
- morphata-2.1.0/cliff.toml +0 -59
- morphata-2.1.0/docs/api/morphata.acceptance.rst +0 -8
- morphata-2.1.0/docs/api/morphata.alphabet.rst +0 -8
- morphata-2.1.0/docs/api/morphata.automaton.rst +0 -11
- morphata-2.1.0/docs/api/morphata.builder.rst +0 -8
- morphata-2.1.0/docs/api/morphata.hoa.rst +0 -29
- morphata-2.1.0/docs/api/morphata.logic.ltl.rst +0 -8
- morphata-2.1.0/docs/api/morphata.logic.psl.rst +0 -15
- morphata-2.1.0/docs/api/morphata.logic.sere.rst +0 -9
- morphata-2.1.0/docs/api/morphata.logic.strel.rst +0 -8
- morphata-2.1.0/docs/api/morphata.operators.matrix.rst +0 -8
- morphata-2.1.0/docs/api/morphata.operators.polynomial.rst +0 -9
- morphata-2.1.0/docs/api/morphata.operators.rst +0 -9
- morphata-2.1.0/docs/api/morphata.symbolic.rst +0 -48
- morphata-2.1.0/docs/concepts/hoa.rst +0 -119
- morphata-2.1.0/docs/concepts/operators.rst +0 -184
- morphata-2.1.0/docs/concepts/spec.rst +0 -133
- morphata-2.1.0/docs/concepts/weights.rst +0 -167
- morphata-2.1.0/docs/conf.py +0 -71
- morphata-2.1.0/docs/index.rst +0 -139
- morphata-2.1.0/docs/quick-start.rst +0 -139
- morphata-2.1.0/docs/symbolic-transforms.rst +0 -208
- morphata-2.1.0/src/morphata/__init__.py +0 -29
- morphata-2.1.0/src/morphata/acceptance.py +0 -565
- morphata-2.1.0/src/morphata/alphabet.py +0 -178
- morphata-2.1.0/src/morphata/automaton.py +0 -345
- morphata-2.1.0/src/morphata/builder.py +0 -159
- morphata-2.1.0/src/morphata/hoa/exporter.py +0 -797
- morphata-2.1.0/src/morphata/logic/__init__.py +0 -15
- morphata-2.1.0/src/morphata/logic/_common.py +0 -325
- morphata-2.1.0/src/morphata/logic/ltl.py +0 -268
- morphata-2.1.0/src/morphata/logic/psl.py +0 -319
- morphata-2.1.0/src/morphata/logic/sere.py +0 -436
- morphata-2.1.0/src/morphata/logic/strel.py +0 -488
- morphata-2.1.0/src/morphata/operators/matrix.py +0 -308
- morphata-2.1.0/src/morphata/operators/polynomial.py +0 -357
- morphata-2.1.0/src/morphata/symbolic/__init__.py +0 -57
- morphata-2.1.0/src/morphata/symbolic/automaton.py +0 -623
- morphata-2.1.0/src/morphata/symbolic/bdd.py +0 -941
- morphata-2.1.0/src/morphata/symbolic/compose.py +0 -506
- morphata-2.1.0/src/morphata/symbolic/equivalence.py +0 -199
- morphata-2.1.0/src/morphata/symbolic/persistence.py +0 -470
- morphata-2.1.0/src/morphata/symbolic/transforms.py +0 -861
- morphata-2.1.0/src/morphata/utils.py +0 -74
- morphata-2.1.0/tests/hoa/test_exporter_basic.py +0 -125
- morphata-2.1.0/tests/hoa/test_exporter_roundtrip.py +0 -43
- morphata-2.1.0/tests/hoa/test_exporter_streaming.py +0 -310
- morphata-2.1.0/tests/logic/test_psl.py +0 -196
- morphata-2.1.0/tests/logic/test_sere.py +0 -547
- morphata-2.1.0/tests/logic/test_sere_properties.py +0 -152
- morphata-2.1.0/tests/logic/test_strel.py +0 -316
- morphata-2.1.0/tests/operators/test_matrix_from_ir.py +0 -249
- morphata-2.1.0/tests/operators/test_matrix_from_ltl.py +0 -68
- morphata-2.1.0/tests/symbolic/test_alphabet_aware_transitions.py +0 -174
- morphata-2.1.0/tests/symbolic/test_bdd_helpers.py +0 -318
- morphata-2.1.0/tests/symbolic/test_compose.py +0 -449
- morphata-2.1.0/tests/symbolic/test_composition_map.py +0 -312
- morphata-2.1.0/tests/symbolic/test_equivalence_naive_property.py +0 -138
- morphata-2.1.0/tests/symbolic/test_persistence.py +0 -308
- morphata-2.1.0/tests/symbolic/test_prune.py +0 -280
- morphata-2.1.0/tests/symbolic/test_step.py +0 -77
- morphata-2.1.0/tests/symbolic/test_symbolic_automaton.py +0 -459
- morphata-2.1.0/tests/symbolic/test_symbolic_from_ir.py +0 -55
- morphata-2.1.0/tests/symbolic/test_to_hoa.py +0 -176
- morphata-2.1.0/tests/symbolic/test_transforms.py +0 -451
- morphata-2.1.0/tests/symbolic/test_transforms_ir.py +0 -41
- morphata-2.1.0/tests/symbolic/test_transforms_properties.py +0 -140
- morphata-2.1.0/tests/test_acceptance_validation.py +0 -45
- morphata-2.1.0/tests/test_alphabet.py +0 -205
- morphata-2.1.0/tests/test_automaton.py +0 -242
- morphata-2.1.0/tests/test_builder.py +0 -124
- morphata-2.1.0/tests/test_from_parsed.py +0 -101
- morphata-2.1.0/uv.lock +0 -3331
- {morphata-2.1.0 → morphata-2.2.0}/.basedpyright/baseline.json +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.dockerignore +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.editorconfig +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.envrc.recommended +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.fdignore +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.gitattributes +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.gitignore +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.mailmap +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/.python-version +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/CLAUDE.md +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/CONTRIBUTING.md +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/LICENSE +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/bench/README.md +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/bench/__init__.py +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/ci/make-release +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/docs/_static/navigation.html +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/mypy.ini +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/project.utf-8.add +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/project.utf-8.add.spl +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/pyrightconfig.json +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/hoa/__main__.py +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/hoa/hoa.lark +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/operators/__init__.py +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/operators/_backend.py +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/src/morphata/py.typed +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut1.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut11.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut2.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut3.2.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut3.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut4.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut5.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut6.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut7.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/aut8.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/finite_aut.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/gen_buchi_3.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/gen_cobuchi_2.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/rabin_2pair.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/streett_2pair.hoa +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/hoa/test_parser.py +0 -0
- {morphata-2.1.0 → morphata-2.2.0}/tests/logic/__init__.py +0 -0
|
@@ -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")"
|
morphata-2.2.0/AGENTS.md
ADDED
|
@@ -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,40 +1,124 @@
|
|
|
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
|
+
|
|
3
77
|
## 2.1.0 — 2026-06-11
|
|
4
78
|
|
|
5
79
|
### Added
|
|
6
80
|
|
|
7
|
-
- Add `morphata.symbolic.prune` that does a cheap,
|
|
8
|
-
pruning of an AFA.
|
|
9
|
-
|
|
10
|
-
|
|
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.
|
|
11
87
|
|
|
12
88
|
### Changed
|
|
13
89
|
|
|
14
|
-
- `MatrixOperator` and `PolynomialOperator` are generic now —
|
|
15
|
-
and `PolynomialOperator[Symbol, AP]`,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`MatrixOperator`
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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`
|
|
31
115
|
(the one with the spatial `expand()` rules), so that dep gets bumped along with it.
|
|
32
116
|
|
|
33
117
|
### Miscellaneous
|
|
34
118
|
|
|
35
|
-
- Housekeeping, but worth saying:
|
|
36
|
-
|
|
37
|
-
whack-a-mole.
|
|
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.
|
|
38
122
|
|
|
39
123
|
## 2.0.10 — 2026-06-08
|
|
40
124
|
|
|
@@ -46,8 +130,8 @@
|
|
|
46
130
|
|
|
47
131
|
### Performance
|
|
48
132
|
|
|
49
|
-
- The HOA grammar is now LALR compatible!
|
|
50
|
-
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.
|
|
51
135
|
- Similar thing was done in `logic-asts` and thus, the version will be bumped.
|
|
52
136
|
|
|
53
137
|
## 2.0.9 — 2026-06-04
|
|
@@ -123,7 +207,7 @@
|
|
|
123
207
|
### Fixed
|
|
124
208
|
|
|
125
209
|
- A major regression where the streaming `to_hoa` stuff changed the label enumeration
|
|
126
|
-
semantics to be
|
|
210
|
+
semantics to be *minterms* instead of *cubes*.
|
|
127
211
|
This is now fixed.
|
|
128
212
|
|
|
129
213
|
### Added
|
|
@@ -344,8 +428,7 @@ which will be summarized below.
|
|
|
344
428
|
The reverse direction is deliberately omitted —
|
|
345
429
|
recovering Boolean semantics from arbitrary `V` needs an ordering and a cut (cf.
|
|
346
430
|
STL), and pretending otherwise would silently produce garbage.
|
|
347
|
-
- **Ergonomic construction.**
|
|
348
|
-
`AutomatonBuilder` replaces the old NFA builder.
|
|
431
|
+
- **Ergonomic construction.** `AutomatonBuilder` replaces the old NFA builder.
|
|
349
432
|
Add states, add transitions with a guard and a successor
|
|
350
433
|
(single state, set of states, or a raw `BoolExpr` for full alternation),
|
|
351
434
|
and `build()` cleans up by merging rows that share a successor.
|
|
@@ -373,11 +456,9 @@ which will be summarized below.
|
|
|
373
456
|
The BDD cofactor path works for any `BooleanAlphabet`,
|
|
374
457
|
so you can feed a `SymbolicAutomaton` over integers, graph nodes, whatever —
|
|
375
458
|
as long as you can write a labeling.
|
|
376
|
-
- **The AFA-to-min-DFA pipeline actually exists now.**
|
|
377
|
-
`
|
|
378
|
-
|
|
379
|
-
`minimize` (Hopcroft) — all share one BDD manager
|
|
380
|
-
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.
|
|
381
462
|
`SymbolicAutomaton.to_min_dfa` chains the three.
|
|
382
463
|
Finite-word only for now; omega-regular determinisation is a different beast.
|
|
383
464
|
- **DFA equivalence checks.**
|
|
@@ -388,19 +469,17 @@ which will be summarized below.
|
|
|
388
469
|
|
|
389
470
|
### Operators
|
|
390
471
|
|
|
391
|
-
- **One per-step shape.**
|
|
392
|
-
`SymbolicAutomaton`, `MatrixOperator`,
|
|
472
|
+
- **One per-step shape.** `SymbolicAutomaton`, `MatrixOperator`,
|
|
393
473
|
and `PolynomialOperator` all expose the same `step(current, symbol)` / `run(word)` /
|
|
394
474
|
`accepts(word)` shape.
|
|
395
475
|
Each binds its alphabet at construction
|
|
396
476
|
(matching how the semiring / algebra were already bound),
|
|
397
477
|
so the per-call API is monomorphic and `V` is pinned end-to-end.
|
|
398
478
|
Wanted symmetry between the layers; got it.
|
|
399
|
-
- **`PolynomialOperator` evaluates lazily.**
|
|
400
|
-
`
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
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.
|
|
404
483
|
The AFA's row structure stays static
|
|
405
484
|
(good for JAX tracing), and the alphabet decides whether to memoise.
|
|
406
485
|
- **Polynomial performance.**
|
|
@@ -410,9 +489,8 @@ which will be summarized below.
|
|
|
410
489
|
|
|
411
490
|
### Tooling and Tests
|
|
412
491
|
|
|
413
|
-
- **Hand-written changelogs.**
|
|
414
|
-
|
|
415
|
-
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.
|
|
416
494
|
`ci/make-release` no longer touches `CHANGELOG.md` or tag messages.
|
|
417
495
|
Run `git cliff` separately if you want a draft to crib from.
|
|
418
496
|
- **Tests.**
|
morphata-2.2.0/PKG-INFO
ADDED
|
@@ -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()
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The case: an LTLf min-DFA whose AP universe is large (|aps| ~ 19) but
|
|
4
4
|
whose guards mention only 4 APs. Pre-rewrite this regime explodes;
|
|
5
|
-
post-rewrite the per-pair (
|
|
6
|
-
|
|
5
|
+
post-rewrite the per-pair (``is_language_equivalent``) support reduction
|
|
6
|
+
keeps work bounded.
|
|
7
7
|
|
|
8
8
|
pytest-benchmark records the timing distribution; no hard-coded
|
|
9
9
|
thresholds, the dataset is the regression signal.
|
|
@@ -13,18 +13,18 @@ Run with: ``pytest bench/test_equivalence_perf.py -v``
|
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
+
from collections.abc import Set as AbstractSet
|
|
17
|
+
|
|
16
18
|
import logic_asts.ltl as ltl
|
|
19
|
+
import pytest
|
|
17
20
|
from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
|
|
18
21
|
|
|
19
22
|
from morphata.alphabet import powerset_alphabet
|
|
20
|
-
from morphata.automaton import Automaton
|
|
21
|
-
from morphata.logic.ltl import Input, ltl_to_automaton
|
|
22
|
-
from morphata.symbolic import isomorphic
|
|
23
23
|
from morphata.symbolic.automaton import SymbolicAutomaton
|
|
24
|
-
from morphata.symbolic.
|
|
24
|
+
from morphata.symbolic.utils import is_language_equivalent
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def _sparse_big_alphabet_dfa() -> SymbolicAutomaton[str]:
|
|
27
|
+
def _sparse_big_alphabet_dfa() -> SymbolicAutomaton[str, AbstractSet[str]]:
|
|
28
28
|
aps = frozenset({f"p{i}" for i in range(15)} | {"a", "b", "c", "d"})
|
|
29
29
|
formula = ltl.And(
|
|
30
30
|
(
|
|
@@ -35,23 +35,15 @@ def _sparse_big_alphabet_dfa() -> SymbolicAutomaton[str]:
|
|
|
35
35
|
)
|
|
36
36
|
)
|
|
37
37
|
alphabet = powerset_alphabet(aps)
|
|
38
|
-
aut
|
|
39
|
-
return
|
|
38
|
+
aut = SymbolicAutomaton.from_specification(formula, alphabet=alphabet, finite=True)
|
|
39
|
+
return aut.to_min_dfa()
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
@pytest.mark.limit_memory("2 GB")
|
|
42
43
|
def test_language_equivalent_sparse_big_alphabet(benchmark: Benchmark) -> None:
|
|
43
44
|
dfa = _sparse_big_alphabet_dfa()
|
|
44
45
|
|
|
45
46
|
def _run() -> bool:
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
assert benchmark(_run)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def test_isomorphic_sparse_big_alphabet(benchmark: Benchmark) -> None:
|
|
52
|
-
dfa = _sparse_big_alphabet_dfa()
|
|
53
|
-
|
|
54
|
-
def _run() -> bool:
|
|
55
|
-
return isomorphic(dfa, dfa)
|
|
47
|
+
return is_language_equivalent(dfa, dfa)
|
|
56
48
|
|
|
57
49
|
assert benchmark(_run)
|