Skip to content

Commit b424ca6

Browse files
committed
add recursive automaton annotations
1 parent 63ca621 commit b424ca6

File tree

2 files changed

+48
-49
lines changed

2 files changed

+48
-49
lines changed

pyformlang/rsa/box.py

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""
22
Representation of a box for recursive automaton
33
"""
4-
from typing import Union
4+
from typing import Set, Any
55

66
from pyformlang.finite_automaton.epsilon_nfa import EpsilonNFA
77
from pyformlang.finite_automaton.finite_automaton import to_symbol
8+
from pyformlang.finite_automaton.state import State
89
from pyformlang.finite_automaton.symbol import Symbol
910

1011

@@ -22,15 +23,13 @@ class Box:
2223
2324
"""
2425

25-
def __init__(self, enfa: EpsilonNFA, nonterminal: Union[Symbol, str]):
26-
self._dfa = enfa
26+
def __init__(self, enfa: EpsilonNFA, nonterminal: Any) -> None:
27+
self._enfa: EpsilonNFA = enfa
28+
self._nonterminal: Symbol = to_symbol(nonterminal)
2729

28-
nonterminal = to_symbol(nonterminal)
29-
self._nonterminal = nonterminal
30-
31-
def to_subgraph_dot(self):
30+
def to_subgraph_dot(self) -> str:
3231
"""Creates a named subgraph representing a box"""
33-
graph = self._dfa.to_networkx()
32+
graph = self._enfa.to_networkx()
3433
strange_nodes = []
3534
nonterminal = self.nonterminal.value.replace('"', '').replace("'", "").replace(".", "")
3635
dot_string = (f'subgraph cluster_{nonterminal}\n{{ label="{nonterminal}"\n'
@@ -58,26 +57,26 @@ def to_subgraph_dot(self):
5857
return dot_string
5958

6059
@property
61-
def dfa(self):
62-
""" Box's dfa """
63-
return self._dfa
60+
def enfa(self) -> EpsilonNFA:
61+
""" Box's enfa """
62+
return self._enfa
6463

6564
@property
66-
def nonterminal(self):
65+
def nonterminal(self) -> Symbol:
6766
""" Box's nonterminal """
6867
return self._nonterminal
6968

7069
@property
71-
def start_states(self):
70+
def start_states(self) -> Set[State]:
7271
""" The start states """
73-
return self._dfa.start_states
72+
return self._enfa.start_states
7473

7574
@property
76-
def final_states(self):
75+
def final_states(self) -> Set[State]:
7776
""" The final states """
78-
return self._dfa.final_states
77+
return self._enfa.final_states
7978

80-
def is_equivalent_to(self, other):
79+
def is_equivalent_to(self, other: "Box") -> bool:
8180
""" Check whether two boxes are equivalent
8281
8382
Parameters
@@ -91,13 +90,13 @@ def is_equivalent_to(self, other):
9190
Whether the two boxes are equivalent or not
9291
"""
9392

93+
return self._enfa.is_equivalent_to(other.enfa) \
94+
and self.nonterminal == other.nonterminal
95+
96+
def __eq__(self, other: Any) -> bool:
9497
if not isinstance(other, Box):
9598
return False
96-
97-
return self._dfa.is_equivalent_to(other.dfa) and self.nonterminal == other.nonterminal
98-
99-
def __eq__(self, other):
10099
return self.is_equivalent_to(other)
101100

102-
def __hash__(self):
101+
def __hash__(self) -> int:
103102
return self._nonterminal.__hash__()

pyformlang/rsa/recursive_automaton.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Representation of a recursive automaton
33
"""
44

5-
from typing import AbstractSet, Union
5+
from typing import Dict, Set, AbstractSet, Optional, Any
66

77
from pyformlang.finite_automaton.finite_automaton import to_symbol
88
from pyformlang.finite_automaton.symbol import Symbol
@@ -28,15 +28,16 @@ class RecursiveAutomaton:
2828

2929
def __init__(self,
3030
start_box: Box,
31-
boxes: AbstractSet[Box]):
32-
self._nonterminal_to_box = {}
31+
boxes: AbstractSet[Box]) -> None:
32+
self._nonterminal_to_box: Dict[Symbol, Box] = {}
3333
if start_box not in boxes:
34-
self._nonterminal_to_box[to_symbol(start_box.nonterminal)] = start_box
35-
self._start_nonterminal = to_symbol(start_box.nonterminal)
34+
self._nonterminal_to_box[
35+
to_symbol(start_box.nonterminal)] = start_box
36+
self._start_nonterminal: Symbol = to_symbol(start_box.nonterminal)
3637
for box in boxes:
3738
self._nonterminal_to_box[to_symbol(box.nonterminal)] = box
3839

39-
def get_box_by_nonterminal(self, nonterminal: Union[Symbol, str]):
40+
def get_box_by_nonterminal(self, nonterminal: Any) -> Optional[Box]:
4041
"""
4142
Box by nonterminal
4243
@@ -54,15 +55,13 @@ def get_box_by_nonterminal(self, nonterminal: Union[Symbol, str]):
5455
nonterminal = to_symbol(nonterminal)
5556
if nonterminal in self._nonterminal_to_box:
5657
return self._nonterminal_to_box[nonterminal]
57-
5858
return None
5959

60-
def get_number_boxes(self):
60+
def get_number_boxes(self) -> int:
6161
""" Size of set of boxes """
62-
6362
return len(self._nonterminal_to_box)
6463

65-
def to_dot(self):
64+
def to_dot(self) -> str:
6665
""" Create dot representation of recursive automaton """
6766
dot_string = 'digraph "" {'
6867
for box in self._nonterminal_to_box.values():
@@ -71,31 +70,28 @@ def to_dot(self):
7170
return dot_string
7271

7372
@property
74-
def nonterminals(self) -> set:
73+
def nonterminals(self) -> Set[Symbol]:
7574
""" The set of nonterminals """
76-
7775
return set(self._nonterminal_to_box.keys())
7876

7977
@property
80-
def boxes(self) -> dict:
78+
def boxes(self) -> Dict[Symbol, Box]:
8179
""" The set of boxes """
82-
8380
return self._nonterminal_to_box
8481

8582
@property
8683
def start_nonterminal(self) -> Symbol:
8784
""" The start nonterminal """
88-
8985
return self._start_nonterminal
9086

9187
@property
92-
def start_box(self):
88+
def start_box(self) -> Box:
9389
""" The start box """
94-
9590
return self.boxes[self.start_nonterminal]
9691

9792
@classmethod
98-
def from_regex(cls, regex: Regex, start_nonterminal: Union[Symbol, str]):
93+
def from_regex(cls, regex: Regex, start_nonterminal: Any) \
94+
-> "RecursiveAutomaton":
9995
""" Create a recursive automaton from regular expression
10096
10197
Parameters
@@ -115,14 +111,17 @@ def from_regex(cls, regex: Regex, start_nonterminal: Union[Symbol, str]):
115111
return RecursiveAutomaton(box, {box})
116112

117113
@classmethod
118-
def from_ebnf(cls, text, start_nonterminal: Union[Symbol, str] = Symbol("S")):
119-
""" Create a recursive automaton from ebnf (ebnf = Extended Backus-Naur Form)
114+
def from_ebnf(cls, text: str, start_nonterminal: Any = Symbol("S")) \
115+
-> "RecursiveAutomaton":
116+
""" Create a recursive automaton from ebnf \
117+
(ebnf = Extended Backus-Naur Form)
120118
121119
Parameters
122120
-----------
123121
text : str
124122
The text of transform
125-
start_nonterminal : :class:`~pyformlang.finite_automaton.Symbol` | str, optional
123+
start_nonterminal : \
124+
:class:`~pyformlang.finite_automaton.Symbol` | str, optional
126125
The start nonterminal, S by default
127126
128127
Returns
@@ -155,10 +154,11 @@ def from_ebnf(cls, text, start_nonterminal: Union[Symbol, str] = Symbol("S")):
155154
for head, body in productions.items():
156155
boxes.add(Box(Regex(body).to_epsilon_nfa().minimize(),
157156
to_symbol(head)))
158-
start_box = Box(Regex(productions[start_nonterminal.value]).to_epsilon_nfa().minimize(), start_nonterminal)
157+
start_box = Box(Regex(productions[start_nonterminal.value]) \
158+
.to_epsilon_nfa().minimize(), start_nonterminal)
159159
return RecursiveAutomaton(start_box, boxes)
160160

161-
def is_equals_to(self, other):
161+
def is_equal_to(self, other: "RecursiveAutomaton") -> bool:
162162
"""
163163
Check whether two recursive automata are equals by boxes.
164164
Not equivalency in terms of formal languages theory, just mapping boxes
@@ -173,9 +173,9 @@ def is_equals_to(self, other):
173173
are_equivalent : bool
174174
Whether the two recursive automata are equals or not
175175
"""
176-
if not isinstance(other, RecursiveAutomaton):
177-
return False
178176
return self.boxes == other.boxes
179177

180-
def __eq__(self, other):
181-
return self.is_equals_to(other)
178+
def __eq__(self, other: Any) -> bool:
179+
if not isinstance(other, RecursiveAutomaton):
180+
return False
181+
return self.is_equal_to(other)

0 commit comments

Comments
 (0)