7

I am doing an assignment for simulate a nondeterministic finite automaton, just as I explain in this post. I have this input read from the file tarea4.in:

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
acdddddd
abc

The first line of input is an integer T, represented the number of cases to evaluate the program. Each test case starts with 4 integers, the first is the number of state for the automaton, next is the number of transitions of the automaton, the third number is the initial state, and then the number of final states. then come the final states (in the example the final states are 2 and 5). Then come F lines, each with an integer E, representing E is a final state.

Then come N lines (N is the number of transitions), each with 2 integers and a character, I, J and C, representing the states where the transition, ie, the transition goes from state i to state J with the character C. Following this line come with a single integer S, which will contain the number of strings to test, then S lines with the respective strings.

the expected output is:

Test Case #2:
aaabcccc Rejected
aabbbbcdc Rejected
abbcdddcc Rejected
acdddddd Accepted
abc Accepted

The output resulting in my code:

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

Here's my code:

#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <vector>    
using namespace std;

typedef map<pair<int, int>, char> transitions;
    transitions trans;

    int  numberFinals;
    vector<int> currentStates;    

int main (){ 

    freopen ("tarea4.in", "r", stdin);
    //freopen ("tarea4.out", "w", stdout);        
    int testCases, i, j,k, cont=1,finalStates,numberInputs,stateOrigin, stateDestination;
    int numberStates, numberTransitions, initialState;
    char transitionCharacter ;

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

    cin>> testCases;
    for (i=0;i< testCases;i++){
        cin>>numberStates>>numberTransitions>>initialState>>numberFinals;
        current.insert (initialState);

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

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

        cin>>numberInputs;

        cout<<"Test Case #"<<cont++<<":"<<endl;    

        for (j=0; j<numberInputs;j++){
             //////////////////the code of the answer /////////////////
            current.insert (initialState);
            cin>> inputString;
            cout<<inputString<<" ";


     for (k=0; k<str.size();k++){
         next.clear();
         for ( it=current.begin() ; it != current.end(); it++ ){
              for (q= trans.begin(); q!= trans.end();q++){
                  if((*it == q->first.first)&&(str[k]==q->second)){
                     next.insert(q->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.size()>0){
                cout<< "Accepted"<<endl;
            }
            else{
                cout<< "Rejected"<<endl;
            }

        }

        printf ("\n");
    }

return 0;
}

My question is: Why do I get incorrect output? I think it is for the nondeterminism of the automaton defined in the test case, but how I can evaluate the string correctly?. How I can change my function called evaluate_string to that in some way check the different paths that can take the automaton to evaluate the string by the non-determinism?

I've been stuck with this for several days and to be honest I am somewhat desperate about.

Community
  • 1
  • 1
novaKid
  • 233
  • 2
  • 4
  • 11
  • Please format your code properly the next time. Your indentations were way off. Furthermore, I don’t understand the expected output. For instance, where is `0 b 3` coming from? Finally, which do you want? An NFA or a DFA? Nothing in your post is a deterministic automaton (neither the input nor the expected output) so I’ve removed mentions of “DFA” for now … – Konrad Rudolph May 16 '12 at 21:15
  • `where is 0 b 3 coming from?`: for the input aabbbbcdc the transitions of the automaton are: `(q0, a) = 0, (q0, a) = 0, (q0, b) = 3, (q3, b) = 0, (q0, b) = 3, (q3, b) = 0` 'which do you want?'; My function "evaluate_string" implements a DFA and I want to know how to modify it to get an NFA – novaKid May 16 '12 at 21:32
  • 1
    That’s not what I mean. The `0 b 3` is from the transition function, there is no input to consider. – Concerning your question: ah, got it. The bad news is: you can transform an NFA into a DFA and solve it, but you cannot get the identical state transition output from that because your state names *will* differ. Also, running the NFA directly is probably easier (not even 10 lines!) than transforming it to a DFA first. – Konrad Rudolph May 16 '12 at 21:34
  • @KonradRudolph The state transitions don't matter, I'm just printing them to see what happens in each state change, the program simply must show if the string is accepted or rejected. `running the NFA directly is probably easier (not even 10 lines!)`: the question is: how I can do this?, I'm stuck on this for several days. How should I modify my code to do this? – novaKid May 16 '12 at 21:44

3 Answers3

10

Evaluating an NFA is almost as easy as evaluating a DFA.

In a DFA, you have one current state and in each step you select the next transition. At the end of the input, you check whether the current state is an accepting state.

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] ∪ transitions[state][ϵ]:
        • 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. To make this easy, I suggest using std::set<int> for the current and next sets, and a vector of std::multimap<char, int> for the transitions. This assumes that each state corresponds to an integer.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • I edited the code of the question, I made ​​the changes you indicated in your answer but I still get a correct output. What am I doing wrong in implementing your soluicón?. I translated the pseudocode to language c + + using set as you indicated but I still see what the hell am I doing wrong. Any help on this? – novaKid May 17 '12 at 17:15
  • 1
    im not sure but I think the set "current" has no elements at the end of the processing the string, therefore the intersect between current and final sets is empty. and always will be rejected. Now I don't know if the implementation proposed by Konrad Rudolph is quite correct, I see no fault in your implementation. – franvergara66 May 17 '12 at 17:43
  • @Melkhiah66 The pseudocode is correct. I’ve taken it 1:1 from a C++ implementation which works as expected on OP’s input. OP’s implementation has an error in `next.insert(p->second);`. It should probably be `p->first.second`. But as I said, a `vector>` would be easier (and more efficient here). – Konrad Rudolph May 17 '12 at 20:24
  • 1
    @KonradRudolph `for each transition in transitions[state][char]: next.append(target_of(transition))`, I do not understand these lines, indentation is bad or `next.append(target_of(transition))` should be in the loop? – novaKid May 17 '12 at 21:42
  • @KonradRudolph I don't understand why you recommend using a vector of multimap vector>, the structure having the code would work perfectly. What is the difference?, Sorry for my insistence – franvergara66 May 17 '12 at 22:41
  • @Melkhiah66 The difference is that now you have to search through *all* transitions in each step, for each current state. With a multimap of transitions for each state, you can jump directly to the current state’s transitions with `themultimap.equal_range`. This also saves the `if` in your code (which I don’t have in my pseudocode). – Konrad Rudolph May 17 '12 at 23:56
  • @KonradRudolph Your algorithm doesn't cover [Ɛ-moves](http://en.wikipedia.org/wiki/Nondeterministic_finite_automaton_with_%CE%B5-moves) – ajmartin Jan 14 '13 at 00:01
  • @ajmartin Ooops. Better now? Off the top of my head ϵ moves don’t need any special treatment (apart from being considered at all), do they? – Konrad Rudolph Jan 14 '13 at 09:46
  • @KonradRudolph Yes, they do. Branching will come and there'll parallel machines which will operate on the same input. [Check this](http://en.wikipedia.org/wiki/Nondeterministic_finite_automaton_with_%CE%B5-moves) – ajmartin Jan 24 '13 at 08:37
  • @ajmartin Damn, I hadn’t considered that ϵ moves are transitive. Thanks for taking your time to review this answer. Unfortunately I don’t have time now to correct it but I will do so in the near future. – Konrad Rudolph Jan 24 '13 at 10:37
1

I think you should first implement the general mechanism to convert any NFA to its corresponding DFA. After doing that, you can easily implement automaton runner since DFAs work deterministically.

Seçkin Savaşçı
  • 3,446
  • 2
  • 23
  • 39
1

The fundamental problem is that your code is breaking out of the transition loop as soon as you find the FIRST valid transition. Which would work if you were doing a DFA, but an NFA could have multiple valid paths.

Two options you have (I'm sure there are more):

1) Implement an NFA evaluator: This involves keeping track of a set of current states, and evaluating each input character against each state. Once the string has been read, if any of the final states are in the set, it is complete.

2) Convert the NFA to a DFA, which is, IMHO the harder approach, since that basically involves building the same set logic and evaluating the transitions for the new states.

Dave S
  • 20,507
  • 3
  • 48
  • 68
  • How could I modify my code to do what you indicate in your option 1) `Implement an NFA evaluator`. There is some pseudocode to do?, I have many doubts the logic of the NFA evaluator. – novaKid May 16 '12 at 23:08
  • Hey man, you must use recursion to make the NFA?. I can not find the way to go, any suggestions apart from what you indicated to me? – novaKid May 17 '12 at 04:53