Question

For some days I'm trying to do a program for simulate a nondeterministic finite automaton (NFA), more specifically, a string recognizer. After several failures, thanks to the user Konrad Rudolph, I could implement a solution based on this pseudocode:

Well, in an NFA you have a set of current states, and in each step you go through all current states, and for each, you select all valid transitions. Those combined sets form your new state set.

At the end, you check whether the intersection of the current states and the accepting states is non-empty.

In Pseudo-code this looks as follows:

current = { initial }
    for each char in input:
        next = { }
        for each state in current:
            for each transition in transitions[state][char]:
                next.append(target_of(transition))
        current = next
if len(intersection(current, accepting)) > 0:
    print "String accepted"
else:
    print "String rejected"

This can be translated, line by line, into C++ code. He recommended to make this easy, use std::set<int> for the current and next sets

Herés my implementation in c++:

#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <vector>

using namespace std;

int main (){

    int testCases, i, j,k, cont=1,finalStates,numberInputs,stateOrigin, stateDestination;
    int numberStates, numberTransitions, initialState;
    int  numberFinals;
    char transitionCharacter ;

    set<int> current;
    set<int> next;
    set<int>::iterator it;
    set <int> final;
    set<int> the_intersection;  // Destination of intersect
    map<pair<int, int>, char>::iterator p;
    string inputString;

    typedef std::pair<int, int> trigger;
    std::map<trigger, char> transitions;
    map<trigger, char>::iterator r;

    cin>> testCases;
    for (i=0;i< testCases;i++){
        
        final.clear();
        next.clear();
        current.clear();
        the_intersection.clear();
        transitions.clear();
        cin>>numberStates>>numberTransitions>>initialState>>numberFinals;

        for (j=0;j<numberFinals;j++){
            cin>>finalStates;
            final.insert(finalStates);
        }

        for (j=0; j<numberTransitions;j++){
            cin>> stateOrigin>>stateDestination>>transitionCharacter;
            transitions.insert(make_pair(make_pair(stateOrigin, stateDestination), transitionCharacter));
        }

        cin>>numberInputs;
        current.insert (initialState);
        cout<<"Test Case #"<<cont++<<":"<<endl;
        
        for (j=0; j<numberInputs;j++){
            current.clear();
            current.insert (initialState);
            the_intersection.clear();
            cin>> inputString;
            cout<<inputString<<" ";
            
            /// ///////////////Konrad Rudolph's solution /////////////////
            for (k=0; k<inputString.size();k++){
                next.clear();
                for (it = current.begin(); it!=current.end(); it++){
                    for (r =transitions.begin(); r!=transitions.end(); r++){
                        if ( ((*r).first.first == *it) && ( (*r).second == inputString[k] ) ){
                            next.insert((*r).first.second);
                        }
                    }
                    current = next;
                }
            }
            std::set_intersection(current.begin(), current.end(), final.begin(), final.end(), std::inserter(the_intersection, the_intersection.end()));

            if (the_intersection.empty()){
                cout<<"Rejected"<<endl;
            }else {
                cout<<"Acepted"<<endl;
            }
            
            /// ///////////////////////////////////////////////////////
        }
        cout<<endl;
    }
return 0;
}

I have this input:

1
6 8 0 2
2
5
0 0 a
0 1 a
1 1 b
1 2 c
1 3 c
3 4 d
4 4 d
4 5 d
5
aaabcccc
aabbbbcdc
abbcdddcc
abc
acdddddd

the expected output is:

Test Case #1:
aaabcccc Rejected
aabbbbcdc Rejected
abbcdddcc Rejected
abc Acepted
acdddddd Acepted

However, my code produces as output:

Test Case #1:
aaabcccc Rejected
aabbbbcdc Rejected
abbcdddcc Rejected
abc Acepted
acdddddd

And for the last string of the test case the program is doing nothing, just does not stop run. My question is Why does my program crashes with this particular input. I designed the same automaton NFA in JFlap and recognizes this last input

acdddddd

.

enter image description here

(0, a) = 1
(1, c) = 2
(2, d) = 3
(3, d) = 4
(4, d) = 4
(4, d) = 4
(4, d) = 4
(4, d) = 5

What mistake I'm having in the implementation of my code?

Was it helpful?

Solution

You want to do;

for each char in input:
    next = { }
    for each state in current:
        for each transition in transitions[state][char]:
            next.append(target_of(transition))
    current = next

but what you're doing is;

for each char in input:
    next = { }
    for each state in current:
        for each transition in transitions[state][char]:
            next.append(target_of(transition))
        current = next

Subtle, but reassigning current while looping over it may cause your hang and will definitely not give the desired result.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top