-
Tomáš Pecka authoredTomáš Pecka authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ArcFactoredNondeterministicZAutomaton.h 24.83 KiB
/*
* 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/>.
*/
#pragma once
#include <ostream>
#include <sstream>
#include <alib/multimap>
#include <alib/set>
#include <alib/vector>
#include <alib/compare>
#include <core/components.hpp>
#include <common/DefaultStateType.h>
#include <common/DefaultSymbolType.h>
#include <automaton/AutomatonException.h>
#include <core/normalize.hpp>
#include <alphabet/common/SymbolNormalize.h>
#include <automaton/common/AutomatonNormalize.h>
#include "ArcFactoredDeterministicZAutomaton.h"
namespace automaton {
class InputAlphabet;
class States;
class FinalStates;
/**
* \brief
* Nondeterministic Z-Automaton in Arc-Factored Normal Form. Computation model for unranked regular tree languages.
*
* \details
* Defined in Björklund, Drewes, Satta: Z-Automata for Compact and Direct Representation of Unranked Tree Languages
* https://doi.org/10.1007/978-3-030-23679-3_7
*
* Nondeterministic Z-Automaton in Arc-Factored Normal Form is a Nondeterministic Z-Automaton
* where every transition is in arc-factored normal form.
* A transition is in arc-factored normal form if its lhs is in (\Sigma \cup Q(Q)).
*
* \tparam SymbolTypeT used for the symbols of the tree the automaton is executed on.
* \tparam StateTypeT used for the states, and the initial state of the automaton.
*/
template < class SymbolTypeT = DefaultSymbolType, class StateTypeT = DefaultStateType >
class ArcFactoredNondeterministicZAutomaton final : public core::Components < ArcFactoredNondeterministicZAutomaton < SymbolTypeT, StateTypeT >, ext::set < SymbolTypeT >, component::Set, InputAlphabet, ext::set < StateTypeT >, component::Set, std::tuple < States, FinalStates > > {
public:
typedef SymbolTypeT SymbolType;
typedef StateTypeT StateType;
private:
/**
* Transition function as mapping from a list of states times an input symbol on the left hand side to a state.
*/
ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > transitions;
public:
/**
* \brief Creates a new instance of the automaton.
*/
explicit ArcFactoredNondeterministicZAutomaton ( );
/**
* \brief Creates a new instance of the automaton with a concrete set of states, input alphabet, and a set of final states.
*
* \param states the initial set of states of the automaton
* \param inputAlphabet the initial input alphabet
* \param finalStates the initial set of final states of the automaton
*/
explicit ArcFactoredNondeterministicZAutomaton ( ext::set < StateType > states, ext::set < SymbolType > inputAlphabet, ext::set < StateType > finalStates );
/*
* \brief Creates a new instance of the automaton based on the Deterministic finite tree automaton.
*
* \param other the Deterministic finite tree automaton
*/
explicit ArcFactoredNondeterministicZAutomaton ( const ArcFactoredDeterministicZAutomaton < SymbolType, StateType > & other );
/**
* Getter of states.
*
* \returns the states of the automaton
*/
const ext::set < StateType > & getStates ( ) const & {
return this->template accessComponent < States > ( ).get ( );
}
/**
* Getter of states.
*
* \returns the states of the automaton
*/
ext::set < StateType > && getStates ( ) && {
return std::move ( this->template accessComponent < States > ( ).get ( ) );
}
/**
* Adder of a state.
*
* \param state the new state to be added to a set of states
*
* \returns true if the state was indeed added
*/
bool addState ( StateType state ) {
return this->template accessComponent < States > ( ).add ( std::move ( state ) );
}
/**
* Setter of states.
*
* \param states completely new set of states
*/
void setStates ( ext::set < StateType > states ) {
this->template accessComponent < States > ( ).set ( std::move ( states ) );
}
/**
* Remover of a state.
*
* \param state a state to be removed from a set of states
*
* \returns true if the state was indeed removed
*/
void removeState ( const StateType & state ) {
this->template accessComponent < States > ( ).remove ( state );
}
/**
* Getter of final states.
*
* \returns the final states of the automaton
*/
const ext::set < StateType > & getFinalStates ( ) const & {
return this->template accessComponent < FinalStates > ( ).get ( );
}
/**
* Getter of final states.
*
* \returns the final states of the automaton
*/
ext::set < StateType > && getFinalStates ( ) && {
return std::move ( this->template accessComponent < FinalStates > ( ).get ( ) );
}
/**
* Adder of a final state.
*
* \param state the new state to be added to a set of final states
*
* \returns true if the state was indeed added
*/
bool addFinalState ( StateType state ) {
return this->template accessComponent < FinalStates > ( ).add ( std::move ( state ) );
}
/**
* Setter of final states.
*
* \param states completely new set of final states
*/
void setFinalStates ( ext::set < StateType > states ) {
this->template accessComponent < FinalStates > ( ).set ( std::move ( states ) );
}
/**
* Remover of a final state.
*
* \param state a state to be removed from a set of final states
*
* \returns true if the state was indeed removed
*/
void removeFinalState ( const StateType & state ) {
this->template accessComponent < FinalStates > ( ).remove ( state );
}
/**
* Getter of the input alphabet.
*
* \returns the input alphabet of the automaton
*/
const ext::set < SymbolType > & getInputAlphabet ( ) const & {
return this->template accessComponent < InputAlphabet > ( ).get ( );
}
/**
* Getter of the input alphabet.
*
* \returns the input alphabet of the automaton
*/
ext::set < SymbolType > && getInputAlphabet ( ) && {
return std::move ( this->template accessComponent < InputAlphabet > ( ).get ( ) );
}
/**
* Adder of a input symbol.
*
* \param symbol the new symbol to be added to an input alphabet
*
* \returns true if the symbol was indeed added
*/
bool addInputSymbol ( SymbolType symbol ) {
return this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) );
}
/**
* Adder of input symbols.
*
* \param symbols new symbols to be added to an input alphabet
*/
void addInputSymbols ( ext::set < SymbolType > symbols ) {
this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) );
}
/**
* Setter of input alphabet.
*
* \param symbols completely new input alphabet
*/
void setInputAlphabet ( ext::set < SymbolType > symbols ) {
this->template accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) );
}
/**
* Remover of an input symbol.
*
* \param symbol a symbol to be removed from an input alphabet
*
* \returns true if the symbol was indeed removed
*/
void removeInputSymbol ( const SymbolType & symbol ) {
this->template accessComponent < InputAlphabet > ( ).remove ( symbol );
}
/**
* \brief Add a transition to the automaton.
*
* \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T
*
* \param children the source states (A, B, C, ...)
* \param current the input symbol (a)
* \param next the target state (B)
*
* \throws AutomatonException when transition contains state or symbol not present in the automaton components
*
* \returns true if the transition was indeed added
*/
bool addTransition ( ext::variant < SymbolType, ext::pair < StateType, StateType > > lhs, StateType rhs );
bool addTransition ( SymbolType lhs, StateType rhs );
bool addTransition ( ext::pair < StateType, StateType > lhs, StateType rhs );
/**
* \brief Removes a transition from the automaton.
*
* \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T
*
* \param children the source states (A, B, C, ...)
* \param current the input symbol (a)
* \param next the target state (B)
*
* \returns true if the transition was indeed removed
*/
bool removeTransition ( const ext::variant < SymbolType, ext::pair < StateType, StateType > > & lhs, const StateType & next );
/**
* Get the transition function of the automaton in its natural form.
*
* \returns transition function of the automaton
*/
const ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > & getTransitions ( ) const & {
return transitions;
}
/**
* Get the transition function of the automaton in its natural form.
*
* \returns transition function of the automaton
*/
ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > && getTransitions ( ) && {
return std::move ( transitions );
}
/**
* \returns transitions to state @p q
*/
ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > getTransitionsToState ( const StateType & q ) const {
ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > res;
for ( const auto & transition : getTransitions ( ) ) {
if ( transition.second == q )
res.insert ( std::make_pair ( transition.first, q ) );
}
return res;
}
/**
* \returns transitions from state @p q
*/
ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > getTransitionsFromState ( const StateType & q ) const {
ext::multimap < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > res;
for ( const auto & transition : getTransitions ( ) ) {
if ( transition.first.template is < ext::pair < StateType, StateType > > ( ) && transition.first.template get < ext::pair < StateType, StateType > > ( ).second == q )
res.insert ( transition );
}
return res;
}
/**
* The three way comparison implementation
*
* \param other the other instance
*
* \returns the ordering between this object and the @p other.
*/
auto operator <=> ( const ArcFactoredNondeterministicZAutomaton & other ) const {
return std::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions) <=> std::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions);
}
/**
* The equality comparison implementation.
*
* \param other the other object to compare with.
*
* \returns true if this and other objects are equal, false othervise
*/
bool operator == ( const ArcFactoredNondeterministicZAutomaton & other ) const {
return std::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions) == std::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions);
}
/**
* Print this object as raw representation to ostream.
*
* \param out ostream where to print
* \param instance object to print
*
* \returns modified output stream
*/
friend std::ostream & operator << ( std::ostream & out, const ArcFactoredNondeterministicZAutomaton & instance ) {
return out << "(ArcFactoredNondeterministicZAutomaton "
<< " states = " << instance.getStates ( )
<< " inputAlphabet = " << instance.getInputAlphabet ( )
<< " finalStates = " << instance.getFinalStates ( )
<< " transitions = " << instance.getTransitions ( )
<< ")";
}
/**
* Casts this instance to as compact as possible string representation.
*
* \returns string representation of the object
*/
operator std::string ( ) const;
};
/**
* Trait to detect whether the type parameter T is or is not NAFZA. Derived from std::false_type.
*
* \tparam T the tested type parameter
*/
template < class T >
class isNAFZA_impl : public std::false_type {};
/**
* Trait to detect whether the type parameter T is or is not NAFZA. Derived from std::true_type.
*
* Specialisation for NAFZA.
*
* \tparam SymbolType used for the terminal alphabet of the automaton
* \tparam StateType used for the terminal alphabet of the automaton
*/
template < class SymbolType, class StateType >
class isNAFZA_impl < ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > > : public std::true_type {};
/**
* Constexpr true if the type parameter T is NAFZA, false otherwise.
*
* \tparam T the tested type parameter
*/
template < class T >
constexpr bool isNAFZA = isNAFZA_impl < T > { };
template<class SymbolType, class StateType >
ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::ArcFactoredNondeterministicZAutomaton ( ext::set < StateType > states, ext::set < SymbolType > inputAlphabet, ext::set < StateType > finalStates ) : core::Components < ArcFactoredNondeterministicZAutomaton, ext::set < SymbolType >, component::Set, InputAlphabet, ext::set < StateType >, component::Set, std::tuple < States, FinalStates > > ( std::move ( inputAlphabet ), std::move ( states ), std::move ( finalStates ) ) {
}
template<class SymbolType, class StateType >
ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::ArcFactoredNondeterministicZAutomaton() : ArcFactoredNondeterministicZAutomaton ( ext::set < StateType > { }, ext::set < SymbolType > { }, ext::set < StateType > { } ) {
}
template < class SymbolType, class StateType >
ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::ArcFactoredNondeterministicZAutomaton(const ArcFactoredDeterministicZAutomaton < SymbolType, StateType > & other) : ArcFactoredNondeterministicZAutomaton ( other.getStates(), other.getInputAlphabet(), other.getFinalStates() ) {
transitions.insert ( other.getTransitions ( ).begin ( ), other.getTransitions ( ).end ( ) );
}
template<class SymbolType, class StateType >
bool ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::addTransition ( ext::variant < SymbolType, ext::pair < StateType, StateType > > lhs, StateType rhs ) {
if ( lhs.template is < SymbolType > ( ) && ! getInputAlphabet ( ).count ( lhs.template get < SymbolType > ( ) ) )
throw AutomatonException("Input symbol \"" + ext::to_string ( lhs.template get < SymbolType > ( ) ) + "\" doesn't exist.");
if ( lhs.template is < ext::pair < StateType, StateType > > ( ) ) {
const ext::pair < StateType, StateType > & stateLhs = lhs.template get < ext::pair < StateType, StateType > > ( );
if ( ! getStates ( ).count ( stateLhs.first ) )
throw AutomatonException("State \"" + ext::to_string ( stateLhs.first ) + "\" doesn't exist.");
if ( ! getStates ( ).count ( stateLhs.second ) )
throw AutomatonException("State \"" + ext::to_string ( stateLhs.second ) + "\" doesn't exist.");
}
if (! getStates().count(rhs))
throw AutomatonException("State \"" + ext::to_string ( rhs ) + "\" doesn't exist.");
auto upper_bound = transitions.upper_bound ( lhs );
auto lower_bound = transitions.lower_bound ( lhs );
auto iter = std::lower_bound ( lower_bound, upper_bound, rhs, [ ] ( const auto & transition, const auto & target ) { return transition.second < target; } );
if ( iter != upper_bound && rhs >= iter->second )
return false;
transitions.insert ( iter, std::make_pair ( std::move ( lhs ), std::move ( rhs ) ) );
return true;
}
template<class SymbolType, class StateType >
bool ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::addTransition ( SymbolType lhs, StateType rhs ) {
return addTransition ( ext::variant < SymbolType, ext::pair < StateType, StateType > > ( std::move ( lhs ) ), std::move ( rhs ) );
}
template<class SymbolType, class StateType >
bool ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::addTransition ( ext::pair < StateType, StateType > lhs, StateType rhs ) {
return addTransition ( ext::variant < SymbolType, ext::pair < StateType, StateType > > ( std::move ( lhs ) ), std::move ( rhs ) );
}
template<class SymbolType, class StateType >
bool ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::removeTransition ( const ext::variant < SymbolType, ext::pair < StateType, StateType > > & lhs, const StateType & next ) {
auto upper_bound = transitions.upper_bound ( lhs );
auto lower_bound = transitions.lower_bound ( lhs );
auto iter = std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == next; } );
if ( iter == upper_bound )
return false;
transitions.erase ( iter );
return true;
}
template<class SymbolType, class StateType >
ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >::operator std::string ( ) const {
std::stringstream ss;
ss << *this;
return ss.str();
}
} /* namespace automaton */
namespace core {
/**
* Helper class specifying constraints for the automaton's internal input alphabet component.
*
* \tparam SymbolType used for the symbols of the tree the automaton is executed on.
* \tparam StateType used for the states, and the initial state of the automaton.
*/
template<class SymbolType, class StateType >
class SetConstraint< automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >, SymbolType, automaton::InputAlphabet > {
public:
/**
* Returns true if the symbol is still used in some transition of the automaton.
*
* \param automaton the tested automaton
* \param symbol the tested symbol
*
* \returns true if the symbol is used, false othervise
*/
static bool used ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > & automaton, const SymbolType & symbol ) {
for ( const std::pair < const ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > & t : automaton.getTransitions ( ) )
if ( t.first == symbol )
return true;
return false;
}
/**
* Returns true as all symbols are possibly available to be elements of the input alphabet.
*
* \param automaton the tested automaton
* \param symbol the tested symbol
*
* \returns true
*/
static bool available ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > &, const SymbolType & ) {
return true;
}
/**
* All symbols are valid as input symbols.
*
* \param automaton the tested automaton
* \param symbol the tested symbol
*/
static void valid ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > & automaton, const SymbolType & symbol ) {
if ( automaton.template accessComponent < automaton::States > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
throw automaton::AutomatonException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the input alphabet since it is already in the states set." );
}
};
/**
* Helper class specifying constraints for the automaton's internal states component.
*
* \tparam SymbolType used for the symbols of the tree the automaton is executed on.
* \tparam StateType used for the states, and the initial state of the automaton.
*/
template<class SymbolType, class StateType >
class SetConstraint< automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >, StateType, automaton::States > {
public:
/**
* Returns true if the state is still used in some transition of the automaton.
*
* \param automaton the tested automaton
* \param state the tested state
*
* \returns true if the state is used, false othervise
*/
static bool used ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > & automaton, const StateType & state ) {
if ( automaton.getFinalStates ( ).count ( state ) )
return true;
for ( const std::pair < const ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > & t : automaton.getTransitions ( ) )
if ( t.first.template is < ext::pair < StateType, StateType > > ( ) ) {
const ext::pair < StateType, StateType > & lhs = t.first.template get < ext::pair < StateType, StateType > > ( );
if ( lhs.first == state || lhs.second == state )
return true;
}
return false;
}
/**
* Returns true as all states are possibly available to be elements of the states.
*
* \param automaton the tested automaton
* \param state the tested state
*
* \returns true
*/
static bool available ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > &, const StateType & ) {
return true;
}
/**
* All states are valid as a state of the automaton.
*
* \param automaton the tested automaton
* \param state the tested state
*/
static void valid ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > & automaton, const StateType & state ) {
if ( automaton.template accessComponent < automaton::InputAlphabet > ( ).get ( ).count ( ext::poly_comp ( state ) ) )
throw automaton::AutomatonException ( "State " + ext::to_string ( state ) + " cannot be in the states set since it is already in the input alphabet." );
}
};
/**
* Helper class specifying constraints for the automaton's internal final states component.
*
* \tparam SymbolType used for the symbols of the tree the automaton is executed on.
* \tparam StateType used for the states, and the initial state of the automaton.
*/
template<class SymbolType, class StateType >
class SetConstraint< automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType >, StateType, automaton::FinalStates > {
public:
/**
* Returns false. Final state is only a mark that the automaton itself does require further.
*
* \param automaton the tested automaton
* \param state the tested state
*
* \returns false
*/
static bool used ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > &, const StateType & ) {
return false;
}
/**
* Nondetermines whether the state is available in the automaton's states set.
*
* \param automaton the tested automaton
* \param state the tested state
*
* \returns true if the state is already in the set of states of the automaton
*/
static bool available ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > & automaton, const StateType & state ) {
return automaton.template accessComponent < automaton::States > ( ).get ( ).count ( state );
}
/**
* All states are valid as a final state of the automaton.
*
* \param automaton the tested automaton
* \param state the tested state
*/
static void valid ( const automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > &, const StateType & ) {
}
};
/**
* Helper for normalisation of types specified by templates used as internal datatypes of symbols and states.
*
* \returns new instance of the automaton with default template parameters or unmodified instance if the template parameters were already the default ones
*/
template < class SymbolType, class StateType >
struct normalize < automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > > {
static automaton::ArcFactoredNondeterministicZAutomaton < > eval ( automaton::ArcFactoredNondeterministicZAutomaton < SymbolType, StateType > && value ) {
ext::set < DefaultSymbolType > alphabet = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getInputAlphabet ( ) );
ext::set < DefaultStateType > states = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getStates ( ) );
ext::set < DefaultStateType > finalStates = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getFinalStates ( ) );
automaton::ArcFactoredNondeterministicZAutomaton < > res ( std::move ( states ), std::move ( alphabet ), std::move ( finalStates ) );
for ( std::pair < ext::variant < SymbolType, ext::pair < StateType, StateType > >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) {
if ( transition.first.template is < SymbolType > ( ) ) {
DefaultSymbolType lhs = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( transition.first.template get < SymbolType > ( ) ) );
DefaultStateType to = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) );
res.addTransition ( std::move ( lhs ), std::move ( to ) );
} else {
ext::pair < StateType, StateType > & lhs = transition.first.template get < ext::pair < StateType, StateType > > ( );
ext::pair < DefaultStateType, DefaultStateType > lshDefault = ext::make_pair ( automaton::AutomatonNormalize::normalizeState ( std::move ( lhs.first ) ), automaton::AutomatonNormalize::normalizeState ( std::move ( lhs.second ) ) );
DefaultStateType to = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) );
res.addTransition ( std::move ( lshDefault ), std::move ( to ) );
}
}
return res;
}
};
} /* namespace core */
extern template class automaton::ArcFactoredNondeterministicZAutomaton < >;