Skip to content
Snippets Groups Projects
Commit df4f38be authored by Tomáš Pecka's avatar Tomáš Pecka Committed by Tomáš Pecka
Browse files

Algo: Distinguishable states of DFA

parent 5d7e0886
Branches
Tags
1 merge request!79Dev tp
/*
* DistinguishableStates.cpp
*
* Created on: 27. 3. 2019
* Author: Tomas Pecka
*/
#include "DistinguishableStates.h"
#include <registration/AlgoRegistration.hpp>
namespace automaton {
namespace properties {
auto DistinguishableStatesDFA = registration::AbstractRegister < DistinguishableStates, ext::set < ext::pair < DefaultStateType, DefaultStateType > >, const automaton::DFA < > & > ( DistinguishableStates::distinguishableStates, "fsm" ).setDocumentation (
"Computes the pairs of distinguishable states in given DFA.\n\
\n\
@param dfa finite automaton.\n\
@return set of pairs of distinguishable states" );
} /* namespace properties */
} /* namespace automaton */
/*
* DistinguishableStates.h
*
* This file is part of Algorithms library toolkit.
* Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
* Algorithms library toolkit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* Algorithms library toolkit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>.
*
* Created on: 27. 3. 2019
* Author: Tomas Pecka
*/
#ifndef DISTINGUISHABLE_STATES_H_
#define DISTINGUISHABLE_STATES_H_
#include <alib/set>
#include <alib/map>
#include <automaton/FSM/DFA.h>
#include <automaton/Automaton.h>
namespace automaton {
namespace properties {
/**
* Find all distinguishable pairs of states of DFA.
* Implements table-filling algorithm, Hopcroft 2nd edition, 4.4.1
*/
class DistinguishableStates {
public:
/**
* Find all distinguishable pairs of states of DFA.
* Implements table-filling algorithm, Hopcroft 2nd edition, 4.4.1
* O(n^4) version. TODO quadratic-time version.
*
* @param fsm automaton
* @return set of pairs of distinguishable states of @p fsm
*/
template < class SymbolType, class StateType >
static ext::set < ext::pair < StateType, StateType > > distinguishableStates ( const automaton::DFA < SymbolType, StateType > & fsm );
};
template < class SymbolType, class StateType >
ext::set < ext::pair < StateType, StateType > > DistinguishableStates::distinguishableStates ( const automaton::DFA < SymbolType, StateType > & fsm ) {
ext::set < ext::pair < StateType, StateType > > distinguishable;
for ( const StateType & a : fsm.getStates ( ) ) {
for ( const StateType & b : fsm.getStates ( ) ) {
if ( ( fsm.getFinalStates ( ).count ( a ) == 0 ) ^ ( fsm.getFinalStates ( ).count ( b ) == 0 ) ) {
distinguishable.insert ( ext::make_pair ( a, b ) );
distinguishable.insert ( ext::make_pair ( b, a ) );
}
}
}
bool changed;
do {
changed = false;
for ( const StateType & a : fsm.getStates ( ) ) {
for ( const StateType & b : fsm.getStates ( ) ) {
for ( const SymbolType & symb : fsm.getInputAlphabet ( ) ) {
auto trA = fsm.getTransitions ( ).find ( ext::make_pair ( a, symb ) );
auto trB = fsm.getTransitions ( ).find ( ext::make_pair ( b, symb ) );
if ( trA == fsm.getTransitions ( ).end ( ) && trB == fsm.getTransitions ( ).end ( ) ) {
// end up in the same target state (dead state) -> not distinguishable
} else if ( trA == fsm.getTransitions ( ).end ( ) || trB == fsm.getTransitions ( ).end ( ) || distinguishable.count ( ext::make_pair ( trA -> second, trB -> second ) ) ) {
// end up in dead state - dead state is be distinguishable from every other state OR
// end up in distinguishable states
if ( ! distinguishable.count ( ext::make_pair ( a, b ) ) ) { // we have not yet found this
distinguishable.insert ( ext::make_pair ( a, b ) );
distinguishable.insert ( ext::make_pair ( b, a ) );
changed = true;
}
}
}
}
}
} while ( changed );
return distinguishable;
}
} /* namespace properties */
} /* namespace automaton */
#endif /* DISTINGUISHABLE_STATES_H_ */
#include <catch2/catch.hpp>
#include <automaton/FSM/DFA.h>
#include "automaton/properties/DistinguishableStates.h"
TEST_CASE ( "Distringuishable States Test", "[unit][algo][automaton]" ) {
SECTION ( "Test" ) {
{
DefaultStateType qA ( "qA" );
DefaultStateType qB ( "qB" );
DefaultStateType qC ( "qC" );
DefaultStateType qD ( "qD" );
DefaultStateType qE ( "qE" );
DefaultStateType qF ( "qF" );
DefaultStateType qG ( "qG" );
DefaultStateType qH ( "qH" );
automaton::DFA < > automaton ( qA );
automaton.setStates ( { qA, qB, qC, qD, qE, qF, qG, qH } );
automaton.setFinalStates ( { qC } );
automaton.addInputSymbols ( { DefaultSymbolType ( 0 ), DefaultSymbolType ( 1 ) } );
automaton.addTransition(qA, DefaultSymbolType ( 0 ), qB);
automaton.addTransition(qA, DefaultSymbolType ( 1 ), qF);
automaton.addTransition(qB, DefaultSymbolType ( 0 ), qG);
automaton.addTransition(qB, DefaultSymbolType ( 1 ), qC);
automaton.addTransition(qC, DefaultSymbolType ( 0 ), qA);
automaton.addTransition(qC, DefaultSymbolType ( 1 ), qC);
automaton.addTransition(qD, DefaultSymbolType ( 0 ), qC);
automaton.addTransition(qD, DefaultSymbolType ( 1 ), qG);
automaton.addTransition(qE, DefaultSymbolType ( 0 ), qH);
automaton.addTransition(qE, DefaultSymbolType ( 1 ), qF);
automaton.addTransition(qF, DefaultSymbolType ( 0 ), qC);
automaton.addTransition(qF, DefaultSymbolType ( 1 ), qG);
automaton.addTransition(qG, DefaultSymbolType ( 0 ), qG);
automaton.addTransition(qG, DefaultSymbolType ( 1 ), qE);
automaton.addTransition(qH, DefaultSymbolType ( 0 ), qG);
automaton.addTransition(qH, DefaultSymbolType ( 1 ), qC);
ext::set < ext::pair < DefaultStateType, DefaultStateType > > exp;
const ext::set < ext::pair < DefaultStateType, DefaultStateType > > res = automaton::properties::DistinguishableStates::distinguishableStates ( automaton );
const ext::set < ext::pair < DefaultStateType, DefaultStateType > > exp_ ( {
ext::make_pair ( qA, qB ), ext::make_pair ( qA, qC ), ext::make_pair ( qA, qD ), ext::make_pair ( qA, qF ), ext::make_pair ( qA, qG ), ext::make_pair ( qA, qH ),
ext::make_pair ( qB, qC ), ext::make_pair ( qB, qD ), ext::make_pair ( qB, qE ), ext::make_pair ( qB, qF ), ext::make_pair ( qB, qG ),
ext::make_pair ( qC, qD ), ext::make_pair ( qC, qE ), ext::make_pair ( qC, qF ), ext::make_pair ( qC, qG ), ext::make_pair ( qC, qH ),
ext::make_pair ( qD, qE ), ext::make_pair ( qD, qG ), ext::make_pair ( qD, qH ),
ext::make_pair ( qE, qF ), ext::make_pair ( qE, qG ), ext::make_pair ( qE, qH ),
ext::make_pair ( qF, qG ), ext::make_pair ( qF, qH ),
ext::make_pair ( qG, qH ),
} );
for ( const auto & x : exp_ ) {
exp.insert ( ext::make_pair ( x.first, x.second ) );
exp.insert ( ext::make_pair ( x.second, x.first ) );
}
CHECK ( res == exp );
}
{
DefaultStateType qA ( "qA" );
DefaultStateType qB ( "qB" );
DefaultStateType qC ( "qC" );
DefaultStateType qD ( "qD" );
DefaultStateType qE ( "qE" );
DefaultStateType qF ( "qF" );
automaton::DFA < > automaton ( qA );
automaton.setStates ( { qA, qB, qC, qD, qE, qF } );
automaton.setFinalStates ( { qC, qF } );
automaton.addInputSymbols ( { DefaultSymbolType ( 0 ), DefaultSymbolType ( 1 ) } );
automaton.addTransition(qA, DefaultSymbolType ( 0 ), qB);
automaton.addTransition(qA, DefaultSymbolType ( 1 ), qD);
automaton.addTransition(qB, DefaultSymbolType ( 0 ), qC);
automaton.addTransition(qD, DefaultSymbolType ( 0 ), qE);
automaton.addTransition(qE, DefaultSymbolType ( 0 ), qF);
ext::set < ext::pair < DefaultStateType, DefaultStateType > > exp;
const ext::set < ext::pair < DefaultStateType, DefaultStateType > > res = automaton::properties::DistinguishableStates::distinguishableStates ( automaton );
const ext::set < ext::pair < DefaultStateType, DefaultStateType > > exp_ ( {
ext::make_pair ( qA, qB ), ext::make_pair ( qA, qC ), ext::make_pair ( qA, qD ), ext::make_pair ( qA, qE ), ext::make_pair ( qA, qF ),
ext::make_pair ( qB, qC ), ext::make_pair ( qB, qD ), ext::make_pair ( qB, qF ),
ext::make_pair ( qC, qD ), ext::make_pair ( qC, qE ),
ext::make_pair ( qD, qE ), ext::make_pair ( qD, qF ),
ext::make_pair ( qE, qF )
} );
for ( const auto & x : exp_ ) {
exp.insert ( ext::make_pair ( x.first, x.second ) );
exp.insert ( ext::make_pair ( x.second, x.first ) );
}
CHECK ( res == exp );
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment