libgsjj  1
Deterministic finite automata learning library
DFA.h
Go to the documentation of this file.
1 
7 #pragma once
8 
9 // These container hash the keys, therefore the average complexity is constant
10 #include <unordered_set>
11 // These container use a red-black tree, therefore the complexity is logarithmic
12 #include <map>
13 #include <vector>
14 #include <list>
15 #include <memory>
16 
17 #include <string>
18 #include <sstream>
19 
23 namespace gsjj {
38  template<typename Sigma>
39  class DFA {
40  public:
47  DFA(unsigned int initial, bool isAccepting = false) {
48  m_states.insert(initial);
49  m_initialState = initial;
50  if (isAccepting) {
51  m_acceptingStates.insert(initial);
52  }
53  }
54 
62  void addState(unsigned int state, bool isAccepting = false) {
63  m_states.insert(state); // The check if the state is already in the set is automatically done in the insert function
64  if (isAccepting) {
65  m_acceptingStates.insert(state);
66  }
67  }
68 
79  void addTransition(unsigned int p, Sigma symbol, unsigned int q) {
80  if (m_states.find(p) == m_states.end()) {
81  std::ostringstream error;
82  error << p << " is not known when adding the transition " << p << " --" << symbol << "--> " << q;
83  throw std::out_of_range(error.str());
84  }
85  else if (m_states.find(q) == m_states.end()) {
86  std::ostringstream error;
87  error << q << " is not known when adding the transition " << p << " --" << symbol << "--> " << q;
88  throw std::out_of_range(error.str());
89  }
90 
91  m_transitions[p][symbol] = q;
92  }
93 
99  bool isAccepted(const std::list<Sigma>& word) {
100  unsigned int state = m_initialState;
101  for (const Sigma &a : word) {
102  auto itr = m_transitions.find(state);
103  if (itr == m_transitions.end()) {
104  return false;
105  }
106  auto tran = itr->second.find(a);
107 
108  if (tran != itr->second.end()) {
109  state = tran->second;
110  }
111  else {
112  return false;
113  }
114  }
115 
116  return isAcceptingState(state);
117  }
118 
124  bool isAccepted(const std::vector<Sigma> &word) {
125  unsigned int state = m_initialState;
126  for (const Sigma &a : word) {
127  auto tran = m_transitions.find(std::make_pair(state, a));
128 
129  if (tran != m_transitions.end()) {
130  state = tran->second;
131  }
132  else {
133  return false;
134  }
135  }
136 
137  return isAcceptingState(state);
138  }
139 
144  unsigned int getNumberOfStates() const {
145  return m_states.size();
146  }
147 
152  std::string to_dot() const {
153  std::ostringstream dot;
154  dot << "digraph deterministic_finite_automaton {\n";
155  dot << "\trankdir=LR;\n";
156  dot << "\tsize=\"8.5\"\n";
157  process_states_dot(dot);
158  process_transitions_dot(dot);
159  dot << "}\n";
160  return dot.str();
161  }
162 
169  template<typename T>
170  std::unique_ptr<DFA<T>> convert(const std::map<Sigma, T> &conversionMap) const {
171  std::unique_ptr<DFA<T>> converted = std::make_unique<DFA<T>>(m_initialState, isAcceptingState(m_initialState));
172 
173  for (unsigned int state : m_states) {
174  if (state != m_initialState) {
175  converted->addState(state, isAcceptingState(state));
176  }
177  }
178 
179  for (auto transition : m_transitions) {
180  unsigned int p = transition.first;
181  for (auto t : transition.second) {
182  T a = conversionMap.at(t.first);
183  unsigned int q = t.second;
184  converted->addTransition(p, a, q);
185  }
186  }
187 
188  return std::move(converted);
189  }
190 
196  bool isAcceptingState(unsigned int state) const {
197  return m_acceptingStates.find(state) != m_acceptingStates.end();
198  }
199 
204  const std::unordered_set<unsigned int> &getStates() const {
205  return m_states;
206  }
207 
214  const std::unordered_set<unsigned int> &getAcceptingStates() const {
215  return m_acceptingStates;
216  }
217 
224  unsigned int getInitialState() const {
225  return m_initialState;
226  }
227 
233  const std::map<unsigned int, std::map<Sigma, unsigned int>> getTransitions() const {
234  return m_transitions;
235  }
236 
242  bool isState(unsigned int state) const {
243  return m_states.find(state) != m_states.end();
244  }
245 
246  private:
250  std::unordered_set<unsigned int> m_states;
254  unsigned int m_initialState;
258  std::map<unsigned int, std::map<Sigma, unsigned int>> m_transitions;
262  std::unordered_set<unsigned int> m_acceptingStates;
263 
264  private:
269  void process_states_dot(std::ostringstream& dot) const {
270  // We must add one state to create the arrow indicating the initial state
271  dot << "\tnode [shape=none, label=\"\"] qi\n";
272  for (int state : m_states) {
273  dot << "\tnode [shape=";
274  // Accepting states are double circled
275  if (isAcceptingState(state)) {
276  dot << "doublecircle";
277  }
278  else {
279  dot << "circle";
280  }
281 
282  dot << ", label=\"q" << state << "\"] q" << state << ";\n";
283  }
284  }
285 
290  void process_transitions_dot(std::ostringstream &dot) const {
291  // The arrow indicating the initial state
292  dot << "\tqi -> q" << m_initialState << ";\n";
293 
294  for (auto state : m_transitions) {
295  unsigned int start = state.first;
296  for (auto transition : state.second) {
297  Sigma symbol = transition.first;
298  unsigned int end = transition.second;
299  dot << "\tq" << start << " -> q" << end << " [label=\"" << symbol << "\"];\n";
300  }
301  }
302  }
303  };
304 }
bool isState(unsigned int state) const
Checks if the given state number is in the states set.
Definition: DFA.h:242
The namespace of the library.
Definition: binary.h:11
const std::unordered_set< unsigned int > & getAcceptingStates() const
Returns the set of accepting states of this DFA.
Definition: DFA.h:214
bool isAcceptingState(unsigned int state) const
Tests whether the given state is a final (or accepting) state.
Definition: DFA.h:196
unsigned int getNumberOfStates() const
Returns the number of states in this DFA.
Definition: DFA.h:144
std::unique_ptr< DFA< T > > convert(const std::map< Sigma, T > &conversionMap) const
Creates a new DFA with exactly the same number of states and the same transitions but the type of the...
Definition: DFA.h:170
bool isAccepting(Expr f_value)
bool isAccepted(const std::list< Sigma > &word)
Tests whether the word is accepted by the DFA.
Definition: DFA.h:99
const std::unordered_set< unsigned int > & getStates() const
Returns the set of states in this DFA.
Definition: DFA.h:204
std::string to_dot() const
Constructs a string that is the representation of the DFA in the DOT language.
Definition: DFA.h:152
bool isAccepted(const std::vector< Sigma > &word)
Tests whether the word is accepted by the DFA.
Definition: DFA.h:124
DFA(unsigned int initial, bool isAccepting=false)
Constructs the DFA.
Definition: DFA.h:47
void addState(unsigned int state, bool isAccepting=false)
Adds a state to the DFA.
Definition: DFA.h:62
void addTransition(unsigned int p, Sigma symbol, unsigned int q)
Adds a transition to the DFA.
Definition: DFA.h:79
A Deterministic Finite Automaton.
Definition: DFA.h:39
const std::map< unsigned int, std::map< Sigma, unsigned int > > getTransitions() const
Returns the function delta.
Definition: DFA.h:233
unsigned int getInitialState() const
Returns the initial state of this DFA.
Definition: DFA.h:224