NFA: implement transitions as dict instead of function
Some checks failed
test / test (push) Has been cancelled
Some checks failed
test / test (push) Has been cancelled
This commit is contained in:
parent
bbfa3cad87
commit
1deb18ef22
156
src/glemt.gleam
156
src/glemt.gleam
@ -1,37 +1,110 @@
|
|||||||
import gleam/list
|
import gleam/dict.{type Dict}
|
||||||
import gleam/string
|
|
||||||
import gleam/set.{type Set}
|
|
||||||
import gleam/io
|
import gleam/io
|
||||||
|
import gleam/list
|
||||||
|
import gleam/result
|
||||||
|
import gleam/set.{type Set}
|
||||||
|
import gleam/string
|
||||||
|
|
||||||
//pub type State {
|
pub type State =
|
||||||
// State(Int)
|
Int
|
||||||
//}
|
|
||||||
|
|
||||||
pub type State = Int
|
pub type AlphabetChar =
|
||||||
|
String
|
||||||
|
|
||||||
//pub type AlphabetChar {
|
pub type NFATransitionKey =
|
||||||
// AlphabetChar(String)
|
#(State, AlphabetChar)
|
||||||
//}
|
|
||||||
|
|
||||||
pub type AlphabetChar = String
|
pub type NFATransitionFunction =
|
||||||
|
Dict(NFATransitionKey, Set(State))
|
||||||
|
|
||||||
pub type NFAError {
|
pub type NFAError {
|
||||||
NoTransition
|
NoTransition
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type NFA {
|
pub type NFA {
|
||||||
NFA(states: Set(State), alphabet: Set(AlphabetChar), transition_func: fn(Set(State), AlphabetChar) -> Set(State), init_state: State, accepting_states: Set(State))
|
NFA(
|
||||||
|
states: Set(State),
|
||||||
|
alphabet: Set(AlphabetChar),
|
||||||
|
transitions: NFATransitionFunction,
|
||||||
|
init_state: State,
|
||||||
|
accepting_states: Set(State),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub type DFAViolation {
|
pub type DFAViolation {
|
||||||
// NotAllTransitionsDefined(state: State, missing_chars: Set(AlphabetChar))
|
NotAllTransitionsDefined(state: State, missing_chars: Set(AlphabetChar))
|
||||||
// MultiplePossibleTransitions(state: State, duplicate_chars: Set(AlphabetChar))
|
MultiplePossibleTransitions(state: State, duplicate_chars: Set(AlphabetChar))
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
pub fn is_dfa(nfa: NFA) -> Result(Nil, List(DFAViolation)) {
|
||||||
|
let violations =
|
||||||
|
nfa.states
|
||||||
|
|> set.map(fn(state) {
|
||||||
|
let missing_transitions =
|
||||||
|
nfa.alphabet
|
||||||
|
|> set.filter(fn(char) {
|
||||||
|
nfa.transitions
|
||||||
|
|> dict.get(#(state, char))
|
||||||
|
|> result.unwrap(set.new())
|
||||||
|
|> set.is_empty
|
||||||
|
})
|
||||||
|
|
||||||
|
let multi_transitions =
|
||||||
|
nfa.transitions
|
||||||
|
|> dict.filter(fn(_key, val) { set.size(val) > 1 })
|
||||||
|
|> dict.keys
|
||||||
|
|> list.map(fn(transition_key) { transition_key.1 })
|
||||||
|
|> set.from_list
|
||||||
|
|
||||||
|
let missing_transitions = case set.size(missing_transitions) {
|
||||||
|
count if count > 0 -> [
|
||||||
|
NotAllTransitionsDefined(state, missing_transitions),
|
||||||
|
]
|
||||||
|
_ -> []
|
||||||
|
}
|
||||||
|
|
||||||
|
let multi_transitions = case set.size(multi_transitions) {
|
||||||
|
count if count > 0 -> [
|
||||||
|
MultiplePossibleTransitions(state, multi_transitions),
|
||||||
|
]
|
||||||
|
_ -> []
|
||||||
|
}
|
||||||
|
|
||||||
|
list.append(missing_transitions, multi_transitions)
|
||||||
|
})
|
||||||
|
|> set.to_list
|
||||||
|
|> list.flatten
|
||||||
|
|
||||||
|
case list.length(violations) {
|
||||||
|
count if count > 0 -> Error(violations)
|
||||||
|
_ -> Ok(Nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec_transition(
|
||||||
|
transitions: Dict(#(State, AlphabetChar), Set(State)),
|
||||||
|
states: Set(State),
|
||||||
|
char: AlphabetChar,
|
||||||
|
) -> Set(State) {
|
||||||
|
states
|
||||||
|
|> set.filter(fn(state) { dict.has_key(transitions, #(state, char)) })
|
||||||
|
|> set.fold(set.new(), fn(new_states, state) {
|
||||||
|
new_states
|
||||||
|
|> set.union(
|
||||||
|
transitions
|
||||||
|
|> dict.get(#(state, char))
|
||||||
|
|> result.unwrap(set.new()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_string(nfa: NFA, input: String) -> Bool {
|
pub fn check_string(nfa: NFA, input: String) -> Bool {
|
||||||
let final_states = input
|
let final_states =
|
||||||
|> string.to_graphemes
|
input
|
||||||
|> list.fold(set.from_list([nfa.init_state]), nfa.transition_func)
|
|> string.to_graphemes
|
||||||
|
|> list.fold(set.from_list([nfa.init_state]), fn(states, char) {
|
||||||
|
exec_transition(nfa.transitions, states, char)
|
||||||
|
})
|
||||||
|
|
||||||
!set.is_disjoint(nfa.accepting_states, final_states)
|
!set.is_disjoint(nfa.accepting_states, final_states)
|
||||||
}
|
}
|
||||||
@ -39,27 +112,50 @@ pub fn check_string(nfa: NFA, input: String) -> Bool {
|
|||||||
pub fn even_a() -> NFA {
|
pub fn even_a() -> NFA {
|
||||||
let states = set.from_list([0, 1])
|
let states = set.from_list([0, 1])
|
||||||
let alphabet = set.from_list(["a"])
|
let alphabet = set.from_list(["a"])
|
||||||
let transition_func = fn (states, char) {
|
let transitions =
|
||||||
states
|
dict.from_list([
|
||||||
|> set.fold(set.new(), fn(n_states, state) {
|
#(#(0, "a"), set.from_list([1])),
|
||||||
case state, char {
|
#(#(1, "a"), set.from_list([0])),
|
||||||
0, "a" -> set.insert(n_states, 1)
|
])
|
||||||
1, "a" -> set.insert(n_states, 0)
|
|
||||||
_, _ -> n_states
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
let init_state = 0
|
let init_state = 0
|
||||||
let accepting_states = set.from_list([0])
|
let accepting_states = set.from_list([0])
|
||||||
NFA(states:, alphabet:, transition_func:, init_state:, accepting_states:)
|
NFA(states:, alphabet:, transitions:, init_state:, accepting_states:)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ends_with_b() -> NFA {
|
||||||
|
let states = set.from_list([0, 1, 2])
|
||||||
|
let alphabet = set.from_list(["a", "b"])
|
||||||
|
let transitions =
|
||||||
|
dict.from_list([
|
||||||
|
#(#(0, "a"), set.from_list([1])),
|
||||||
|
#(#(0, "b"), set.from_list([0, 2])),
|
||||||
|
#(#(1, "a"), set.from_list([1])),
|
||||||
|
#(#(1, "b"), set.from_list([2])),
|
||||||
|
// #(#(2, "a"), set.from_list([0])),
|
||||||
|
// #(#(2, "b"), set.from_list([1])),
|
||||||
|
])
|
||||||
|
let init_state = 0
|
||||||
|
let accepting_states = set.from_list([0, 2])
|
||||||
|
NFA(states:, alphabet:, transitions:, init_state:, accepting_states:)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
io.println("Hello from glemt!")
|
io.println("Hello from glemt!")
|
||||||
|
|
||||||
let automaton = even_a()
|
let automaton = even_a()
|
||||||
|
let _ = io.debug(is_dfa(automaton))
|
||||||
io.debug(check_string(automaton, ""))
|
io.debug(check_string(automaton, ""))
|
||||||
io.debug(check_string(automaton, "a"))
|
io.debug(check_string(automaton, "a"))
|
||||||
io.debug(check_string(automaton, "aa"))
|
io.debug(check_string(automaton, "aa"))
|
||||||
io.debug(check_string(automaton, "aaab"))
|
io.debug(check_string(automaton, "aaab"))
|
||||||
|
|
||||||
|
let automaton = ends_with_b()
|
||||||
|
io.debug(is_dfa(automaton))
|
||||||
|
io.debug(check_string(automaton, ""))
|
||||||
|
io.debug(check_string(automaton, "a"))
|
||||||
|
io.debug(check_string(automaton, "aa"))
|
||||||
|
io.debug(check_string(automaton, "aaaaaa"))
|
||||||
|
io.debug(check_string(automaton, "aaabaaa"))
|
||||||
|
io.debug(check_string(automaton, "bbbbbaab"))
|
||||||
|
io.debug(check_string(automaton, "abaabaaab"))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user