morphata 2.0.1__tar.gz → 2.0.3__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.0.1 → morphata-2.0.3}/.claude/settings.local.json +12 -1
- {morphata-2.0.1 → morphata-2.0.3}/.envrc +0 -4
- {morphata-2.0.1 → morphata-2.0.3}/AGENTS.md +160 -126
- {morphata-2.0.1 → morphata-2.0.3}/CHANGELOG.md +115 -30
- morphata-2.0.3/PKG-INFO +137 -0
- morphata-2.0.3/bench/README.md +28 -0
- morphata-2.0.3/bench/conftest.py +53 -0
- morphata-2.0.3/bench/test_sere_nlm_perf.py +84 -0
- morphata-2.0.3/ci/make-release +131 -0
- {morphata-2.0.1 → morphata-2.0.3}/pixi.lock +157 -464
- {morphata-2.0.1 → morphata-2.0.3}/pixi.toml +9 -7
- {morphata-2.0.1 → morphata-2.0.3}/pyproject.toml +4 -2
- morphata-2.0.3/pytest.toml +32 -0
- morphata-2.0.3/src/morphata/logic/_common.py +136 -0
- morphata-2.0.3/src/morphata/logic/psl.py +372 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/logic/sere.py +148 -35
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/symbolic/__init__.py +3 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/symbolic/bdd.py +2 -1
- morphata-2.0.3/src/morphata/symbolic/compose.py +363 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/symbolic/transforms.py +4 -4
- {morphata-2.0.1 → morphata-2.0.3}/tests/conftest.py +24 -0
- morphata-2.0.3/tests/logic/__init__.py +0 -0
- morphata-2.0.3/tests/logic/test_psl.py +179 -0
- morphata-2.0.3/tests/logic/test_sere.py +489 -0
- morphata-2.0.3/tests/logic/test_sere_properties.py +132 -0
- morphata-2.0.3/tests/symbolic/test_compose.py +335 -0
- {morphata-2.0.1 → morphata-2.0.3}/uv.lock +176 -89
- morphata-2.0.1/PKG-INFO +0 -29
- morphata-2.0.1/ci/make-release +0 -99
- morphata-2.0.1/pytest.toml +0 -14
- morphata-2.0.1/src/morphata/logic/_common.py +0 -72
- morphata-2.0.1/src/morphata/logic/psl.py +0 -495
- morphata-2.0.1/tests/logic/test_psl.py +0 -230
- morphata-2.0.1/tests/logic/test_sere.py +0 -236
- {morphata-2.0.1 → morphata-2.0.3}/.basedpyright/baseline.json +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.dockerignore +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.editorconfig +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.envrc.recommended +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.fdignore +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.gitattributes +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.gitignore +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.mailmap +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.python-version +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/.rstcheck.cfg +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/CLAUDE.md +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/CONTRIBUTING.md +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/LICENSE +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/README.md +0 -0
- {morphata-2.0.1/tests/logic → morphata-2.0.3/bench}/__init__.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/cliff.toml +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/_static/navigation.html +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/modules.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.acceptance.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.alphabet.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.automaton.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.builder.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.hoa.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.logic.ltl.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.logic.psl.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.logic.sere.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.logic.strel.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.operators.matrix.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.operators.polynomial.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.operators.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/api/morphata.symbolic.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/concepts/acceptance.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/concepts/hoa.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/concepts/index.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/concepts/operators.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/concepts/spec.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/concepts/weights.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/conf.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/index.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/quick-start.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/docs/symbolic-transforms.rst +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/justfile +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/mypy.ini +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/project.utf-8.add +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/project.utf-8.add.spl +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/pyrefly.toml +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/pyrightconfig.json +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/ruff.toml +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/__init__.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/acceptance.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/alphabet.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/automaton.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/builder.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/hoa/__init__.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/hoa/__main__.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/hoa/acc_expr.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/hoa/exporter.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/hoa/hoa.lark +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/hoa/parser.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/logic/__init__.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/logic/ltl.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/logic/strel.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/operators/__init__.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/operators/_backend.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/operators/matrix.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/operators/polynomial.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/py.typed +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/symbolic/automaton.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/src/morphata/symbolic/equivalence.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut1.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut11.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut2.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut3.2.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut3.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut4.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut5.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut6.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut7.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/aut8.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/finite_aut.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/gen_buchi_3.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/gen_cobuchi_2.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/rabin_2pair.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/streett_2pair.hoa +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/test_exporter_basic.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/test_exporter_roundtrip.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/hoa/test_parser.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/logic/test_ltl.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/logic/test_strel.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/operators/test_matrix_from_ir.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/operators/test_matrix_from_ltl.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/operators/test_polynomial_from_ir.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_bdd_helpers.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_from_hoaf.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_ltlf2dfa_equivalence.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_step.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_symbolic_automaton.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_symbolic_from_ir.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_transforms.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_transforms_ir.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/symbolic/test_transforms_properties.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/test_alphabet.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/test_automaton.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/test_builder.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/tests/test_from_parsed.py +0 -0
- {morphata-2.0.1 → morphata-2.0.3}/ty.toml +0 -0
|
@@ -15,7 +15,18 @@
|
|
|
15
15
|
"Bash(.venv/bin/python -m pytest *)",
|
|
16
16
|
"Skill(superpowers:writing-plans)",
|
|
17
17
|
"Skill(superpowers:subagent-driven-development)",
|
|
18
|
-
"Bash(grep -v \"AssertionError\\\\|Traceback\\\\|File \\\\|^\\\\s*$\")"
|
|
18
|
+
"Bash(grep -v \"AssertionError\\\\|Traceback\\\\|File \\\\|^\\\\s*$\")",
|
|
19
|
+
"Skill(superpowers:brainstorming)",
|
|
20
|
+
"Bash(jj log *)",
|
|
21
|
+
"Bash(jj st *)",
|
|
22
|
+
"Bash(jj diff *)",
|
|
23
|
+
"Skill(superpowers:requesting-code-review)",
|
|
24
|
+
"Bash(timeout 15 python -c ' *)",
|
|
25
|
+
"Read(//tmp/**)",
|
|
26
|
+
"Bash(echo \"exit: $?\")",
|
|
27
|
+
"Skill(superpowers:executing-plans)",
|
|
28
|
+
"Bash(ruff check *)",
|
|
29
|
+
"Bash(ruff format *)"
|
|
19
30
|
]
|
|
20
31
|
}
|
|
21
32
|
}
|
|
@@ -9,73 +9,81 @@ It packages structural automaton representations together with semiring-valued
|
|
|
9
9
|
The development shell already has the project virtual environment activated,
|
|
10
10
|
so `pytest`, `mypy`, `ruff`, `sphinx-build`, etc. are on `PATH` directly.
|
|
11
11
|
**Do not** prefix commands with `uv run`, `pixi run`, `poetry run`, or similar.
|
|
12
|
-
Just invoke the tool.
|
|
13
|
-
|
|
12
|
+
Just invoke the tool.
|
|
13
|
+
If a tool is missing, stop and tell the user rather than trying to bootstrap
|
|
14
|
+
or reinstall the environment.
|
|
14
15
|
|
|
15
16
|
## Core Architecture
|
|
16
17
|
|
|
17
|
-
### IR
|
|
18
|
+
### IR Layer (`morphata.automaton`, `morphata.alphabet`, `morphata.acceptance`)
|
|
18
19
|
|
|
19
20
|
**`morphata.automaton`** : the canonical automaton IR.
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
- `Automaton[State, Symbol, AP]` : the single automaton dataclass.
|
|
23
|
+
Fields: `states`, `predicates`, `initial: BoolExpr[State]`, `delta: Delta`,
|
|
22
24
|
`acceptance: AcceptanceCondition[State]`, plus a derived ``variant``.
|
|
23
|
-
- `Outgoing[State, AP]` : canonical predicate-row delta.
|
|
25
|
+
- `Outgoing[State, AP]` : canonical predicate-row delta. ``fn(state)``
|
|
24
26
|
yields ``(guard: BoolExpr[AP], successor: BoolExpr[State])`` pairs.
|
|
25
|
-
- `Step[State, Symbol]` : escape-hatch delta for input-dependent state
|
|
26
|
-
|
|
27
|
+
- `Step[State, Symbol]` : escape-hatch delta for input-dependent state spaces.
|
|
28
|
+
``fn(state, symbol) -> BoolExpr[State]``.
|
|
29
|
+
Used by STREL.
|
|
27
30
|
Not symbolically liftable.
|
|
28
31
|
- `Delta` : union of ``Outgoing`` and ``Step``.
|
|
29
32
|
- `DeltaKind` : ``DETERMINISTIC``, ``NONDETERMINISTIC``, ``UNIVERSAL``,
|
|
30
33
|
``ALTERNATING``.
|
|
31
34
|
- `classify_delta(delta, states)` : classifies a delta into a
|
|
32
|
-
``DeltaKind``.
|
|
35
|
+
``DeltaKind``. ``Step`` always classifies as ``ALTERNATING``.
|
|
33
36
|
- `BoolExpr[Var]` : alias for ``logic_asts.base.BaseExpr[Var]``.
|
|
34
37
|
|
|
35
|
-
**`morphata.alphabet`** : input alphabet abstractions.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- `
|
|
41
|
-
``
|
|
42
|
-
|
|
43
|
-
``
|
|
44
|
-
|
|
45
|
-
``
|
|
46
|
-
|
|
38
|
+
**`morphata.alphabet`** : input alphabet abstractions.
|
|
39
|
+
Guards in the IR stay symbolic;
|
|
40
|
+
the alphabet bundles the symbol-side metadata with the function
|
|
41
|
+
that interprets a guard against a symbol.
|
|
42
|
+
|
|
43
|
+
- `Alphabet[Symbol, AP, V]` (``Protocol``) : the operator-facing contract.
|
|
44
|
+
Exposes ``predicates`` and ``weight(symbol, guard) -> V``.
|
|
45
|
+
- `BooleanAlphabet[Symbol, AP]` : carries a labeling ``L: Symbol -> AbstractSet[AP]``.
|
|
46
|
+
``weight`` evaluates the guard in Boolean semantics against the AP-truth set
|
|
47
|
+
``L(symbol)``.
|
|
48
|
+
Satisfies ``Alphabet[Symbol, AP, bool]``.
|
|
49
|
+
- `WeightedAlphabet[Symbol, AP, V]` : carries an arbitrary ``weight_fn:
|
|
50
|
+
(Symbol, BoolExpr[AP]) -> V``.
|
|
51
|
+
Satisfies ``Alphabet[Symbol, AP, V]``.
|
|
47
52
|
- Factories: ``powerset_alphabet(aps)`` (Sigma = 2^AP, identity
|
|
48
53
|
labeling), ``finite_alphabet(aps)`` (Sigma = AP, one-hot labeling),
|
|
49
54
|
``weighted_alphabet(weight_fn, *, predicates)``.
|
|
50
55
|
- ``WeightedAlphabet.from_boolean(boolean, semiring)`` lifts a Boolean
|
|
51
56
|
alphabet into ``V`` via evaluate-then-lift (the guard is evaluated in
|
|
52
57
|
``bool`` and the result is mapped to ``semiring.zero`` / ``one``).
|
|
53
|
-
- ``WeightedAlphabet.from_predicates
|
|
54
|
-
weight function from per-AP predicates over ``V``.
|
|
55
|
-
former ``morphata.weights`` module.
|
|
58
|
+
- ``WeightedAlphabet.from_predicates
|
|
59
|
+
(predicates, semiring)`` builds a weight function from per-AP predicates over ``V``.
|
|
60
|
+
Replaces the former ``morphata.weights`` module.
|
|
56
61
|
|
|
57
|
-
The reverse direction (``WeightedAlphabet -> BooleanAlphabet``) requires
|
|
58
|
-
|
|
59
|
-
and is deliberately not provided.
|
|
62
|
+
The reverse direction (``WeightedAlphabet -> BooleanAlphabet``) requires extra ordering
|
|
63
|
+
/ threshold structure (cf.
|
|
64
|
+
STL quantitative semantics) and is deliberately not provided.
|
|
60
65
|
|
|
61
|
-
**`morphata.acceptance`** :
|
|
62
|
-
used by the HOA parser
|
|
63
|
-
``Buchi``, ``CoBuchi``, ``GeneralizedBuchi``,
|
|
64
|
-
``Rabin``, ``Streett``,
|
|
65
|
-
|
|
66
|
+
**`morphata.acceptance`** :
|
|
67
|
+
expression-based acceptance conditions used by the HOA parser
|
|
68
|
+
and the rest of the stack - ``Finite``, ``Buchi``, ``CoBuchi``, ``GeneralizedBuchi``,
|
|
69
|
+
``GeneralizedCoBuchi``, ``Rabin``, ``Streett``,
|
|
70
|
+
plus a ``GenericCondition`` fallback for acceptance formulas
|
|
71
|
+
that do not match a named condition.
|
|
66
72
|
|
|
67
73
|
**`morphata.hoa`** : Hanoi Omega-Automata v1 parser.
|
|
74
|
+
|
|
68
75
|
- ``parser.py`` : LALR-based parser; supports the ``Final(n)``
|
|
69
76
|
extension for finite-word acceptance.
|
|
70
77
|
- ``acc_expr.py`` : acceptance-formula AST shared with the parser.
|
|
71
78
|
- ``exporter.py`` : HOA v1 serializer; round-trips parser input via
|
|
72
79
|
``automaton_to_hoa``.
|
|
73
80
|
|
|
74
|
-
### Construction
|
|
81
|
+
### Construction Layer
|
|
82
|
+
|
|
83
|
+
**`morphata.builder.AutomatonBuilder[State, AP]`** :
|
|
84
|
+
the mutable builder that produces an ``Automaton`` IR on ``build()``.
|
|
85
|
+
Replaces the deleted ``morphata.constructions.nfa.NFA``.
|
|
75
86
|
|
|
76
|
-
**`morphata.builder.AutomatonBuilder[State, AP]`** : the mutable builder
|
|
77
|
-
that produces an ``Automaton`` IR on ``build()``. Replaces the deleted
|
|
78
|
-
``morphata.constructions.nfa.NFA``.
|
|
79
87
|
- ``add_state(state, *, initial=False, accepting=False)``.
|
|
80
88
|
- ``add_transition(src, guard, succ)`` where ``succ`` may be a single
|
|
81
89
|
state, a set of states (lifted to ``Or`` / ``And`` per variant), or a
|
|
@@ -88,35 +96,40 @@ LTL/LTLf -> alternating ``Automaton`` with an ``Outgoing`` delta.
|
|
|
88
96
|
``finite=True`` -> ``Finite`` acceptance; ``finite=False`` -> ``Buchi``.
|
|
89
97
|
|
|
90
98
|
**`morphata.logic.strel.strel_to_automata(expr, dist_attr, label_fn, ...)`** :
|
|
91
|
-
STREL over labelled graphs.
|
|
92
|
-
delta - the transition consumes the labelled
|
|
93
|
-
automata are not symbolically liftable.
|
|
94
|
-
Somewhere, Everywhere.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
``
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
99
|
+
STREL over labelled graphs.
|
|
100
|
+
Returns an ``Automaton`` with a ``Step`` delta - the transition consumes the labelled
|
|
101
|
+
graph eagerly, so STREL automata are not symbolically liftable.
|
|
102
|
+
Operators: Reach, Escape, Somewhere, Everywhere.
|
|
103
|
+
Boolean-only.
|
|
104
|
+
|
|
105
|
+
**`morphata.logic.sere.sere_to_automaton(expr)`** :
|
|
106
|
+
SERE -> alternating finite automaton.
|
|
107
|
+
Supports ``Concat``, ``Fusion``, ``Repeat``
|
|
108
|
+
(bounded and unbounded), ``Inter``, ``Alt``, and Boolean leaves over AP.
|
|
109
|
+
Acceptance is always ``Finite``;
|
|
110
|
+
the accepting-state set is exactly the *nullable* states
|
|
111
|
+
(those that match the empty word).
|
|
112
|
+
|
|
113
|
+
**`morphata.logic.psl.psl_to_automaton(phi, *, finite=False)`** :
|
|
114
|
+
PSL -> alternating automaton.
|
|
115
|
+
Wraps pure-LTL subformulas in an internal ``_LTL`` tag
|
|
116
|
+
and dispatches to the LTL expansion rule; closure operators (``{r}!
|
|
117
|
+
``, ``{r}``, ``!{r}``, ``{r}<>-> f``, ``{r}[]-> f``) become their own tagged states with
|
|
118
|
+
SERE-step expansion.
|
|
119
|
+
Suffix implications follow Spot's overlapping semantics:
|
|
120
|
+
the last symbol of ``r`` and the first position of ``f`` coincide.
|
|
121
|
+
``finite=True`` -> ``Finite`` acceptance (PSLf); ``finite=False`` -> ``Buchi``.
|
|
122
|
+
|
|
123
|
+
Hand-written automata are built with ``AutomatonBuilder``;
|
|
124
|
+
the package has no separate ``constructions`` namespace.
|
|
125
|
+
|
|
126
|
+
### Operator Layer (`morphata.operators`)
|
|
127
|
+
|
|
128
|
+
Algebraic morphisms that turn an ``Automaton`` plus an ``Alphabet`` into a computable
|
|
129
|
+
interpretation over an algebraic domain.
|
|
118
130
|
|
|
119
131
|
**`morphata.operators.matrix.MatrixOperator`** :
|
|
132
|
+
|
|
120
133
|
- Weighted finite-word NFA semantics as semiring matrix multiplication.
|
|
121
134
|
- Fields: ``initial_weights``, ``final_weights``, ``semiring``, an
|
|
122
135
|
``alphabet`` bound at construction, and a frozen ``(src, dst, guard)``
|
|
@@ -129,6 +142,7 @@ a computable interpretation over an algebraic domain.
|
|
|
129
142
|
- ``cost_transitions(x)`` returns an ``algebraic.AlgebraicArray``.
|
|
130
143
|
|
|
131
144
|
**`morphata.operators.polynomial.PolynomialOperator`** :
|
|
145
|
+
|
|
132
146
|
- Alternating finite automata as multilinear polynomials over a
|
|
133
147
|
bounded distributive lattice (typically Boolean).
|
|
134
148
|
- The alphabet is bound at construction. ``step(current, symbol)``
|
|
@@ -139,51 +153,64 @@ a computable interpretation over an algebraic domain.
|
|
|
139
153
|
``PolynomialOperator.from_ltl(formula, algebra, *, alphabet, finite=True, ...)``.
|
|
140
154
|
- Backed by ``algebraic.polynomials.RankDecomposition``.
|
|
141
155
|
|
|
142
|
-
**`morphata.operators._backend`** :
|
|
143
|
-
``_StaticAux`` JAX-pytree helper.
|
|
144
|
-
``AlgebraicArray`` or specified explicitly via ``backend=``.
|
|
156
|
+
**`morphata.operators._backend`** :
|
|
157
|
+
``resolve_backend(...)`` and the ``_StaticAux`` JAX-pytree helper.
|
|
158
|
+
Inferred from any provided ``AlgebraicArray`` or specified explicitly via ``backend=``.
|
|
145
159
|
|
|
146
|
-
### Symbolic
|
|
160
|
+
### Symbolic Layer (`morphata.symbolic`)
|
|
147
161
|
|
|
148
|
-
BDD-backed representation of an ``Automaton``.
|
|
149
|
-
layer: no target algebra, no semiring.
|
|
162
|
+
BDD-backed representation of an ``Automaton``.
|
|
163
|
+
Structural / runtime layer: no target algebra, no semiring.
|
|
150
164
|
|
|
151
|
-
**`morphata.symbolic.bdd`** :
|
|
152
|
-
``dd`` BDD package.
|
|
153
|
-
``
|
|
154
|
-
``boolexpr_to_bdd
|
|
155
|
-
``bdd_to_boolexpr(node) -> BoolExpr[int]``.
|
|
156
|
-
``morphata`` imports ``dd`` directly.
|
|
165
|
+
**`morphata.symbolic.bdd`** :
|
|
166
|
+
thin bridge between ``BoolExpr`` and the ``dd`` BDD package.
|
|
167
|
+
Exports ``make_manager(reordering=True)``, ``declare_state_vars``, ``state_var_name``,
|
|
168
|
+
``STATE_VAR_FORMAT``, ``boolexpr_to_bdd
|
|
169
|
+
(expr, mgr, num_vars) -> dd.Function``, ``bdd_to_boolexpr(node) -> BoolExpr[int]``.
|
|
170
|
+
Nothing else in ``morphata`` imports ``dd`` directly.
|
|
157
171
|
|
|
158
172
|
**`morphata.symbolic.automaton.SymbolicAutomaton`** :
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
173
|
+
|
|
174
|
+
- Wraps an ``Automaton`` so the initial-state set
|
|
175
|
+
and every cached transition are live ``dd.Function`` nodes in a single ``dd.BDD``
|
|
176
|
+
manager.
|
|
177
|
+
Acceptance is stored as given; only ``accepts(word)`` requires ``Finite`` acceptance.
|
|
163
178
|
- Requires ``aut.delta`` to be ``Outgoing``; ``Step`` deltas (STREL)
|
|
164
179
|
raise ``TypeError``.
|
|
165
|
-
- Constructor: ``SymbolicAutomaton.from_automaton
|
|
166
|
-
manager=None, reordering=True, cache_transitions=True,
|
|
180
|
+
- Constructor: ``SymbolicAutomaton.from_automaton
|
|
181
|
+
(aut, *, alphabet, manager=None, reordering=True, cache_transitions=True,
|
|
182
|
+
name_fn=None)``.
|
|
167
183
|
Convenience ``from_ltl`` / ``from_hoaf`` constructors compose with
|
|
168
|
-
``ltl_to_automaton`` and the HOA parser, and likewise require
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
``BooleanAlphabet``; the BDD cofactor path generalises to any
|
|
173
|
-
user-supplied labeling.
|
|
184
|
+
``ltl_to_automaton`` and the HOA parser, and likewise require ``alphabet=``.
|
|
185
|
+
- Per-step primitives: ``step(current, symbol)``, ``run(word)``, ``accepts(word)``.
|
|
186
|
+
The alphabet is bound at construction and must be a ``BooleanAlphabet``;
|
|
187
|
+
the BDD cofactor path generalises to any user-supplied labeling.
|
|
174
188
|
- State variables in the manager are always named ``q0..q{n-1}``;
|
|
175
189
|
callers who want their own variable names should apply ``mgr.let``
|
|
176
190
|
with an alias map.
|
|
177
191
|
|
|
178
|
-
**`morphata.symbolic.transforms`** :
|
|
179
|
-
over ``SymbolicAutomaton`` -- ``nfa_from_afa``
|
|
180
|
-
``determinize`` (subset construction with an explicit sink), and
|
|
181
|
-
``minimize`` (Hopcroft partition refinement).
|
|
182
|
-
``SymbolicAutomaton.to_min_dfa``.
|
|
183
|
-
|
|
184
|
-
**`morphata.symbolic.
|
|
185
|
-
|
|
186
|
-
``
|
|
192
|
+
**`morphata.symbolic.transforms`** :
|
|
193
|
+
BDD-level structural transforms over ``SymbolicAutomaton`` -- ``nfa_from_afa``
|
|
194
|
+
(dealternation), ``determinize`` (subset construction with an explicit sink), and
|
|
195
|
+
``minimize`` (Hopcroft partition refinement).
|
|
196
|
+
The three compose to ``SymbolicAutomaton.to_min_dfa``.
|
|
197
|
+
|
|
198
|
+
**`morphata.symbolic.compose`** :
|
|
199
|
+
compositional min-DFA construction on top of ``minimize``.
|
|
200
|
+
``compose_min_dfa(left, right, op)`` takes the product of two DFA-shaped
|
|
201
|
+
``SymbolicAutomaton`` instances over a shared manager and minimizes the result; ``op``
|
|
202
|
+
is ``"and"`` or ``"or"``.
|
|
203
|
+
``min_dfa_of_conjunction(formulas, *, alphabet)`` builds each conjunct's min-DFA over a
|
|
204
|
+
shared manager with a canonical AP ``name_fn`` derived from the alphabet's predicate
|
|
205
|
+
set, then folds them under ``compose_min_dfa(..., op="and")``.
|
|
206
|
+
For top-level LTLf conjunctions where each conjunct has a small min-DFA
|
|
207
|
+
but the monolithic AFA explodes under ``determinize``,
|
|
208
|
+
the layered path can be orders of magnitude faster.
|
|
209
|
+
|
|
210
|
+
**`morphata.symbolic.equivalence`** :
|
|
211
|
+
language-equivalence and isomorphism checks
|
|
212
|
+
for DFA-shaped symbolic automata -- ``language_equivalent``, ``canonical_form``,
|
|
213
|
+
``isomorphic``.
|
|
187
214
|
|
|
188
215
|
## Dependencies
|
|
189
216
|
|
|
@@ -194,18 +221,18 @@ isomorphism checks for DFA-shaped symbolic automata --
|
|
|
194
221
|
- Optional: `jax` (for the JAX backend), `torch` (for the PyTorch
|
|
195
222
|
backend), `pydot` (for `.dot` exports).
|
|
196
223
|
|
|
197
|
-
`morphata` operators that use `equinox` are JAX-flavoured;
|
|
198
|
-
is backend-agnostic via `backend=`.
|
|
224
|
+
`morphata` operators that use `equinox` are JAX-flavoured;
|
|
225
|
+
`algebraic` is backend-agnostic via `backend=`.
|
|
199
226
|
|
|
200
227
|
## Design Principles
|
|
201
228
|
|
|
202
|
-
1. **Single IR shape** : everything is a
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
2. **Alphabet-Carried Characteristic Function** : guards stay symbolic
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
for symbolic evaluation, semiring elements for weighted evaluation).
|
|
229
|
+
1. **Single IR shape** : everything is a ``morphata.automaton.Automaton``.
|
|
230
|
+
Variants (det / nondet / univ / alt) are derived from the rows,
|
|
231
|
+
not encoded in separate classes.
|
|
232
|
+
2. **Alphabet-Carried Characteristic Function** : guards stay symbolic in the IR.
|
|
233
|
+
``Alphabet.weight(symbol, guard)`` lifts a symbol against a guard.
|
|
234
|
+
Match the alphabet's ``V`` type to your consumer
|
|
235
|
+
(``bool`` for symbolic evaluation, semiring elements for weighted evaluation).
|
|
209
236
|
3. **Semiring-Agnostic Operators** : operator factories accept the
|
|
210
237
|
target algebra and the alphabet separately; the alphabet does not
|
|
211
238
|
know about the algebra.
|
|
@@ -221,31 +248,36 @@ is backend-agnostic via `backend=`.
|
|
|
221
248
|
|
|
222
249
|
## Usage Notes and Limitations
|
|
223
250
|
|
|
224
|
-
- STREL automata use a ``Step`` delta
|
|
225
|
-
|
|
226
|
-
|
|
251
|
+
- STREL automata use a ``Step`` delta
|
|
252
|
+
(the transition consumes the input graph eagerly),
|
|
253
|
+
so they cannot be lifted to ``SymbolicAutomaton``
|
|
254
|
+
and are not consumable by ``MatrixOperator`` / ``PolynomialOperator``.
|
|
227
255
|
STREL itself is Boolean-only.
|
|
228
|
-
- ``MatrixOperator`` targets finite-word acceptance;
|
|
229
|
-
acceptance is not implemented for it.
|
|
230
|
-
single ``Variable(dst)`` per row
|
|
256
|
+
- ``MatrixOperator`` targets finite-word acceptance;
|
|
257
|
+
omega-regular acceptance is not implemented for it.
|
|
258
|
+
Successor expressions must be single ``Variable(dst)`` per row
|
|
259
|
+
(no alternation / universal lifting).
|
|
231
260
|
- ``PolynomialOperator`` is tested with Boolean algebra; other semirings
|
|
232
261
|
may require additional validation.
|
|
233
|
-
- **State-based acceptance only.**
|
|
234
|
-
sets
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
262
|
+
- **State-based acceptance only.**
|
|
263
|
+
Acceptance sets are sets of states, not sets of transitions.
|
|
264
|
+
The HOA parser ingests ``{n}`` markers from ``State:`` declarations;
|
|
265
|
+
per-edge ``{n}`` markers are ignored.
|
|
266
|
+
Convert transition-based HOA files to state-based form before loading them.
|
|
267
|
+
- ``psl_to_automaton`` requires the continuation of any ``SuffixImpliesExist`` /
|
|
268
|
+
``SuffixImpliesUniv`` to be a pure-LTL formula in v1.
|
|
269
|
+
Nested PSL closures inside a suffix-implication continuation raise
|
|
270
|
+
``NotImplementedError``.
|
|
271
|
+
Likewise, LTL temporal operators wrapping a PSL closure at the top level
|
|
272
|
+
(e.g. ``Always(StrongClosure(r))``)
|
|
273
|
+
are not yet decomposed; lift the PSL fragment out of the LTL temporal operator
|
|
274
|
+
before calling.
|
|
244
275
|
- The PSL Buchi acceptance classification is the natural per-tag rule
|
|
245
|
-
(strong-closure non-accepting, weak-closure accepting, etc.).
|
|
246
|
-
not been cross-checked against a published reference
|
|
247
|
-
combination of operators;
|
|
248
|
-
|
|
276
|
+
(strong-closure non-accepting, weak-closure accepting, etc.).
|
|
277
|
+
It has not been cross-checked against a published reference
|
|
278
|
+
for every combination of operators;
|
|
279
|
+
consult ``docs/superpowers/specs/``
|
|
280
|
+
before relying on omega-language semantics in production.
|
|
249
281
|
|
|
250
282
|
## Testing
|
|
251
283
|
|
|
@@ -379,6 +411,8 @@ matrix_product = algebraic.matmul(arr1, arr2)
|
|
|
379
411
|
- `src/morphata/operators/polynomial.py` : ``PolynomialOperator``.
|
|
380
412
|
- `src/morphata/symbolic/automaton.py` : ``SymbolicAutomaton``.
|
|
381
413
|
- `src/morphata/symbolic/bdd.py` : ``BoolExpr`` / ``dd`` bridge.
|
|
414
|
+
- `src/morphata/symbolic/compose.py` : ``compose_min_dfa`` and
|
|
415
|
+
``min_dfa_of_conjunction``.
|
|
382
416
|
- `src/morphata/symbolic/transforms.py` : ``nfa_from_afa`` /
|
|
383
417
|
``determinize`` / ``minimize``.
|
|
384
418
|
- `src/morphata/symbolic/equivalence.py` : language equivalence and
|
|
@@ -1,47 +1,132 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 2.0.3 — 2026-05-28
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
Added a new `morphata.symbolic.compose` API
|
|
8
|
+
that provides some helper functions to construct `SymbolicAutomaton` from composing two
|
|
9
|
+
minimal DFAs or to construct minimal DFAs from LTLf formula with a lot of overlapping
|
|
10
|
+
conjunctive clauses (essentially uses `compose_min_dfa`).
|
|
11
|
+
|
|
12
|
+
This helps fix some downstream issues where the AFA can have maybe 20 states
|
|
13
|
+
(like in Craftax tech trees),
|
|
14
|
+
but always using the `SymbolicAutomaton.to_min_dfa()` pipeline causes us to hit the
|
|
15
|
+
worst-case exponential blow up.
|
|
16
|
+
But, since these specifications have the structure of being conjunctive clauses of much
|
|
17
|
+
smaller minimal DFAs, having a better composition operation benefits us.
|
|
18
|
+
|
|
19
|
+
## 2.0.2 — 2026-05-27
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- The rest of the SERE surface that needed real work, rather than a desugaring rule:
|
|
24
|
+
non-length-matching intersection
|
|
25
|
+
(`NLMInter`, the `&` operator), `Complement` (`~`), and `FirstMatch`.
|
|
26
|
+
NLM intersection is handled by a local rewrite in the expansion polynomial;
|
|
27
|
+
complement dualises the polynomial and gets a small BFS-loop special case
|
|
28
|
+
so the state space stays compact.
|
|
29
|
+
`GotoRepeat`, `EqualRepeat`,
|
|
30
|
+
and bounded `FusionRepeat` desugar through `logic_asts.spec.Expr.expand`.
|
|
31
|
+
Unbounded `FusionRepeat[:*i..]` deliberately raises `NotImplementedError` —
|
|
32
|
+
I don't have a clean expansion for it yet.
|
|
33
|
+
- Benchmarking script for SERE NLM intersection, so I can see when I
|
|
34
|
+
break the perf curve.
|
|
20
35
|
|
|
21
36
|
### Changed
|
|
22
37
|
|
|
23
|
-
- `morphata.logic.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
- `morphata.logic.psl` dropped a layer of in-tree wrappers
|
|
39
|
+
and leans on `logic_asts` types directly now
|
|
40
|
+
that the upstream package carries the extended SERE surface I needed.
|
|
41
|
+
Less code, fewer places for the two sides to disagree.
|
|
42
|
+
|
|
43
|
+
### Miscellaneous
|
|
44
|
+
|
|
45
|
+
- The README is linked from `pyproject.toml`, so it actually shows up
|
|
46
|
+
on PyPI.
|
|
47
|
+
|
|
48
|
+
## 2.0.1 — 2026-05-24
|
|
49
|
+
|
|
50
|
+
The point release that delivers the SERE
|
|
51
|
+
and PSL frontends originally promised alongside 2.0,
|
|
52
|
+
plus the perf work that made the symbolic pipeline actually finish on formulas of
|
|
53
|
+
interest.
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- `morphata.logic.sere.sere_to_automaton(formula)` —
|
|
58
|
+
converts a SERE expression to an alternating finite automaton.
|
|
59
|
+
Supports `Concat`, `Fusion`, `Alt`, `Inter` (length-matching), `Repeat`
|
|
60
|
+
(bounded and unbounded),
|
|
61
|
+
and Boolean leaves (`Literal`, `Variable`, `Not`, `And`, `Or`).
|
|
62
|
+
- `morphata.logic.psl.psl_to_automaton(phi, *, finite=False)` —
|
|
63
|
+
converts a PSL expression to an alternating automaton,
|
|
64
|
+
with `Finite` acceptance for PSLf (`finite=True`) and `Büchi` acceptance
|
|
65
|
+
for full PSL (`finite=False`).
|
|
66
|
+
Supports the strong / weak / negated-strong closure operators
|
|
67
|
+
and existential / universal suffix implication.
|
|
68
|
+
Suffix implications follow Spot's overlapping semantics:
|
|
69
|
+
the last symbol matched by the SERE prefix is shared with the first position at
|
|
70
|
+
which the continuation is evaluated.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
30
73
|
|
|
31
|
-
|
|
74
|
+
- `morphata.logic.ltl` factored its per-call BDD scratch-space construction into a
|
|
75
|
+
shared helper `morphata.logic._common.make_logic_context`, reused by the SERE and PSL
|
|
76
|
+
converters.
|
|
77
|
+
Two LTL helpers (`_aut_symbolic_expansion`, `_empty_trace_value`) were renamed to
|
|
78
|
+
`ltl_symbolic_expansion` / `ltl_empty_trace_value` so PSL can delegate to them for
|
|
79
|
+
pure-LTL subformulas.
|
|
80
|
+
- Moved off `uv` and onto Pixi. `uv`'s handling of CUDA packages and
|
|
81
|
+
the way it churns the lockfile weren't working for me; Pixi does.
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
|
|
85
|
+
- New BDD constructions in `morphata.logic` take an explicit manager parameter instead
|
|
86
|
+
of silently spinning up their own.
|
|
87
|
+
- `bdd_to_boolexpr` in `morphata.symbolic.bdd` was silently folding `~x`
|
|
88
|
+
and `x` together because the CUDD complement-edge flag on the current node wasn't
|
|
89
|
+
being respected on the recursive walk.
|
|
90
|
+
Caught while rewriting `ltl_to_automaton`; fixed there.
|
|
91
|
+
|
|
92
|
+
### Performance
|
|
93
|
+
|
|
94
|
+
- `ltl_to_automaton` no longer iterates `2^|AP|` input symbols per AFA state.
|
|
95
|
+
The closure BFS keeps APs symbolic, builds an expansion polynomial with tagged atoms
|
|
96
|
+
(one tag for guard atoms, one for successor states),
|
|
97
|
+
compiles it to a per-call BDD,
|
|
98
|
+
and partitions AP-space by distinct state cofactors via the new
|
|
99
|
+
`mgr_partition_ap_by_state_residual` helper.
|
|
100
|
+
Per-AFA-state cost drops from `O(2^|AP|)` to `O(distinct successor classes)`,
|
|
101
|
+
and AP variables that don't affect a given cofactor get pruned.
|
|
102
|
+
A depth-15 sequential conjunction `F(a_0) & X(F(a_1) & X(...))`
|
|
103
|
+
that used to take ~330s and OOM at depth 20 now builds in ~0.02s.
|
|
104
|
+
The remaining wall-clock on those formulas lives in `nfa_from_afa`,
|
|
105
|
+
which is intrinsic `2^N` in macro state count.
|
|
106
|
+
- `SymbolicAutomaton.to_min_dfa()` is tractable on formulas with non-trivial `|AP|`
|
|
107
|
+
(`~5+` for monotone conjunctions, `~10+` for sequential), where it used to hang.
|
|
108
|
+
Three pieces: prime-implicant DFS (`mgr_minimal_pos_satisfying_subsets`) replaces the
|
|
109
|
+
old `2^(2^|AP|)` BDD-evaluation pass in `_nfa_macro_step` after dealternation;
|
|
110
|
+
symbolic AP-space partition helpers (`mgr_partition_ap_by_classifiers` and
|
|
111
|
+
`mgr_partition_ap_by_state_residual`) replace explicit `2^|AP|` minterm enumeration in
|
|
112
|
+
`determinize` and `nfa_from_afa`; and `_extract_dfa_target` parses the single
|
|
113
|
+
state-variable name directly instead of linear-scanning every state in the manager,
|
|
114
|
+
removing an `O(num_states^2)` per-refinement-round cost inside `minimize()`.
|
|
115
|
+
|
|
116
|
+
Sadly (but not really sadly),
|
|
117
|
+
these performance fixes make the BDD manager a viral argument in `morphata.logic`,
|
|
118
|
+
but it isn't too bad as it is optional,
|
|
119
|
+
and the `morphata.logic.*_to_automaton` functions will automatically create a
|
|
120
|
+
short-lived manager for these things.
|
|
121
|
+
|
|
122
|
+
### Known Limitations
|
|
32
123
|
|
|
33
124
|
- `psl_to_automaton` does not yet decompose LTL temporal operators
|
|
34
|
-
that wrap PSL closures at the top level
|
|
35
|
-
|
|
36
|
-
the surrounding LTL temporal operator before calling.
|
|
125
|
+
that wrap PSL closures at the top level (e.g. `Always(StrongClosure(r))`).
|
|
126
|
+
Lift the PSL fragment out of the surrounding LTL temporal operator before calling.
|
|
37
127
|
- The continuation of a `SuffixImpliesExist` / `SuffixImpliesUniv`
|
|
38
128
|
must be a pure-LTL formula; nested PSL closures inside a
|
|
39
129
|
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
130
|
|
|
46
131
|
## 2.0.0 — 2026-05-23
|
|
47
132
|
|