mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-11 06:29:29 +01:00
186 lines
4.2 KiB
Go
186 lines
4.2 KiB
Go
|
package enfa
|
||
|
|
||
|
import "fmt"
|
||
|
|
||
|
type transitionInput struct {
|
||
|
srcState int
|
||
|
input string
|
||
|
}
|
||
|
|
||
|
type destState map[int]bool
|
||
|
|
||
|
type ENFA struct {
|
||
|
initState int
|
||
|
currentState map[int]bool
|
||
|
totalStates []int
|
||
|
finalStates []int
|
||
|
transition map[transitionInput]destState
|
||
|
inputMap map[string]bool
|
||
|
}
|
||
|
|
||
|
//New a new NFA
|
||
|
func NewENFA(initState int, isFinal bool) *ENFA {
|
||
|
|
||
|
retNFA := &ENFA{
|
||
|
transition: make(map[transitionInput]destState),
|
||
|
inputMap: make(map[string]bool),
|
||
|
initState: initState}
|
||
|
|
||
|
retNFA.currentState = make(map[int]bool)
|
||
|
retNFA.currentState[initState] = true
|
||
|
retNFA.AddState(initState, isFinal)
|
||
|
return retNFA
|
||
|
}
|
||
|
|
||
|
//Add new state in this NFA
|
||
|
func (d *ENFA) AddState(state int, isFinal bool) {
|
||
|
if state == -1 {
|
||
|
fmt.Println("Cannot add state as -1, it is dead state")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
d.totalStates = append(d.totalStates, state)
|
||
|
if isFinal {
|
||
|
d.finalStates = append(d.finalStates, state)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Add new transition function into NFA
|
||
|
func (d *ENFA) AddTransition(srcState int, input string, dstStateList ...int) {
|
||
|
find := false
|
||
|
|
||
|
//find input if exist in NFA input List
|
||
|
if _, ok := d.inputMap[input]; !ok {
|
||
|
//not exist, new input in this NFA
|
||
|
d.inputMap[input] = true
|
||
|
}
|
||
|
|
||
|
for _, v := range d.totalStates {
|
||
|
if v == srcState {
|
||
|
find = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !find {
|
||
|
fmt.Println("No such state:", srcState, " in current NFA")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
dstMap := make(map[int]bool)
|
||
|
for _, destState := range dstStateList {
|
||
|
dstMap[destState] = true
|
||
|
}
|
||
|
|
||
|
targetTrans := transitionInput{srcState: srcState, input: input}
|
||
|
d.transition[targetTrans] = dstMap
|
||
|
}
|
||
|
|
||
|
func (d *ENFA) CheckPathExist(src int, input string, dst int) bool {
|
||
|
retMap, _ := d.transition[transitionInput{srcState: src, input: input}]
|
||
|
if _, ok := retMap[dst]; ok {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (d *ENFA) Input(testInput string) []int {
|
||
|
updateCurrentState := make(map[int]bool)
|
||
|
for current, _ := range d.currentState {
|
||
|
for _, realTestInput := range []string{testInput, "*", "?"} {
|
||
|
intputTrans := transitionInput{srcState: current, input: realTestInput}
|
||
|
valMap, ok := d.transition[intputTrans]
|
||
|
if ok {
|
||
|
for dst, _ := range valMap {
|
||
|
updateCurrentState[dst] = true
|
||
|
|
||
|
//Update epsilon input way... if exist
|
||
|
epsilonTrans := transitionInput{srcState: dst}
|
||
|
if eMap, ok := d.transition[epsilonTrans]; ok {
|
||
|
for eDst, _ := range eMap {
|
||
|
updateCurrentState[eDst] = true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
//dead state, remove in current state
|
||
|
//do nothing.
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//update curret state
|
||
|
d.currentState = updateCurrentState
|
||
|
|
||
|
//return result
|
||
|
var ret []int
|
||
|
for state, _ := range updateCurrentState {
|
||
|
ret = append(ret, state)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
//To verify current state if it is final state
|
||
|
func (d *ENFA) Verify() bool {
|
||
|
for _, val := range d.finalStates {
|
||
|
for cState, _ := range d.currentState {
|
||
|
if val == cState {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
//Reset NFA state to initilize state, but all state and transition function will remain
|
||
|
func (d *ENFA) Reset() {
|
||
|
initState := make(map[int]bool)
|
||
|
initState[d.initState] = true
|
||
|
d.currentState = initState
|
||
|
}
|
||
|
|
||
|
//Verify if list of input could be accept by NFA or not
|
||
|
func (d *ENFA) VerifyInputs(inputs []string) bool {
|
||
|
for _, v := range inputs {
|
||
|
d.Input(v)
|
||
|
}
|
||
|
return d.Verify()
|
||
|
}
|
||
|
|
||
|
//To print detail transition table contain of current NFA
|
||
|
func (d *ENFA) PrintTransitionTable() {
|
||
|
fmt.Println("===================================================")
|
||
|
//list all inputs
|
||
|
var inputList []string
|
||
|
for key, _ := range d.inputMap {
|
||
|
if key == "" {
|
||
|
fmt.Printf("\tε|")
|
||
|
} else {
|
||
|
fmt.Printf("\t%s|", key)
|
||
|
}
|
||
|
inputList = append(inputList, key)
|
||
|
}
|
||
|
|
||
|
fmt.Printf("\n")
|
||
|
fmt.Println("---------------------------------------------------")
|
||
|
|
||
|
for _, state := range d.totalStates {
|
||
|
fmt.Printf("%d |", state)
|
||
|
for _, key := range inputList {
|
||
|
checkInput := transitionInput{srcState: state, input: key}
|
||
|
if dstState, ok := d.transition[checkInput]; ok {
|
||
|
fmt.Printf("\t")
|
||
|
for val, _ := range dstState {
|
||
|
fmt.Printf("%d,", val)
|
||
|
}
|
||
|
fmt.Printf("|")
|
||
|
} else {
|
||
|
fmt.Printf("\tNA|")
|
||
|
}
|
||
|
}
|
||
|
fmt.Printf("\n")
|
||
|
}
|
||
|
|
||
|
fmt.Println("---------------------------------------------------")
|
||
|
fmt.Println("===================================================")
|
||
|
}
|