-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfsaFrontend.py
More file actions
119 lines (99 loc) · 3.36 KB
/
fsaFrontend.py
File metadata and controls
119 lines (99 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from typing import List
from pydantic import BaseModel, Field
from .fsa import FSA, Transition
# frontend zod restricts typing, this is the current workaround
class FSAFrontend(BaseModel):
"""
Finite State Automaton representation.
Represents a 5-tuple (Q, Σ, δ, q0, F) where:
- Q = states
- Σ = alphabet
- δ = transitions (transition function)
- q0 = initial_state
- F = accept_states
Example:
{
"states": ["q0", "q1", "q2"],
"alphabet": ["a", "b"],
"transitions": [
{"from_state": "q0", "to_state": "q1", "symbol": "a"},
{"from_state": "q1", "to_state": "q2", "symbol": "b"}
],
"initial_state": "q0",
"accept_states": ["q2"]
}
"""
states: List[str] = Field(
...,
min_length=1,
description="Q: Set of all state identifiers"
)
alphabet: List[str] = Field(
...,
min_length=1,
description="Σ: Input alphabet symbols (excluding epsilon)"
)
transitions: List[str] = Field(
default_factory=list,
description="δ: Transition function as a list of (from_state, symbol, to_state) tuples"
)
initial_state: str = Field(
...,
description="q0: The starting state"
)
accept_states: List[str] = Field(
default_factory=list,
description="F: Set of accepting/final states"
)
config: str | None = Field(default=None)
class Config:
schema_extra = {
"example": {
"states": ["q0", "q1", "q2"],
"alphabet": ["a", "b"],
"transitions": [
"q0|a|q1|",
"q1|b|q2",
],
"initial_state": "q0",
"accept_states": ["q2"]
}
}
def toFSA(self) -> FSA:
transitions: List[Transition] = []
for t in self.transitions:
parts = t.split("|")
# allow trailing delimiter but enforce structure
if len(parts) == 4 and parts[-1] == "":
parts = parts[:-1]
if len(parts) != 3:
raise ValueError(
f"Invalid transition format '{t}'. "
"Expected 'from|symbol|to'"
)
from_state, symbol, to_state = parts
if from_state not in self.states:
raise ValueError(f"Unknown from_state '{from_state}'")
if to_state not in self.states:
raise ValueError(f"Unknown to_state '{to_state}'")
if symbol not in self.alphabet:
raise ValueError(f"Symbol '{symbol}' not in alphabet")
transitions.append(
Transition(
from_state=from_state,
symbol=symbol,
to_state=to_state,
)
)
if self.initial_state not in self.states:
raise ValueError("initial_state must be in states")
for s in self.accept_states:
if s not in self.states:
raise ValueError(f"Accept state '{s}' not in states")
return FSA(
states=self.states,
alphabet=self.alphabet,
transitions=transitions,
initial_state=self.initial_state,
accept_states=self.accept_states,
)