Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
fja
eval
Commits
d0b41a0f
Commit
d0b41a0f
authored
Feb 06, 2020
by
Kateřina Sloupová
Browse files
transformations DFA -> REG, REG -> NFA, nfa_to_str, emptiness
parent
84d04cee
Pipeline
#53402
failed with stage
in 20 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
demo.py
View file @
d0b41a0f
from
parser
import
Parser
from
objects
import
Terminal
,
Nonterminal
,
State
,
DFA
,
REG
from
objects
import
Terminal
,
Nonterminal
,
State
,
DFA
,
REG
,
NFA
from
objects
import
Composition
as
comp
from
typing
import
Set
,
Dict
,
Tuple
...
...
@@ -52,16 +52,26 @@ def reg_2():
reg
=
REG
(
nonterminals
,
terminals
,
rules
,
init
)
return
reg
def
nfa_1
():
q0
=
State
(
"q0"
)
q1
=
State
(
"q1"
)
q2
=
State
(
"q2"
)
a
=
Terminal
(
"a"
)
transition
=
{(
q0
,
a
):
{
q1
,
q2
},
(
q1
,
a
):
{
q1
},
(
q2
,
a
):
{
q2
}}
nfa
=
NFA
({
q0
,
q1
,
q2
},
{
a
},
transition
,
q0
,
{
q1
,
q2
})
return
nfa
def
main
():
dfa_1
=
make_dfa
({
"q_0, q_1"
},
{
"a"
},
{(
"q_0"
,
"a"
):
"q_1"
,
(
"q_1"
,
"a"
):
"q_1"
},
"q_0"
,
{
"q_1"
})
dfa_2
=
make_dfa
({
"r_0, r_1"
,
"r_2"
},
{
"a"
,
"b"
},
{(
"r_0"
,
"a"
):
"r_1"
,
(
"r_0"
,
"b"
):
"r_1"
,
dfa_1
=
make_dfa
({
"q_0
"
,
"
q_1"
},
{
"a"
},
{(
"q_0"
,
"a"
):
"q_1"
,
(
"q_1"
,
"a"
):
"q_1"
},
"q_0"
,
{
"q_1"
})
dfa_2
=
make_dfa
({
"r_0
"
,
"
r_1"
,
"r_2"
},
{
"a"
,
"b"
},
{(
"r_0"
,
"a"
):
"r_1"
,
(
"r_0"
,
"b"
):
"r_1"
,
(
"r_1"
,
"a"
):
"r_2"
,
(
"r_1"
,
"b"
):
"r_2"
},
"r_0"
,
{
"r_2"
})
dfa_3
=
make_dfa
({
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
},
{
"a"
,
"b"
},
{(
"1"
,
"a"
):
"2"
,
(
"2"
,
"a"
):
"3"
,
(
"2"
,
"b"
):
"4"
,
(
"3"
,
"a"
):
"6"
,
(
"3"
,
"b"
):
"5"
,
(
"4"
,
"a"
):
"3"
,
(
"4"
,
"b"
):
"2"
,
(
"5"
,
"a"
):
"6"
,
(
"5"
,
"b"
):
"3"
,
(
"6"
,
"a"
):
"2"
,
(
"7"
,
"a"
):
"6"
,
(
"7"
,
"b"
):
"1"
,
},
"1"
,
{
"3"
,
"5"
,
"6"
})
reg1
=
reg_1
()
reg2
=
reg_2
()
nfa1
=
nfa_1
()
parser
=
Parser
()
print
(
"parser.dfa_to_str():"
)
...
...
@@ -156,5 +166,28 @@ def main():
print
()
canonical
=
minimal
.
canonize
()
print
(
parser
.
dfa_to_str
(
canonical
,
True
))
print
()
print
(
"__________________________________"
)
print
(
"DFA.dfa_to_reg(), REG.reg_to_nfa()"
)
print
(
"Transformation of DFA to REG and REG to NFA"
)
print
(
"plus string representation of REG and NFA."
)
print
()
print
(
"Original DFA:"
)
dfa_4
=
make_dfa
({
"q_0"
,
"q_1"
},
{
"a"
},
{(
"q_0"
,
"a"
):
"q_1"
,
(
"q_1"
,
"a"
):
"q_1"
},
"q_0"
,
{
"q_1"
})
print
(
parser
.
dfa_to_str
(
dfa_4
,
True
))
print
()
dfareg
=
dfa_4
.
dfa_to_reg
()
print
(
"DFA transformated to REG:"
)
print
(
parser
.
reg_to_str
(
dfareg
,
True
))
print
()
regdfa
=
dfareg
.
reg_to_nfa
()
print
(
"REG transformated to NFA:"
)
print
(
parser
.
nfa_to_str
(
regdfa
,
True
))
print
()
#det = nfa1.determinize()
#print(parser.dfa_to_str(det, True))
main
()
\ No newline at end of file
objects.py
View file @
d0b41a0f
...
...
@@ -3,6 +3,7 @@ from typing import Set, List, Dict, Tuple, Optional, TypeVar
from
enum
import
Enum
import
enum
from
copy
import
deepcopy
from
collections
import
deque
class
Composition
(
Enum
):
...
...
@@ -74,6 +75,38 @@ class REG:
self
.
rules
=
self
.
dict_or_none
(
rules
)
self
.
init
=
init
def
reg_to_nfa
(
self
)
->
NFA
:
dfa
=
DFA
(
set
(),
set
(),
{},
None
,
set
())
for
nonterminal
in
self
.
nonterminals
:
state
=
State
(
nonterminal
.
name
)
dfa
.
states
.
add
(
state
)
dfa
.
terminals
=
self
.
terminals
dfa
.
init
=
State
(
self
.
init
.
name
)
final
=
State
(
"new_final"
)
# TODO assert that name is unique, as for hell in make_total
dfa
.
states
.
add
(
final
)
dfa
.
final
.
add
(
final
)
for
nonterminal
in
self
.
rules
:
for
rule
in
self
.
rules
[
nonterminal
]:
# rule A -> a becomes d(A, a) = final
if
type
(
rule
)
==
Terminal
:
# TODO and a is not \eps
if
(
nonterminal
,
rule
)
in
dfa
.
transition
:
dfa
.
transition
[
nonterminal
,
rule
].
add
(
final
)
else
:
dfa
.
transition
[
nonterminal
,
rule
]
=
{
final
}
# rule A -> aB becomes d(A, a) = B
elif
(
nonterminal
,
rule
[
0
])
in
dfa
.
transition
:
dfa
.
transition
[
nonterminal
,
rule
[
0
]].
add
(
rule
[
1
])
else
:
dfa
.
transition
[
nonterminal
,
rule
[
0
]]
=
{
rule
[
1
]}
# TODO if init -> \eps: dfa.final.add(dfa.init)
# I need to know how to treat \eps
return
dfa
class
DFA
:
Transition
=
Dict
[
Tuple
[
State
,
Terminal
],
State
]
...
...
@@ -359,6 +392,59 @@ class DFA:
i
+=
1
return
dfa
def
dfa_to_reg
(
self
)
->
REG
:
reg
=
REG
(
set
(),
set
(),
{},
None
)
for
state
in
self
.
states
:
nonterminal
=
Nonterminal
(
state
.
name
)
reg
.
nonterminals
.
add
(
nonterminal
)
reg
.
terminals
=
self
.
terminals
init
=
Nonterminal
(
"new_init"
)
# TODO assert that name is unique, as for hell in make_total
reg
.
init
=
init
reg
.
nonterminals
.
add
(
init
)
for
state
,
terminal
in
self
.
transition
:
move
=
self
.
transition
[
state
,
terminal
]
if
state
==
self
.
init
:
nonterminal2
=
Nonterminal
(
move
.
name
)
if
init
in
reg
.
rules
:
reg
.
rules
[
init
].
add
((
terminal
,
nonterminal2
))
else
:
reg
.
rules
[
init
]
=
{(
terminal
,
nonterminal2
)}
if
move
in
self
.
final
:
reg
.
rules
[
init
].
add
((
terminal
))
else
:
nonterminal1
=
Nonterminal
(
state
.
name
)
nonterminal2
=
Nonterminal
(
move
.
name
)
if
nonterminal1
in
reg
.
rules
:
reg
.
rules
[
nonterminal1
].
add
((
terminal
,
nonterminal2
))
else
:
reg
.
rules
[
nonterminal1
]
=
{(
terminal
,
nonterminal2
)}
if
move
in
self
.
final
:
reg
.
rules
[
nonterminal1
].
add
((
terminal
))
if
self
.
init
in
self
.
final
:
pass
# TODO eg.rules[init].add((\eps))
return
reg
def
is_empty
(
self
)
->
bool
:
reached
=
deque
(
self
.
init
)
reachable
=
set
(
self
.
init
)
while
len
(
reached
)
>
0
:
actual
=
reachable
.
popleft
()
for
terminal
in
self
.
terminals
:
if
self
.
transition
[
actual
,
terminal
]
is
not
None
and
self
.
transition
[
actual
,
terminal
]
not
in
reachable
:
reached
.
append
(
self
.
transition
[
actual
,
terminal
])
reachable
.
add
(
self
.
transition
[
actual
,
terminal
])
return
len
(
reachable
.
intersection
(
self
.
final
))
>
0
# Ha!
def
is_universal
(
self
):
return
self
.
is_empty
(
self
.
complement
())
class
NFA
:
def
__init__
(
self
,
states
:
Set
[
State
],
...
...
@@ -371,3 +457,38 @@ class NFA:
self
.
transition
=
transition
self
.
init
=
init
self
.
final
=
final
def
determinize
(
self
)
->
DFA
:
states
=
set
(
frozenset
(
self
.
init
))
transition
=
{}
final
=
set
()
done
=
set
()
todo
=
states
.
difference
(
done
)
while
len
(
todo
)
>
0
:
subset
=
iter
(
todo
).
next
()
# arbitrary element from set
if
subset
.
difference
(
self
.
final
)
>
0
:
final
.
add
(
subset
)
for
terminal
in
self
.
terminals
:
new_subset
=
set
()
for
state
in
subset
:
if
(
state
,
terminal
)
in
self
.
transition
:
new_subset
.
add
(
self
.
transition
[
state
,
terminal
])
states
.
add
(
new_subset
)
transition
[
subset
,
terminal
]
=
new_subset
done
.
add
(
subset
)
dfa
=
DFA
(
set
(),
self
.
terminals
,
{},
self
.
init
,
set
())
for
state
in
states
:
dfa
.
states
.
add
(
self
.
unset
(
state
))
for
state
in
final
:
dfa
.
final
.
add
(
self
.
unset
(
state
))
for
state
,
terminal
in
transition
:
dfa
.
transition
[
self
.
unset
(
state
),
terminal
]
=
self
.
unset
(
self
.
transition
[
state
,
terminal
])
# states from sets
def
unset
(
self
,
states
:
Set
[
State
])
->
State
:
return
State
(
'_'
.
join
(
states
.
name
))
parser.py
View file @
d0b41a0f
...
...
@@ -87,6 +87,48 @@ class Parser:
else
:
return
transition
+
"
\n
"
+
final
def
nfa_to_str
(
self
,
dfa
:
DFA
,
full
:
bool
=
False
)
->
str
:
# full - verbose description of DFA - only for development, dismiss later
states
=
"{"
for
state
in
dfa
.
states
:
states
+=
state
.
name
+
","
states
=
states
[:
-
1
]
+
"}"
# Vlada: states = ",".join(dfa.states) but I use it wrong or what
terminals
=
"{"
for
terminal
in
dfa
.
terminals
:
terminals
+=
terminal
.
name
+
","
terminals
=
terminals
[:
-
1
]
+
"}"
transition
=
""
for
key
,
set_states
in
dfa
.
transition
.
items
():
state_1
,
terminal
=
key
transition
+=
"("
+
state_1
.
name
+
","
+
terminal
.
name
+
")={"
for
state
in
set_states
:
transition
+=
state
.
name
+
","
transition
=
transition
[:
-
1
]
+
"}
\n
"
transition
=
"{"
+
transition
[:
-
1
]
+
"}"
init
=
dfa
.
init
.
name
final
=
"F={"
for
state
in
dfa
.
final
:
final
+=
state
.
name
+
","
final
=
final
[:
-
1
]
+
"}"
if
full
:
return
"NFA = ("
+
states
+
","
+
terminals
+
",d,"
+
\
init
+
","
+
final
+
")
\n
"
+
"d = "
+
transition
else
:
return
transition
+
"
\n
"
+
final
# TODO DFA/NFA to string are too similar
# all: string <-> formal object
# reg
# dfa
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment