Limi
timbuk_printer.h
1 /*
2  * Copyright 2016, IST Austria
3  *
4  * This file is part of Limi.
5  *
6  * Limi is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Limi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with Limi. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LIMI_TIMBUK_PRINTER_H
21 #define LIMI_TIMBUK_PRINTER_H
22 #include "automaton.h"
23 
24 #include <iostream>
25 #include <fstream>
26 #include <string>
27 #include <unordered_set>
28 #include <deque>
29 #include <unordered_map>
30 #include <cassert>
31 #include "internal/hash.h"
32 #include <cctype>
33 #include <sstream>
34 #include <stdexcept>
35 
36 namespace Limi {
37 
52 template <class State, class Symbol,class Implementation, class Independence = independence<Symbol>>
54  const Independence& independence_;
55 public:
56  timbuk_printer(const Independence& independence = Independence()) : independence_(independence) {
57 
58  }
59 
72  void print_timbuk(const automaton<State,Symbol,Implementation>& automaton, std::ostream& out, const printer_base<Symbol>& symbol_printer, const std::string& name = "A") {
73  std::unordered_map<State, unsigned> state_id;
74  std::unordered_set<Symbol> symbols;
75  std::unordered_multimap<std::pair<unsigned, Symbol>, unsigned> transitions; // (state, symbol), state
76  std::unordered_set<unsigned> final_state_ids;
77  std::unordered_set<unsigned> initial_state_ids;
78 
79  std::unordered_set<State> seen;
80  std::deque<State> frontier;
81  unsigned state_counter = 0; // give every state a unique id
82  for (const auto& s : automaton.initial_states()) {
83  frontier.push_back(s);
84  state_id[s] = ++state_counter;
85  initial_state_ids.insert(state_id[s]);
86  }
87 
88 #ifdef DEBUG_PRINTING
89  unsigned loop_counter = 0;
90 #endif
91  while (!frontier.empty()) {
92 #ifdef DEBUG_PRINTING
93  if (DEBUG_PRINTING>=2 && ++loop_counter % 1000 == 0) debug << loop_counter << " rounds; A states: " << state_id.size() << std::endl;
94 #endif
95 
96  State next = frontier.front();
97  frontier.pop_front();
98  if (seen.find(next) == seen.end()) {
99  seen.insert(next);
100  auto next_it = state_id.find(next);
101  assert(next_it != state_id.end());
102 
103  if (automaton.is_final_state(next))
104  final_state_ids.insert(next_it->second);
105  for (const Symbol& symbol : automaton.next_symbols(next)) {
106  symbols.insert(symbol);
107  for (const State& succ : automaton.successors(next, symbol)) {
108  // put id
109  auto succ_it = state_id.find(succ);
110  if (succ_it == state_id.end()) succ_it = state_id.insert(std::make_pair(succ, ++state_counter)).first;
111 
112  frontier.push_back(succ);
113  transitions.insert(std::make_pair(std::make_pair(next_it->second,symbol),succ_it->second));
114  }
115  }
116  }
117  }
118 
119 
120  // do the printing
121  out << "Ops init:1 ";
122  for (const auto& symbol : symbols) {
123  out << symbol_printer(symbol) << ":2 ";
124  // check if the symbol is printed correctly
125  std::stringstream sym_ss;
126  sym_ss << symbol_printer(symbol);
127  std::string sym_str = sym_ss.str();
128  if (sym_str=="init")
129  throw std::logic_error("No symbol may be called init. Are you trying to print an automaton previously printed and parsed by timbuk.");
130  for (char c : sym_str) {
131  if (!isalnum(c))
132  throw std::logic_error("Symbols must only consist of alphanumeric characters. This symbol violates this: " + sym_str);
133  }
134  }
135  out << std::endl;
136 
137  // independence relation
138  std::unordered_set<std::pair<Symbol,Symbol>> independence_set;
139  for (auto it = symbols.begin(); it!=symbols.end(); ++it) {
140  auto it2 = it;
141  for (++it2; it2!=symbols.end(); ++it2) {
142  if (independence_(*it, *it2))
143  independence_set.insert(std::make_pair(*it,*it2));
144  }
145  }
146 
147  if (!independence_set.empty()) {
148  out << "Independence ";
149  for (const auto& p : independence_set) {
150  out << "(" << symbol_printer(p.first) << " " << symbol_printer(p.second) << ") ";
151  }
152  out << std::endl;
153  }
154 
155  out << "Automaton " << name << std::endl;
156 
157  out << "States ";
158  for (const auto& state : state_id) {
159  out << "st" << name << state.second << " ";
160  }
161  out << std::endl;
162 
163  out << "Final States ";
164  for (const auto& state : final_state_ids) {
165  out << "st" << name << state << " ";
166  }
167  out << std::endl;
168 
169  out << "Transitions" << std::endl;
170  for (const auto& state : initial_state_ids) {
171  out << "init -> st" << name << state << std::endl;
172  }
173  for (const auto& trans : transitions) {
174  out << symbol_printer(trans.first.second) << "(st" << name << trans.first.first << ") -> st" << name << trans.second << std::endl;
175  }
176  }
177 
182  void print_timbuk(const automaton<State,Symbol,Implementation>& automaton, const std::string& filename, const printer_base<Symbol>& symbol_printer, const std::string& name = "A") {
183  std::ofstream myfile;
184  myfile.open(filename);
185  print_timbuk(automaton, myfile, symbol_printer, name);
186  myfile.close();
187  }
188 };
189 }
190 
191 #endif // LIMI_TIMBUK_PRINTER_H
void next_symbols(const State &state, Symbol_vector &symbols) const
Returns possible successor symbols for a state.
Definition: automaton.h:256
The main namespace of the library.
Definition: antichain_algo.h:40
Prints automata in timbuk format.
Definition: timbuk_printer.h:53
The template for the independence relation.
Definition: generics.h:53
void print_timbuk(const automaton< State, Symbol, Implementation > &automaton, std::ostream &out, const printer_base< Symbol > &symbol_printer, const std::string &name="A")
Prints the automaton.
Definition: timbuk_printer.h:72
bool is_final_state(const State &state) const
This function determines if a specific state is final.
Definition: automaton.h:160
void successors(const State &state, const Symbol &sigma, State_vector &successors1) const
Returns the successor for a specific state.
Definition: automaton.h:201
void print_timbuk(const automaton< State, Symbol, Implementation > &automaton, const std::string &filename, const printer_base< Symbol > &symbol_printer, const std::string &name="A")
Definition: timbuk_printer.h:182
void initial_states(State_vector &states) const
Returns the initial states.
Definition: automaton.h:167
Automata need to inherit from this class and implement certain methods.
Definition: automaton.h:49