Skip to content
Snippets Groups Projects
Commit bd47d2f3 authored by Štěpán Plachý's avatar Štěpán Plachý Committed by Jan Trávníček
Browse files

FTA trim algorithm and test

parent c9f686cb
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,7 @@
#include <automaton/FSM/EpsilonNFA.h>
#include <automaton/FSM/NFA.h>
#include <automaton/FSM/DFA.h>
#include <automaton/TA/DFTA.h>
 
namespace automaton {
 
......@@ -23,6 +24,7 @@ auto TrimMultiInitialStateNFA = Trim::RegistratorWrapper<automaton::MultiInitial
auto TrimEpsilonNFA = Trim::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::EpsilonNFA < > >(Trim::trim);
auto TrimCompactNFA = Trim::RegistratorWrapper<automaton::CompactNFA < >, automaton::CompactNFA < > >(Trim::trim);
auto TrimExtendedNFA = Trim::RegistratorWrapper<automaton::ExtendedNFA < >, automaton::ExtendedNFA < > >(Trim::trim);
auto TrimDFTA = Trim::RegistratorWrapper<automaton::DFTA<>, automaton::DFTA<>>(Trim::trim);
 
automaton::Automaton Trim::trim(const automaton::Automaton& automaton) {
return dispatch(automaton.getData());
......
......@@ -17,6 +17,7 @@ auto UnreachableStatesRemoverCompactNFA = UnreachableStatesRemover::RegistratorW
auto UnreachableStatesRemoverExtendedNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::ExtendedNFA < >, automaton::ExtendedNFA < > >(UnreachableStatesRemover::remove);
auto UnreachableStatesRemoverDFA = UnreachableStatesRemover::RegistratorWrapper<automaton::DFA<>, automaton::DFA<>>(UnreachableStatesRemover::remove);
auto UnreachableStatesRemoverMultiInitialStateNFA = UnreachableStatesRemover::RegistratorWrapper<automaton::MultiInitialStateNFA < > , automaton::MultiInitialStateNFA < > >(UnreachableStatesRemover::remove);
auto UnreachableStatesRemoverDFTA = UnreachableStatesRemover::RegistratorWrapper<automaton::DFTA<>, automaton::DFTA < > >(UnreachableStatesRemover::remove);
 
automaton::Automaton UnreachableStatesRemover::remove(const automaton::Automaton& automaton) {
return dispatch(automaton.getData());
......
......@@ -17,6 +17,7 @@
#include <automaton/FSM/MultiInitialStateNFA.h>
#include <automaton/FSM/NFA.h>
#include <automaton/FSM/DFA.h>
#include <automaton/TA/DFTA.h>
 
#include "../properties/ReachableStates.h"
 
......@@ -37,6 +38,8 @@ public:
static automaton::DFA < SymbolType, StateType > remove( const automaton::DFA < SymbolType, StateType > & fsm );
template < class SymbolType, class StateType >
static automaton::MultiInitialStateNFA < SymbolType, StateType > remove( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm );
template < class SymbolType, class RankType, class StateType >
static automaton::DFTA < SymbolType, RankType, StateType > remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta );
};
 
template<class T, class SymbolType, class StateType >
......@@ -121,6 +124,61 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > UnreachableStatesRemov
return M;
}
 
template < class SymbolType, class RankType, class StateType >
automaton::DFTA < SymbolType, RankType, StateType > UnreachableStatesRemover::remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta ) {
automaton::DFTA < SymbolType, RankType, StateType > res;
res.setInputAlphabet(dfta.getInputAlphabet());
typedef std::pair < const std::pair < std::ranked_symbol < SymbolType, RankType >, std::vector < StateType > >, StateType > Transition;
std::vector<std::pair<const Transition *, int>> transitionsUnreachableCount;
transitionsUnreachableCount.reserve(dfta.getTransitions().size());
//for a state, transitions with unreachable count (initially all unreachable) and number of occurences of this state (at least 1)
std::map<StateType, std::map<std::pair<const Transition *, int> *, int>> stateOccurences;
std::deque<StateType> queue;
for(const auto & transition : dfta.getTransitions()) {
if (transition.first.second.empty()) {
queue.push_back(transition.second);
res.addState(transition.second);
res.addTransition(transition.first.first, transition.first.second, transition.second);
} else {
transitionsUnreachableCount.push_back({&transition, transition.first.second.size()});
for (const auto & state : transition.first.second) {
auto & occurences = stateOccurences[state];
auto it = occurences.find(&transitionsUnreachableCount.back());
if (it == occurences.end()) occurences[&transitionsUnreachableCount.back()] = 1;
else it->second++;
}
}
}
while(!queue.empty()) {
const auto & occurences = stateOccurences[queue.front()];
queue.pop_front();
for (const auto & occurence : occurences) {
int & unreachableCount = occurence.first -> second;
const StateType & to = occurence.first -> first -> second;
unreachableCount -= occurence.second;
if (unreachableCount == 0) {
if (res.addState(to)) {
queue.push_back(to);
}
}
}
}
for (const auto & state : res.getStates()) {
if (dfta.getFinalStates().count(state) != 0) res.addFinalState(state);
}
for (const auto & transitionUnreachableCount : transitionsUnreachableCount) {
if (transitionUnreachableCount.second == 0) {
const Transition transition = *(transitionUnreachableCount.first);
res.addTransition(transition.first.first, transition.first.second, transition.second);
}
}
return res;
}
} /* namespace simplify */
 
} /* namespace automaton */
......
......@@ -17,6 +17,7 @@ auto UselessStatesRemoverCompactNFA = UselessStatesRemover::RegistratorWrapper<a
auto UselessStatesRemoverExtendedNFA = UselessStatesRemover::RegistratorWrapper<automaton::ExtendedNFA < >, automaton::ExtendedNFA < > >(UselessStatesRemover::remove);
auto UselessStatesRemoverDFA = UselessStatesRemover::RegistratorWrapper<automaton::DFA<>, automaton::DFA<>>(UselessStatesRemover::remove);
auto UselessStatesRemoverMultiInitialStateNFA = UselessStatesRemover::RegistratorWrapper<automaton::MultiInitialStateNFA < > , automaton::MultiInitialStateNFA < > >(UselessStatesRemover::remove);
auto UselessStatesRemoverDFTA = UselessStatesRemover::RegistratorWrapper<automaton::DFTA<>, automaton::DFTA<>>(UselessStatesRemover::remove);
 
automaton::Automaton UselessStatesRemover::remove(const automaton::Automaton& automaton) {
return dispatch(automaton.getData());
......
......@@ -19,6 +19,7 @@
#include <automaton/FSM/MultiInitialStateNFA.h>
#include <automaton/FSM/NFA.h>
#include <automaton/FSM/DFA.h>
#include <automaton/TA/DFTA.h>
 
namespace automaton {
 
......@@ -37,6 +38,8 @@ public:
static automaton::DFA < SymbolType, StateType > remove( const automaton::DFA < SymbolType, StateType > & fsm );
template < class SymbolType, class StateType >
static automaton::MultiInitialStateNFA < SymbolType, StateType > remove( const automaton::MultiInitialStateNFA < SymbolType, StateType > & fsm );
template < class SymbolType, class RankType, class StateType >
static automaton::DFTA < SymbolType, RankType, StateType > remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta );
};
 
template < class T, class SymbolType, class StateType >
......@@ -130,6 +133,44 @@ automaton::MultiInitialStateNFA < SymbolType, StateType > UselessStatesRemover::
return M;
}
 
template < class SymbolType, class RankType, class StateType >
automaton::DFTA < SymbolType, RankType, StateType > UselessStatesRemover::remove( const automaton::DFTA < SymbolType, RankType, StateType > & dfta ) {
automaton::DFTA < SymbolType, RankType, StateType > res;
res.setInputAlphabet(dfta.getInputAlphabet());
res.setStates(dfta.getFinalStates());
res.setFinalStates(dfta.getFinalStates());
typedef std::pair < const std::pair < std::ranked_symbol < SymbolType, RankType >, std::vector < StateType > >, StateType > Transition;
std::map<StateType, std::set<const Transition *>> transitionsToState;
for(const auto & transition : dfta.getTransitions()) {
transitionsToState[transition.second].insert(&transition);
}
std::deque<StateType> queue;
for (const auto & state : dfta.getFinalStates()) {
queue.push_back(state);
}
while(!queue.empty()) {
std::set<const Transition *> & transitions = transitionsToState[queue.front()];
queue.pop_front();
for (const Transition * transitionPt : transitions) {
const Transition &transition = *transitionPt;
for (const auto & state : transition.first.second) {
if (res.addState(state)) {
queue.push_back(state);
}
}
res.addTransition(transition.first.first, transition.first.second, transition.second);
}
}
return res;
}
} /* namespace simplify */
 
} /* namespace automaton */
......
......@@ -6,6 +6,7 @@
 
#include "automaton/FSM/DFA.h"
#include "grammar/Regular/RightRG.h"
#include "automaton/TA/DFTA.h"
 
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( trimTest, "automaton" );
CPPUNIT_TEST_SUITE_REGISTRATION( trimTest );
......@@ -17,47 +18,99 @@ void trimTest::tearDown() {
}
 
void trimTest::testTrimAutomaton() {
automaton::DFA < > automaton(DefaultStateType(1));
automaton.addState(DefaultStateType(1));
automaton.addState(DefaultStateType(2));
automaton.addState(DefaultStateType(3));
automaton.addInputSymbol(DefaultSymbolType("a"));
automaton.addInputSymbol(DefaultSymbolType("b"));
automaton.addTransition(DefaultStateType(1), DefaultSymbolType("a"), DefaultStateType(2));
automaton.addTransition(DefaultStateType(2), DefaultSymbolType("b"), DefaultStateType(1));
automaton.addTransition(DefaultStateType(3), DefaultSymbolType("b"), DefaultStateType(1));
automaton.addFinalState(DefaultStateType(1));
automaton::DFA<> trimed = automaton::simplify::Trim::trim(automaton);
CPPUNIT_ASSERT(trimed.getStates().size() == 2);
automaton::DFA < > automaton(DefaultStateType(1));
automaton.addState(DefaultStateType(1));
automaton.addState(DefaultStateType(2));
automaton.addState(DefaultStateType(3));
automaton.addInputSymbol(DefaultSymbolType("a"));
automaton.addInputSymbol(DefaultSymbolType("b"));
automaton.addTransition(DefaultStateType(1), DefaultSymbolType("a"), DefaultStateType(2));
automaton.addTransition(DefaultStateType(2), DefaultSymbolType("b"), DefaultStateType(1));
automaton.addTransition(DefaultStateType(3), DefaultSymbolType("b"), DefaultStateType(1));
automaton.addFinalState(DefaultStateType(1));
automaton::DFA<> trimed = automaton::simplify::Trim::trim(automaton);
CPPUNIT_ASSERT(trimed.getStates().size() == 2);
}
 
void trimTest::testTrimGrammar() {
grammar::RightRG < > rrGrammar(DefaultSymbolType(1));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(1));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(2));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(3));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(4));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(5));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(6));
rrGrammar.addTerminalSymbol(DefaultSymbolType("a"));
rrGrammar.addTerminalSymbol(DefaultSymbolType("b"));
rrGrammar.addRule(DefaultSymbolType(1), std::make_pair(DefaultSymbolType("a"), DefaultSymbolType(2)));
rrGrammar.addRule(DefaultSymbolType(2), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(3)));
rrGrammar.addRule(DefaultSymbolType(3), DefaultSymbolType("a"));
rrGrammar.addRule(DefaultSymbolType(4), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(5)));
rrGrammar.addRule(DefaultSymbolType(5), DefaultSymbolType("a"));
rrGrammar.addRule(DefaultSymbolType(5), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(2)));
rrGrammar.addRule(DefaultSymbolType(6), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(6)));
grammar::RightRG < > trimed = grammar::simplify::Trim::trim(rrGrammar);
CPPUNIT_ASSERT(trimed.getNonterminalAlphabet().size() == 3);
grammar::RightRG < > rrGrammar(DefaultSymbolType(1));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(1));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(2));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(3));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(4));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(5));
rrGrammar.addNonterminalSymbol(DefaultSymbolType(6));
rrGrammar.addTerminalSymbol(DefaultSymbolType("a"));
rrGrammar.addTerminalSymbol(DefaultSymbolType("b"));
rrGrammar.addRule(DefaultSymbolType(1), std::make_pair(DefaultSymbolType("a"), DefaultSymbolType(2)));
rrGrammar.addRule(DefaultSymbolType(2), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(3)));
rrGrammar.addRule(DefaultSymbolType(3), DefaultSymbolType("a"));
rrGrammar.addRule(DefaultSymbolType(4), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(5)));
rrGrammar.addRule(DefaultSymbolType(5), DefaultSymbolType("a"));
rrGrammar.addRule(DefaultSymbolType(5), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(2)));
rrGrammar.addRule(DefaultSymbolType(6), std::make_pair(DefaultSymbolType("b"), DefaultSymbolType(6)));
grammar::RightRG < > trimed = grammar::simplify::Trim::trim(rrGrammar);
CPPUNIT_ASSERT(trimed.getNonterminalAlphabet().size() == 3);
}
void trimTest::testTrimDFTA() {
automaton::DFTA < > automaton;
std::vector<DefaultStateType> q;
for (int i = 0; i <= 11; ++i) {
DefaultStateType state (i);
q.push_back(state);
automaton.addState(state);
}
automaton.addFinalState(q[2]);
automaton.addFinalState(q[11]);
const std::ranked_symbol < > a ("a", 2);
const std::ranked_symbol < > b ("b", 1);
const std::ranked_symbol < > c ("c", 0);
automaton.addInputSymbol(a);
automaton.addInputSymbol(b);
automaton.addInputSymbol(c);
automaton.addTransition(c, {}, q[0]);
automaton.addTransition(a, {q[0], q[0]}, q[1]);
automaton.addTransition(b, {q[1]}, q[2]);
//unreachable and useless
automaton.addTransition(a, {q[3], q[4]}, q[5]);
automaton.addTransition(b, {q[5]}, q[6]);
//useless
automaton.addTransition(a, {q[2], q[2]}, q[7]);
automaton.addTransition(a, {q[7], q[7]}, q[8]);
//unreachable
automaton.addTransition(a, {q[9], q[9]}, q[10]);
automaton.addTransition(a, {q[10], q[10]}, q[11]);
automaton::DFTA<> trimed = automaton::simplify::Trim::trim(automaton);
automaton::DFTA<> correct;
correct.addState(q[0]);
correct.addState(q[1]);
correct.addState(q[2]);
correct.addFinalState(q[2]);
correct.addInputSymbol(a);
correct.addInputSymbol(b);
correct.addInputSymbol(c);
correct.addTransition(c, {}, q[0]);
correct.addTransition(a, {q[0], q[0]}, q[1]);
correct.addTransition(b, {q[1]}, q[2]);
CPPUNIT_ASSERT(trimed == correct);
}
......@@ -3,19 +3,20 @@
 
#include <cppunit/extensions/HelperMacros.h>
 
class trimTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( trimTest );
CPPUNIT_TEST( testTrimAutomaton );
CPPUNIT_TEST( testTrimGrammar );
CPPUNIT_TEST_SUITE_END();
class trimTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( trimTest );
CPPUNIT_TEST( testTrimAutomaton );
CPPUNIT_TEST( testTrimGrammar );
CPPUNIT_TEST( testTrimDFTA );
CPPUNIT_TEST_SUITE_END();
 
public:
void setUp();
void tearDown();
void setUp();
void tearDown();
 
void testTrimAutomaton();
void testTrimGrammar();
void testTrimAutomaton();
void testTrimGrammar();
void testTrimDFTA();
};
 
#endif // TRIM_TEST_H_
#endif // TRIM_TEST_H_
......@@ -65,10 +65,10 @@ int main(int argc, char* argv[]) {
 
TCLAP::CmdLine cmd("Removes unreachable and useless states from FSM, productive and unreachable nonterminals from CFG. Simplifies representation of RE", ' ', "0.01");
 
TCLAP::SwitchArg useless( "u", "useless", "Removes useless states (or symbols). (works with FSM or CFG)" );
TCLAP::SwitchArg useless( "u", "useless", "Removes useless states (or symbols). (works with FSM, FTA or CFG)" );
cmd.add( useless );
 
TCLAP::SwitchArg unreachable( "r", "unreachable", "Removes unreachable states (or symbols). (works with FSM or CFG)" );
TCLAP::SwitchArg unreachable( "r", "unreachable", "Removes unreachable states (or symbols). (works with FSM, FTA or CFG)" );
cmd.add( unreachable );
 
TCLAP::SwitchArg simplify( "s", "simplify", "Simplifies representation. (works with RE only)" );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment