For one of my assignments I am supposed to write a Push Down Automaton. It's supposed to receive a string that has to be checked if it's an RNA Hairpin.
For example: gacgcaaguc would be one, since the gac is the opposite of the guc, and the four in the middle have to be either gcaa or gaaa.
I already have a working program which, however, checks each possible case. It has 15 if
statements, one for each case, and I am sure there is a better way.
Now I am looking for a more elegant way in C++ to check these cases:
S -> aW1u | uW1a | gW1c | cW1g
W1-> aW2u | uW2a | gW2c | cW2g
W2-> aW3u | uW3a | gW3c | cW3g
W3-> gW4a
W4-> ca | aa
As you probably know the right side gets filled into a Stack, and once I reach half the String, I check if the Stack and the other half of my String align. I didn't understand PDAs too well, so maybe you have some help for a guy who is new to this.
HPP:
#include <stack>
class PDA
{
public:
enum Language {
HAIRPIN, // accepts RNA Hairpins
BRACKETS // Zusatzaufgabe
};
enum State {
IN_PROGRESS = 0, // sequence is valid so far, but not complete
SUCCESS = 1, // currently in accepting state, i.e. stack is empty after reading # symbol
FAIL = 2 // sequence is not in language
};
/// Constructor, which specifies which language to check (HAIRPIN by default)
/// and internally builds up the production rules
PDA(const Language l = Language::HAIRPIN);
/// Read the next symbol and internally traverse states
/// If a fail state was reached in the previous call, the fail state will be maintained
/// @param a Symbol to read
/// @return current state of PDA
State next(const char a);
/// Reset the automaton to a state as if newly constructed
/// I.e. init stack and set state to s0.
void reset();
protected:
/// YOUR Member variables and functions
State transitionfunction(char b, State cur, char stacktop);
State current;
std::stack<char> stark;
int statechange;
};
CPP:
#include <stack>
#include "PDA.hpp"
#include <iostream>
using namespace std;
PDA::PDA(const Language l) {
current = IN_PROGRESS;
stark.push('$');
statechange = 0;
}
PDA::State PDA::next(const char a) {
if (statechange == 1) {
if (stark.top() == '$') {
return PDA::SUCCESS;
}
else if (stark.top() == a) {
stark.pop();
return PDA::IN_PROGRESS;
}
else {
return PDA::FAIL;
}
}
else {
return transitionfunction(a, current, stark.top());
}
}
void PDA::reset() {
current = IN_PROGRESS;
while (!stark.empty()) {
stark.pop();
}
stark.push('$');
statechange = 0;
}
PDA::State PDA::transitionfunction(const char b, PDA::State cur, const char stacktop) {
if (cur == PDA::FAIL) {
return PDA::FAIL;
}
else if (stacktop =='$') {
if (b == 'a') {
stark.push('u');
stark.push('1');
return PDA::IN_PROGRESS;
}
else if (b == 'c') {
stark.push('g');
stark.push('1');
return PDA::IN_PROGRESS;
}
else if (b == 'g') {
stark.push('c');
stark.push('1');
return PDA::IN_PROGRESS;
}
else if (b == 'u') {
stark.push('a');
stark.push('1');
return PDA::IN_PROGRESS;
}
else {
return PDA::FAIL;
}
}
else if (stacktop =='1') {
if (b == 'a') {
stark.pop();
stark.push('u');
stark.push('2');
return PDA::IN_PROGRESS;
}
else if (b == 'c') {
stark.pop();
stark.push('g');
stark.push('2');
return PDA::IN_PROGRESS;
}
else if (b == 'g') {
stark.pop();
stark.push('c');
stark.push('2');
return PDA::IN_PROGRESS;
}
else if (b == 'u') {
stark.pop();
stark.push('a');
stark.push('2');
return PDA::IN_PROGRESS;
}
else {
return PDA::FAIL;
}
}
else if (stacktop =='2') {
if (b == 'a') {
stark.pop();
stark.push('u');
stark.push('3');
return PDA::IN_PROGRESS;
}
else if (b == 'c') {
stark.pop();
stark.push('g');
stark.push('3');
return PDA::IN_PROGRESS;
}
else if (b == 'g') {
stark.pop();
stark.push('c');
stark.push('3');
return PDA::IN_PROGRESS;
}
else if (b == 'u') {
stark.pop();
stark.push('a');
stark.push('3');
return PDA::IN_PROGRESS;
}
else {
return PDA::FAIL;
}
}
else if (stacktop == '3') {
if(b == 'g'){
stark.pop();
stark.push('a');
stark.push('4');
return PDA::IN_PROGRESS;
}
else {
return PDA::FAIL;
}
}
else if (stacktop == '4') {
if(b == 'c'){
stark.pop();
stark.push('a');
statechange = 1;
return PDA::IN_PROGRESS;
}
else if(b == 'a') {
stark.pop();
stark.push('a');
statechange = 1;
return PDA::IN_PROGRESS;
}
else {
return PDA::FAIL;
}
}
}
Main:
#include <iostream>
#include "PDA.hpp"
using namespace std;
int main(int argc, char* argv[])
{
if (argc != 2) {
cout << "Please only enter one string" << endl;
return 1;
}
string a = argv[1];
if (a.length() != 10) {
cout << "The string should have length 10" << endl;
return 1;
}
PDA::State final = PDA::IN_PROGRESS;
PDA testpin;
for (uint i = 0; i <= a.length(); i++) {
final = testpin.next(a[i]);
if (final == PDA::FAIL) {
cout << "FAIL" << endl;
return 1;
}
else if (final == PDA::SUCCESS) {
cout << "ACCEPT" << endl;
return 0;
}
}
}