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
.
(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?
You want to do;
but what you're doing is;
Subtle, but reassigning current while looping over it may cause your hang and will definitely not give the desired result.