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
c4aad1ac
Commit
c4aad1ac
authored
Apr 03, 2021
by
Vladimír Štill
Browse files
dfa: Fix is_canonical
parent
df5aa4c3
Changes
1
Hide whitespace changes
Inline
Side-by-side
lib/dfa.py
View file @
c4aad1ac
...
...
@@ -311,29 +311,47 @@ class DFA:
name
=
ascii_uppercase
[
num
-
1
]
+
name
return
name
def
canonize
(
self
)
->
DFA
:
@
staticmethod
def
canonic_name_for_seq
(
num
:
int
)
->
str
:
# alternatively, use self.bijective26(i) for base-26 alpha. names
return
str
(
num
)
def
_can_walk
(
self
,
state_callback
:
Callable
[
None
,
[
State
,
State
]])
->
Set
[
State
]:
seen
:
Set
[
State
]
=
set
()
characters
=
self
.
sorted_characters
()
state_map
:
Dict
[
State
,
State
]
=
{}
i
=
1
queue
=
deque
([
self
.
init
])
while
len
(
queue
)
>
0
:
actual
=
queue
.
popleft
()
if
actual
in
s
tate_map
.
keys
()
:
if
actual
in
s
een
:
continue
# alternatively, use self.bijective26(i) for base-26 alpha. names
state_
map
[
actual
]
=
State
(
s
tr
(
i
))
seen
.
add
(
actual
)
state_
callback
(
actual
,
State
(
s
elf
.
canonic_name_for_seq
(
i
))
)
i
+=
1
for
character
in
characters
:
tgt
=
self
.
transition
.
get
((
actual
,
character
))
if
tgt
is
not
None
and
tgt
not
in
s
tate_map
.
keys
()
:
if
tgt
is
not
None
and
tgt
not
in
s
een
:
queue
.
append
(
tgt
)
return
seen
def
canonize
(
self
)
->
DFA
:
"""
Returns a canonical automaton for ‹self›. Does NOT minimize the
automata, therefore canonize is useful for testing isomorfism, for
testing equivalence you should use ‹is_equivalent› or
‹minimize().canonize()›.
Precondition: ‹self› has no unreachable states (exception thrown otherwise).
"""
state_map
:
Dict
[
State
,
State
]
=
{}
def
add
(
old
:
State
,
new
:
State
):
state_map
[
old
]
=
new
seen
=
self
.
_can_walk
(
add
)
for
st
,
_
in
self
.
transition
.
keys
():
if
st
not
in
state_map
:
raise
Exception
(
"Automaton cannot be canonised, it has "
"unreachable states"
)
if
self
.
states
-
seen
:
raise
Exception
(
"Automaton cannot be canonised, it has "
"unreachable states"
)
return
DFA
(
set
(
state_map
.
values
()),
deepcopy
(
self
.
characters
),
...
...
@@ -460,7 +478,11 @@ class DFA:
return
result
@
staticmethod
def
is_part_identical
(
fst
:
DFA
,
snd
:
DFA
)
->
bool
:
def
is_identical
(
fst
:
DFA
,
snd
:
DFA
)
->
bool
:
"""
Check that two automata are identical, i.e. they are the same including
names.
"""
return
fst
.
states
==
snd
.
states
and
fst
.
characters
==
snd
.
characters
and
\
fst
.
transition
==
snd
.
transition
and
fst
.
init
==
snd
.
init
and
\
fst
.
final
==
snd
.
final
...
...
@@ -471,8 +493,16 @@ class DFA:
len
(
self
.
transition
)
==
len
(
minimal
.
transition
)
def
is_canonical
(
self
)
->
bool
:
canonic
=
self
.
canonize
()
return
DFA
.
is_part_identical
(
self
,
canonic
)
# note: not all DFAs have canonic form and therefore it is not possible
# to test if automaton is canonic by canonising it and testing for
# identity. In particular canonize() needs the automaton to have no
# unreachable states to succeed.
is_can
=
True
def
check
(
old
:
State
,
new
:
State
)
->
None
:
nonlocal
is_can
is_can
=
is_can
and
old
.
name
==
new
.
name
seen
=
self
.
_can_walk
(
check
)
return
is_can
and
self
.
states
==
seen
def
hell
(
self
,
states
):
# check: consider import itertools
...
...
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