morphata 1.0.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-1.0.0/PKG-INFO +169 -0
- morphata-1.0.0/README.md +155 -0
- morphata-1.0.0/pyproject.toml +19 -0
- morphata-1.0.0/src/morphata/__init__.py +78 -0
- morphata-1.0.0/src/morphata/acceptance.py +222 -0
- morphata-1.0.0/src/morphata/automaton.py +0 -0
- morphata-1.0.0/src/morphata/examples/__init__.py +0 -0
- morphata-1.0.0/src/morphata/examples/ltl.py +255 -0
- morphata-1.0.0/src/morphata/examples/nfa.py +218 -0
- morphata-1.0.0/src/morphata/examples/strel.py +545 -0
- morphata-1.0.0/src/morphata/hoa/__init__.py +34 -0
- morphata-1.0.0/src/morphata/hoa/__main__.py +40 -0
- morphata-1.0.0/src/morphata/hoa/acc_expr.py +208 -0
- morphata-1.0.0/src/morphata/hoa/exporter.py +1 -0
- morphata-1.0.0/src/morphata/hoa/hoa.lark +60 -0
- morphata-1.0.0/src/morphata/hoa/parser.py +378 -0
- morphata-1.0.0/src/morphata/py.typed +0 -0
- morphata-1.0.0/src/morphata/spec.py +121 -0
- morphata-1.0.0/src/morphata/utils.py +0 -0
morphata-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: morphata
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Flexible automata representations for regular and ω-regular languages.
|
|
5
|
+
Author: Anand Balakrishnan
|
|
6
|
+
Requires-Dist: typing-extensions
|
|
7
|
+
Requires-Dist: lark
|
|
8
|
+
Requires-Dist: logic-asts>=1.4.1
|
|
9
|
+
Requires-Dist: networkx
|
|
10
|
+
Requires-Dist: types-networkx
|
|
11
|
+
Requires-Dist: attrs>=25.4.0
|
|
12
|
+
Requires-Python: >=3.12
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# Morphata
|
|
16
|
+
|
|
17
|
+
Morphata is a Python library for constructing, manipulating, and translating
|
|
18
|
+
automata over regular and omega-regular languages.
|
|
19
|
+
It provides flexible graph-based representations for automata without committing
|
|
20
|
+
to any specific model checking or monitoring algorithm.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Graph-based automata implementations**
|
|
25
|
+
- Nondeterministic Finite Automata (NFA) for finite words
|
|
26
|
+
- STREL automata for spatio-temporal specifications
|
|
27
|
+
|
|
28
|
+
- **HOA format parser**
|
|
29
|
+
- Extended HOA v1 format with finite-word acceptance support
|
|
30
|
+
- Standard acceptance conditions:
|
|
31
|
+
Buchi, co-Buchi, Rabin, Streett, Parity, Muller
|
|
32
|
+
- Extension:
|
|
33
|
+
`Final(n)` operator for finite-word automata (not in standard HOA v1)
|
|
34
|
+
- Validation and error reporting
|
|
35
|
+
|
|
36
|
+
- **Acceptance conditions**
|
|
37
|
+
- Expression algebra for omega-regular conditions
|
|
38
|
+
- Classical acceptance types (Buchi, generalized-Buchi, co-Buchi, Rabin,
|
|
39
|
+
Streett, Muller, Parity)
|
|
40
|
+
- Finite-word acceptance for regular languages
|
|
41
|
+
|
|
42
|
+
- **Pure structural interfaces**
|
|
43
|
+
- Base automaton interfaces without weighted semantics
|
|
44
|
+
- NetworkX-based graph representations
|
|
45
|
+
- Clean separation from quantitative monitoring (provided by automatix)
|
|
46
|
+
|
|
47
|
+
## Architecture
|
|
48
|
+
|
|
49
|
+
Morphata serves as the foundation for the automatix library:
|
|
50
|
+
|
|
51
|
+
- **morphata**:
|
|
52
|
+
Graph-based automata, HOA parsing, acceptance conditions
|
|
53
|
+
- **automatix**:
|
|
54
|
+
Weighted automata over semirings (depends on morphata)
|
|
55
|
+
- **algebraic**:
|
|
56
|
+
Pure semiring algebra (independent)
|
|
57
|
+
|
|
58
|
+
This layered architecture allows morphata to be used independently for
|
|
59
|
+
structural automata operations, or as a foundation for weighted semantics.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
Morphata is part of the automatix workspace.
|
|
64
|
+
Install using uv:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv pip install -e packages/morphata
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick Example
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from morphata.automata import NFA
|
|
74
|
+
from logic_asts import base
|
|
75
|
+
|
|
76
|
+
# Create an NFA
|
|
77
|
+
nfa = NFA[str]()
|
|
78
|
+
nfa.add_location(0, initial=True)
|
|
79
|
+
nfa.add_location(1, final=True)
|
|
80
|
+
|
|
81
|
+
# Add transition with guard
|
|
82
|
+
guard_a = base.Variable("a")
|
|
83
|
+
nfa.add_transition(0, 1, guard_a)
|
|
84
|
+
|
|
85
|
+
# Use the automaton
|
|
86
|
+
accepting, next_state = nfa({"a"}, nfa.initial_state)
|
|
87
|
+
print(f"Accepting: {accepting}, Next state: {next_state}")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## HOA Parser Example
|
|
91
|
+
|
|
92
|
+
### Standard HOA Format (Omega-Automata)
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from morphata.hoa.parser import parse
|
|
96
|
+
|
|
97
|
+
hoa_string = """
|
|
98
|
+
HOA: v1
|
|
99
|
+
States: 2
|
|
100
|
+
Start: 0
|
|
101
|
+
acc-name: Buchi
|
|
102
|
+
Acceptance: 1 Inf(0)
|
|
103
|
+
AP: 1 "a"
|
|
104
|
+
--BODY--
|
|
105
|
+
State: 0
|
|
106
|
+
[0] 1
|
|
107
|
+
State: 1 {0}
|
|
108
|
+
[t] 1
|
|
109
|
+
--END--
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
automaton = parse(hoa_string)
|
|
113
|
+
print(f"Acceptance: {automaton.header.acc}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Extended Format: Finite-Word Acceptance
|
|
117
|
+
|
|
118
|
+
Morphata extends the HOA v1 format with a `Final(n)` operator for finite-word
|
|
119
|
+
automata.
|
|
120
|
+
This is **not part of the standard HOA specification** but provides a natural
|
|
121
|
+
way to express finite-word acceptance in the HOA syntax.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from morphata.hoa.parser import parse
|
|
125
|
+
|
|
126
|
+
finite_hoa = """
|
|
127
|
+
HOA: v1
|
|
128
|
+
States: 2
|
|
129
|
+
Start: 0
|
|
130
|
+
acc-name: Finite
|
|
131
|
+
Acceptance: 1 Final(0)
|
|
132
|
+
AP: 1 "a"
|
|
133
|
+
--BODY--
|
|
134
|
+
State: 0
|
|
135
|
+
[0] 1 {0}
|
|
136
|
+
[!0] 0
|
|
137
|
+
State: 1
|
|
138
|
+
[t] 1
|
|
139
|
+
--END--
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
automaton = parse(finite_hoa)
|
|
143
|
+
# Accepts finite words ending with 'a'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Note**:
|
|
147
|
+
The `Final(n)` operator semantics differ from `Fin(n)` and `Inf(n)`:
|
|
148
|
+
- `Inf(n)`:
|
|
149
|
+
Accept if acceptance set n is visited **infinitely often** (omega-regular)
|
|
150
|
+
- `Fin(n)`:
|
|
151
|
+
Accept if acceptance set n is visited **finitely often** (omega-regular)
|
|
152
|
+
- `Final(n)`:
|
|
153
|
+
Accept if the run **ends in** a state marked with acceptance set n (regular)
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
Run tests:
|
|
158
|
+
```bash
|
|
159
|
+
python -m pytest packages/morphata/tests/ -v
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Type checking:
|
|
163
|
+
```bash
|
|
164
|
+
python -m mypy packages/morphata/src/morphata/ --strict
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
Part of the automatix project.
|
morphata-1.0.0/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Morphata
|
|
2
|
+
|
|
3
|
+
Morphata is a Python library for constructing, manipulating, and translating
|
|
4
|
+
automata over regular and omega-regular languages.
|
|
5
|
+
It provides flexible graph-based representations for automata without committing
|
|
6
|
+
to any specific model checking or monitoring algorithm.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Graph-based automata implementations**
|
|
11
|
+
- Nondeterministic Finite Automata (NFA) for finite words
|
|
12
|
+
- STREL automata for spatio-temporal specifications
|
|
13
|
+
|
|
14
|
+
- **HOA format parser**
|
|
15
|
+
- Extended HOA v1 format with finite-word acceptance support
|
|
16
|
+
- Standard acceptance conditions:
|
|
17
|
+
Buchi, co-Buchi, Rabin, Streett, Parity, Muller
|
|
18
|
+
- Extension:
|
|
19
|
+
`Final(n)` operator for finite-word automata (not in standard HOA v1)
|
|
20
|
+
- Validation and error reporting
|
|
21
|
+
|
|
22
|
+
- **Acceptance conditions**
|
|
23
|
+
- Expression algebra for omega-regular conditions
|
|
24
|
+
- Classical acceptance types (Buchi, generalized-Buchi, co-Buchi, Rabin,
|
|
25
|
+
Streett, Muller, Parity)
|
|
26
|
+
- Finite-word acceptance for regular languages
|
|
27
|
+
|
|
28
|
+
- **Pure structural interfaces**
|
|
29
|
+
- Base automaton interfaces without weighted semantics
|
|
30
|
+
- NetworkX-based graph representations
|
|
31
|
+
- Clean separation from quantitative monitoring (provided by automatix)
|
|
32
|
+
|
|
33
|
+
## Architecture
|
|
34
|
+
|
|
35
|
+
Morphata serves as the foundation for the automatix library:
|
|
36
|
+
|
|
37
|
+
- **morphata**:
|
|
38
|
+
Graph-based automata, HOA parsing, acceptance conditions
|
|
39
|
+
- **automatix**:
|
|
40
|
+
Weighted automata over semirings (depends on morphata)
|
|
41
|
+
- **algebraic**:
|
|
42
|
+
Pure semiring algebra (independent)
|
|
43
|
+
|
|
44
|
+
This layered architecture allows morphata to be used independently for
|
|
45
|
+
structural automata operations, or as a foundation for weighted semantics.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
Morphata is part of the automatix workspace.
|
|
50
|
+
Install using uv:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv pip install -e packages/morphata
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Example
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from morphata.automata import NFA
|
|
60
|
+
from logic_asts import base
|
|
61
|
+
|
|
62
|
+
# Create an NFA
|
|
63
|
+
nfa = NFA[str]()
|
|
64
|
+
nfa.add_location(0, initial=True)
|
|
65
|
+
nfa.add_location(1, final=True)
|
|
66
|
+
|
|
67
|
+
# Add transition with guard
|
|
68
|
+
guard_a = base.Variable("a")
|
|
69
|
+
nfa.add_transition(0, 1, guard_a)
|
|
70
|
+
|
|
71
|
+
# Use the automaton
|
|
72
|
+
accepting, next_state = nfa({"a"}, nfa.initial_state)
|
|
73
|
+
print(f"Accepting: {accepting}, Next state: {next_state}")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## HOA Parser Example
|
|
77
|
+
|
|
78
|
+
### Standard HOA Format (Omega-Automata)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from morphata.hoa.parser import parse
|
|
82
|
+
|
|
83
|
+
hoa_string = """
|
|
84
|
+
HOA: v1
|
|
85
|
+
States: 2
|
|
86
|
+
Start: 0
|
|
87
|
+
acc-name: Buchi
|
|
88
|
+
Acceptance: 1 Inf(0)
|
|
89
|
+
AP: 1 "a"
|
|
90
|
+
--BODY--
|
|
91
|
+
State: 0
|
|
92
|
+
[0] 1
|
|
93
|
+
State: 1 {0}
|
|
94
|
+
[t] 1
|
|
95
|
+
--END--
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
automaton = parse(hoa_string)
|
|
99
|
+
print(f"Acceptance: {automaton.header.acc}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Extended Format: Finite-Word Acceptance
|
|
103
|
+
|
|
104
|
+
Morphata extends the HOA v1 format with a `Final(n)` operator for finite-word
|
|
105
|
+
automata.
|
|
106
|
+
This is **not part of the standard HOA specification** but provides a natural
|
|
107
|
+
way to express finite-word acceptance in the HOA syntax.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from morphata.hoa.parser import parse
|
|
111
|
+
|
|
112
|
+
finite_hoa = """
|
|
113
|
+
HOA: v1
|
|
114
|
+
States: 2
|
|
115
|
+
Start: 0
|
|
116
|
+
acc-name: Finite
|
|
117
|
+
Acceptance: 1 Final(0)
|
|
118
|
+
AP: 1 "a"
|
|
119
|
+
--BODY--
|
|
120
|
+
State: 0
|
|
121
|
+
[0] 1 {0}
|
|
122
|
+
[!0] 0
|
|
123
|
+
State: 1
|
|
124
|
+
[t] 1
|
|
125
|
+
--END--
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
automaton = parse(finite_hoa)
|
|
129
|
+
# Accepts finite words ending with 'a'
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Note**:
|
|
133
|
+
The `Final(n)` operator semantics differ from `Fin(n)` and `Inf(n)`:
|
|
134
|
+
- `Inf(n)`:
|
|
135
|
+
Accept if acceptance set n is visited **infinitely often** (omega-regular)
|
|
136
|
+
- `Fin(n)`:
|
|
137
|
+
Accept if acceptance set n is visited **finitely often** (omega-regular)
|
|
138
|
+
- `Final(n)`:
|
|
139
|
+
Accept if the run **ends in** a state marked with acceptance set n (regular)
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
Run tests:
|
|
144
|
+
```bash
|
|
145
|
+
python -m pytest packages/morphata/tests/ -v
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Type checking:
|
|
149
|
+
```bash
|
|
150
|
+
python -m mypy packages/morphata/src/morphata/ --strict
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
Part of the automatix project.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "morphata"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Flexible automata representations for regular and ω-regular languages."
|
|
5
|
+
authors = [{ name = "Anand Balakrishnan" }]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"typing-extensions",
|
|
10
|
+
"lark",
|
|
11
|
+
"logic-asts>=1.4.1",
|
|
12
|
+
"networkx",
|
|
13
|
+
"types-networkx",
|
|
14
|
+
"attrs>=25.4.0",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["uv_build>=0.9.22,<0.10.0"]
|
|
19
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Morphata: Flexible automata representations for regular and omega-regular languages.
|
|
2
|
+
|
|
3
|
+
This package provides:
|
|
4
|
+
- Pure structural automaton interfaces (Automaton, Domain, TransitionRelation)
|
|
5
|
+
- Acceptance condition expressions (morphata.acceptance)
|
|
6
|
+
- HOA format parser (morphata.hoa.parser)
|
|
7
|
+
- Example implementations (morphata.examples)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Hashable, Mapping
|
|
13
|
+
from collections.abc import Set as AbstractSet
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
|
|
16
|
+
from typing_extensions import override
|
|
17
|
+
|
|
18
|
+
from morphata.spec import AcceptanceCondition as AcceptanceCondition
|
|
19
|
+
from morphata.spec import (
|
|
20
|
+
AlternatingTransitions,
|
|
21
|
+
BoolExpr,
|
|
22
|
+
DeterministicTransitions,
|
|
23
|
+
NonDeterministicTransitions,
|
|
24
|
+
UniversalTransitions,
|
|
25
|
+
)
|
|
26
|
+
from morphata.spec import Automaton as Automaton
|
|
27
|
+
from morphata.spec import Domain as Domain
|
|
28
|
+
from morphata.spec import InitialState as InitialState
|
|
29
|
+
from morphata.spec import TransitionRelation as TransitionRelation
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class DeterministicTransitionRelation[Q: Hashable, S: Hashable](DeterministicTransitions[Q, S]):
|
|
34
|
+
data: Mapping[Q, Mapping[S, Q]]
|
|
35
|
+
|
|
36
|
+
@override
|
|
37
|
+
def __call__(self, state: Q, symbol: S) -> Q:
|
|
38
|
+
return self.data[state][symbol]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class NonDeterministicTransitionRelation[Q: Hashable, S: Hashable](NonDeterministicTransitions[Q, S]):
|
|
43
|
+
data: Mapping[Q, Mapping[S, AbstractSet[Q]]]
|
|
44
|
+
|
|
45
|
+
@override
|
|
46
|
+
def __call__(self, state: Q, symbol: S) -> AbstractSet[Q]:
|
|
47
|
+
return self.data[state][symbol]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class UniversalTransitionRelation[Q: Hashable, S: Hashable](UniversalTransitions[Q, S]):
|
|
52
|
+
data: Mapping[Q, Mapping[S, AbstractSet[Q]]]
|
|
53
|
+
|
|
54
|
+
@override
|
|
55
|
+
def __call__(self, state: Q, symbol: S) -> AbstractSet[Q]:
|
|
56
|
+
return self.data[state][symbol]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class AlternatingTransitionRelation[Q: Hashable, S: Hashable](AlternatingTransitions[Q, S]):
|
|
61
|
+
data: Mapping[Q, Mapping[S, BoolExpr[Q]]]
|
|
62
|
+
|
|
63
|
+
@override
|
|
64
|
+
def __call__(self, state: Q, symbol: S) -> BoolExpr[Q]:
|
|
65
|
+
return self.data[state][symbol]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
"Domain",
|
|
70
|
+
"InitialState",
|
|
71
|
+
"AcceptanceCondition",
|
|
72
|
+
"TransitionRelation",
|
|
73
|
+
"DeterministicTransitions",
|
|
74
|
+
"NonDeterministicTransitions",
|
|
75
|
+
"UniversalTransitions",
|
|
76
|
+
"AlternatingTransitions",
|
|
77
|
+
"Automaton",
|
|
78
|
+
]
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""Concrete classes for acceptance conditions
|
|
2
|
+
|
|
3
|
+
Provides abstract and concrete acceptance condition classes for omega-automata
|
|
4
|
+
and finite-word automata.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import typing as ty
|
|
10
|
+
from collections.abc import Iterable
|
|
11
|
+
|
|
12
|
+
from attrs import frozen
|
|
13
|
+
from typing_extensions import overload
|
|
14
|
+
|
|
15
|
+
from morphata.spec import AcceptanceCondition, State
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@overload
|
|
19
|
+
def acc_from_name(name: ty.Literal["Finite"], arg: Iterable[State], /) -> Finite[State]: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@overload
|
|
23
|
+
def acc_from_name(name: ty.Literal["Buchi"], arg: Iterable[State], /) -> Buchi[State]: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@overload
|
|
27
|
+
def acc_from_name(name: ty.Literal["co-Buchi"], arg: Iterable[State], /) -> CoBuchi[State]: ...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@overload
|
|
31
|
+
def acc_from_name(name: ty.Literal["generalized-Buchi"], /, *args: Iterable[State]) -> GeneralizedBuchi[State]: ...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@overload
|
|
35
|
+
def acc_from_name(name: ty.Literal["generalized-co-Buchi"], /, *args: Iterable[State]) -> GeneralizedCoBuchi[State]: ...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@overload
|
|
39
|
+
def acc_from_name(name: ty.Literal["Muller"], /, *args: Iterable[State]) -> Muller[State]: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@overload
|
|
43
|
+
def acc_from_name(name: ty.Literal["Streett"], /, *args: AccPair[State]) -> Streett[State]: ...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@overload
|
|
47
|
+
def acc_from_name(name: ty.Literal["Rabin"], /, *args: AccPair[State]) -> Rabin[State]: ...
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def acc_from_name(name: str, /, *args) -> AcceptanceCondition[State]:
|
|
51
|
+
match name:
|
|
52
|
+
case "Finite":
|
|
53
|
+
assert len(args) == 1, "Finite acceptance condition requires 1 accepting set"
|
|
54
|
+
arg = args[0]
|
|
55
|
+
assert isinstance(arg, Iterable)
|
|
56
|
+
return Finite(frozenset(arg))
|
|
57
|
+
case "Buchi":
|
|
58
|
+
assert len(args) == 1, "Buchi acceptance condition requires 1 accepting set"
|
|
59
|
+
arg = args[0]
|
|
60
|
+
assert isinstance(arg, Iterable)
|
|
61
|
+
return Buchi(frozenset(arg))
|
|
62
|
+
case "generalized-Buchi":
|
|
63
|
+
assert len(args) >= 0 and all(isinstance(arg, Iterable) for arg in args), (
|
|
64
|
+
"Generalized Buchi condition needs a list of accepting sets"
|
|
65
|
+
)
|
|
66
|
+
return GeneralizedBuchi(tuple(frozenset(arg) for arg in args))
|
|
67
|
+
case "co-Buchi":
|
|
68
|
+
assert len(args) == 1, "CoBuchi acceptance condition requires 1 non-accepting set"
|
|
69
|
+
arg = args[0]
|
|
70
|
+
assert isinstance(arg, Iterable)
|
|
71
|
+
return CoBuchi(frozenset(arg))
|
|
72
|
+
case "generalized-co-Buchi":
|
|
73
|
+
assert len(args) >= 0 and all(isinstance(arg, Iterable) for arg in args), (
|
|
74
|
+
"Generalized CoBuchi condition needs a list of non-accepting sets"
|
|
75
|
+
)
|
|
76
|
+
return GeneralizedCoBuchi(tuple(frozenset(arg) for arg in args))
|
|
77
|
+
case "Streett":
|
|
78
|
+
assert len(args) >= 0 and all(isinstance(arg, tuple) and len(arg) == 2 for arg in args), (
|
|
79
|
+
"Streett condition needs a list of 2-tuples of rejecting (Fin) and accepting (Inf) sets"
|
|
80
|
+
)
|
|
81
|
+
return Streett(tuple(AccPair(*(frozenset(s) for s in arg)) for arg in args))
|
|
82
|
+
case "Rabin":
|
|
83
|
+
assert len(args) >= 0 and all(isinstance(arg, tuple) and len(arg) == 2 for arg in args), (
|
|
84
|
+
"Rabin condition needs a list of 2-tuples of rejecting (Fin) and accepting (Inf) sets"
|
|
85
|
+
)
|
|
86
|
+
return Rabin(tuple(AccPair(*(frozenset(s) for s in arg)) for arg in args))
|
|
87
|
+
|
|
88
|
+
case _:
|
|
89
|
+
raise ValueError(f"Unknown/unsupported named acceptance condition: {name} {args=}")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# @frozen
|
|
93
|
+
# class GenericCondition(AcceptanceCondition[State]):
|
|
94
|
+
# acceptance_sets: tuple[frozenset[State], ...]
|
|
95
|
+
# expr: AccExpr
|
|
96
|
+
|
|
97
|
+
# @override
|
|
98
|
+
# def __len__(self) -> int:
|
|
99
|
+
# return self.num_sets
|
|
100
|
+
|
|
101
|
+
# @override
|
|
102
|
+
# def to_expr(self) -> AccExpr:
|
|
103
|
+
# return self.expr
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@frozen
|
|
107
|
+
class Finite(AcceptanceCondition[State]):
|
|
108
|
+
"""Finite-word acceptance condition.
|
|
109
|
+
|
|
110
|
+
For finite automata, acceptance means reaching a final state. This uses
|
|
111
|
+
a single acceptance set to mark final states.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
accepting: frozenset[State]
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def is_omega_regular(cls) -> bool:
|
|
118
|
+
"""Finite-word acceptance is not omega-regular."""
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@frozen
|
|
123
|
+
class Buchi(AcceptanceCondition[State]):
|
|
124
|
+
"""Büchi condition: a run, r, is accepting iff inf(r) intersects with `accepting`"""
|
|
125
|
+
|
|
126
|
+
accepting: frozenset[State]
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def is_omega_regular(cls) -> bool:
|
|
130
|
+
"""Büchi acceptance is omega-regular."""
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@frozen
|
|
135
|
+
class GeneralizedBuchi(AcceptanceCondition[State]):
|
|
136
|
+
"""Generalized Büchi condition: a run, r, is accepting iff inf(r) intersects with `accepting[i]` for some i"""
|
|
137
|
+
|
|
138
|
+
accepting: tuple[frozenset[State], ...]
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def is_omega_regular(cls) -> bool:
|
|
142
|
+
"""Generalized Büchi acceptance is omega-regular."""
|
|
143
|
+
return True
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@frozen
|
|
147
|
+
class CoBuchi(AcceptanceCondition[State]):
|
|
148
|
+
"""co-Büchi condition: a run, r, is accepting iff inf(r) does not intersect with `rejecting`"""
|
|
149
|
+
|
|
150
|
+
rejecting: frozenset[State]
|
|
151
|
+
|
|
152
|
+
@classmethod
|
|
153
|
+
def is_omega_regular(cls) -> bool:
|
|
154
|
+
"""co-Büchi acceptance is omega-regular."""
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@frozen
|
|
159
|
+
class GeneralizedCoBuchi(AcceptanceCondition[State]):
|
|
160
|
+
"""Generalized co-Büchi condition: a run, r, is accepting iff inf(r) does not intersect with `rejecting[i]` for some i"""
|
|
161
|
+
|
|
162
|
+
rejecting: tuple[frozenset[State], ...]
|
|
163
|
+
|
|
164
|
+
@classmethod
|
|
165
|
+
def is_omega_regular(cls) -> bool:
|
|
166
|
+
"""Generalized co-Büchi acceptance is omega-regular."""
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class AccPair(ty.NamedTuple, ty.Generic[State]):
|
|
171
|
+
"""Pair of accepting and rejecting state sets for Rabin/Streett conditions."""
|
|
172
|
+
|
|
173
|
+
rejecting: frozenset[State]
|
|
174
|
+
"""States that must not appear infinitely often"""
|
|
175
|
+
accepting: frozenset[State]
|
|
176
|
+
"""States that must appear infinitely often"""
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@frozen
|
|
180
|
+
class Streett(AcceptanceCondition[State]):
|
|
181
|
+
"""Streett condition: a run, r, is accpting iff _for all_ `i`, we have that inf(r) does not intersect with `pairs[i].rejecting` and does intersect with `pairs[i].accepting`"""
|
|
182
|
+
|
|
183
|
+
pairs: tuple[AccPair[State], ...]
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def index(self) -> int:
|
|
187
|
+
"""Number of pairs in this condition."""
|
|
188
|
+
return len(self.pairs)
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def is_omega_regular(cls) -> bool:
|
|
192
|
+
"""Streett acceptance is omega-regular."""
|
|
193
|
+
return True
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@frozen
|
|
197
|
+
class Rabin(AcceptanceCondition[State]):
|
|
198
|
+
"""Rabin condition: a run, r, is accpting iff _for some_ `i`, we have that inf(r) does not intersect with `pairs[i].rejecting` and does intersect with `pairs[i].accepting`"""
|
|
199
|
+
|
|
200
|
+
pairs: tuple[AccPair[State], ...]
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def index(self) -> int:
|
|
204
|
+
"""Number of pairs in this condition."""
|
|
205
|
+
return len(self.pairs)
|
|
206
|
+
|
|
207
|
+
@classmethod
|
|
208
|
+
def is_omega_regular(cls) -> bool:
|
|
209
|
+
"""Rabin acceptance is omega-regular."""
|
|
210
|
+
return True
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@frozen
|
|
214
|
+
class Muller(AcceptanceCondition[State]):
|
|
215
|
+
"""Muller condition: a run, r, is accepting iff for some `i`, we have that inf(r) is exactly `sets[i]`"""
|
|
216
|
+
|
|
217
|
+
sets: tuple[frozenset[State], ...]
|
|
218
|
+
|
|
219
|
+
@classmethod
|
|
220
|
+
def is_omega_regular(cls) -> bool:
|
|
221
|
+
"""Muller acceptance is omega-regular."""
|
|
222
|
+
return True
|
|
File without changes
|
|
File without changes
|