Limi
antichain_algo_ind.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_ANTICHAINALGO_IND_H
21 #define LIMI_ANTICHAINALGO_IND_H
22 
23 #include "automaton.h"
24 #include <algorithm>
25 #include <vector>
26 #include <list>
27 #include <set>
28 #include <deque>
29 #include <queue>
30 #include <memory>
31 #include <iostream>
32 #include "internal/antichain.h"
33 #include "results.h"
34 #include "internal/helpers.h"
35 #include "internal/meta_automaton.h"
36 
41 namespace Limi {
42 
66 template <class ImplementationA, class InnerImplementationB, class Independence = independence<typename ImplementationA::Symbol_>>
68 {
69  using StateA = typename ImplementationA::State_;
70  using InnerStateB = typename InnerImplementationB::State_;
71  using Symbol = typename ImplementationA::Symbol_;
72 
74  using StateB = typename ImplementationB::StateI;
75  using StateA_vector = std::vector<StateA>;
76  using StateB_set = std::unordered_set<StateB>;
77  using StateBI_set = std::shared_ptr<const StateB_set>;
78  using Symbol_set = std::unordered_set<Symbol>;
79  using Symbol_vector = std::vector<Symbol>;
83 
85  using pcounter_chain = std::shared_ptr<counter_chain>;
86 
87  struct pair {
88  StateA a;
89  StateBI_set b;
90  pair(StateA a, StateBI_set b) : a(a), b(b), cex_chain(nullptr) {}
91  pair(StateA a, StateBI_set b, const pcounter_chain& parent, const Symbol& sym) : pair(a,b)
92  {
93  cex_chain = std::make_shared<counter_chain>(sym, parent);
94  }
95 
96  bool dirty = false;
97  pcounter_chain cex_chain;
98  };
99 
101 
102  void prune(std::shared_ptr<StateB_set>& b, StateBI_set& un_pruned, unsigned k, bool dirty) {
103  for(auto it = b->begin(); it!=b->end(); ) {
104  if ((**it).size() > k) {
105  if (!un_pruned && !dirty) {
106  un_pruned = std::make_shared<StateB_set>(*b);
107  }
108  it = b->erase(it);
109  } else {
110  ++it;
111  }
112  }
113  }
114 
115  void remove_dirty(std::deque<pair>& frontier) {
116  std::deque<pair> newp;
117  while (!frontier.empty()) {
118  auto& e = frontier.front();
119  if (!e.dirty) {
120  newp.push_back(e);
121  }
122  frontier.pop_front();
123  }
124  frontier = newp;
125  }
126 
127  std::deque<pair> initial_states(const AutomatonA& a, const AutomatonB& b) {
128  std::shared_ptr<StateB_set> states_b = std::make_shared<StateB_set>();
129  b.initial_states(*states_b);
130  std::deque< pair > result;
131  for(StateA state_a : a.initial_states()) {
132  pair p(state_a, states_b);
133  result.push_back(p);
134  antichain.add_unchecked(state_a, states_b, false);
135  }
136  return result;
137  }
138 
139  const AutomatonA& a;
140  ImplementationB b_;
141  const AutomatonB& b = b_;
142  pair_antichain antichain;
143 
144  unsigned bound = 2; // bound of the algorithm
145  const Independence& independence_;
146 
147  std::deque<pair> before_dirty;
148  std::deque<pair> frontier = initial_states(a,b);
149 public:
150 
160  antichain_algo_ind(const AutomatonA& a, const InnerAutomatonB& ib, unsigned initial_bound = 2, const Independence& independence = Independence()) :
161  a(a), b_(ib, independence), bound(initial_bound), independence_(independence) {
162  }
163 
168  unsigned get_bound() {
169  return bound;
170  }
171 
178  void increase_bound(unsigned new_bound) {
179  if (new_bound < bound) throw std::logic_error("New bound smaller than old bound.");
180  if (new_bound == bound) return;
181  bound = new_bound;
182  antichain.clean_dirty();
183 
184  remove_dirty(frontier);
185  for (auto& e : before_dirty) {
186  if (!antichain.contains(e.a, e.b)) {
187  frontier.push_back(e);
188  antichain.add(e.a, e.b, false);
189  }
190  }
191  before_dirty.clear();
192  }
193 
202  {
204  result.included = true;
205  result.bound_hit = false;
206  result.max_bound = bound;
207 
208 #ifdef DEBUG_PRINTING
209  unsigned loop_counter = 0;
210  unsigned transitions = 0;
211 #endif
212  while (frontier.size() > 0) {
213 #ifdef DEBUG_PRINTING
214  if (DEBUG_PRINTING>=2 && loop_counter % 1000 == 0) std::cout << loop_counter << " rounds; A states: " << antichain.size() << std::endl;
215 #endif
216  pair current = frontier.front();
217  frontier.pop_front();
218 
219  Symbol_vector next_symbols;
220  a.next_symbols(current.a, next_symbols);
221 
222 #ifdef DEBUG_PRINTING
223  ++ loop_counter;
224 #endif
225  if ((a.is_final_state(current.a) && !b.is_final_state(*current.b))) {
226  result.counter_example = current.cex_chain->to_vector();
227  result.included = false;
228  if (current.dirty)
229  result.bound_hit = true;
230  break;
231  }
232 
233 #ifdef DEBUG_PRINTING
234  if (DEBUG_PRINTING>=3) {
235  std::cout << "Next pair: ";
236  std::cout << a.state_printer()(current.a) << " - ";
237  internal::print_set(*current.b, std::cout, b.state_printer());
238  std::cout << std::endl;
239  }
240 #endif
241 
242  for (Symbol sigma : next_symbols) {
243 #ifdef DEBUG_PRINTING
244  ++transitions;
245  if (DEBUG_PRINTING>=4) {
246  std::cout << "Symbol: ";
247  std::cout << a.symbol_printer()(sigma);
248  std::cout << std::endl;
249  }
250 #endif
251  StateA_vector states_a = a.successors(current.a, sigma);
252  StateBI_set unpruned;
253  StateBI_set states_b;
254  if (a.is_epsilon(sigma)) states_b=current.b; else {
255  auto states_b1 = std::make_shared<StateB_set>();
256  b.successors(*current.b, sigma, *states_b1);
257  prune(states_b1, unpruned, bound, current.dirty);
258  states_b = states_b1;
259  }
260 
261  for (StateA state_a : states_a) {
262  antichain_algo_ind::pair next(state_a, states_b, current.cex_chain, sigma);
263  next.dirty = current.dirty || unpruned;
264  if (unpruned) before_dirty.push_back(antichain_algo_ind::pair(state_a, unpruned, current.cex_chain, sigma));
265 
266  if (!antichain.contains(next.a, next.b)) {
267  antichain.add(next.a, next.b, next.dirty);
268  frontier.push_front(std::move(next));
269  }
270  }
271  }
272 
273  }
274 
275 #ifdef DEBUG_PRINTING
276  if (DEBUG_PRINTING>=1) std::cout << loop_counter << " rounds; seen states: " << antichain.size() << "; transitions: " << transitions << std::endl;
277 
278  if (DEBUG_PRINTING >= 4) {
279  antichain.print(std::cout, a.state_printer(), b.state_printer());
280  }
281 #endif
282 
283  return result;
284  }
285 
286 };
287 
288 
289 }
290 
291 #endif // LIMI_ANTICHAINALGO_IND_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
This automaton presents an automaton up to an independence relation.
Definition: meta_automaton.h:43
The result of the language inclusion test.
Definition: results.h:78
void clean_dirty()
Remove elements marked as dirty.
Definition: antichain.h:139
void print(std::ostream &out, const printer_base< A > &printerA=printer< A >(), const printer_base< B > &printerB=printer< B >()) const
Print the antichain on the screen.
Definition: antichain.h:153
void add_unchecked(const A &a, const pb_set &b, bool dirty=false)
Add to the antichain an element without checking if the invariant is preserved.
Definition: antichain.h:80
Represents a list of symbols.
Definition: results.h:41
unsigned max_bound
The maximum bound used to obtain this inclusion result.
Definition: results.h:128
The template for the independence relation.
Definition: generics.h:53
std::vector< Symbol > counter_example
A counter-example if applicable.
Definition: results.h:106
bool contains(const A &a, const pb_set &b) const
Tests if the element (a,b) or a smaller element is already contained in the antichain.
Definition: antichain.h:116
inclusion_result< Symbol > run()
Run the language inclusion.
Definition: antichain_algo_ind.h:201
void increase_bound(unsigned new_bound)
Incleases the bound of the language inclusion check.
Definition: antichain_algo_ind.h:178
antichain_algo_ind(const AutomatonA &a, const InnerAutomatonB &ib, unsigned initial_bound=2, const Independence &independence=Independence())
Constructor that initialises the language inclusion algorithm.
Definition: antichain_algo_ind.h:160
const printer_base< State > & state_printer() const
Returns a printer for states.
Definition: automaton.h:292
bool is_epsilon(const Symbol &symbol) const
Determines if a symbol should be considered an epsilon transition.
Definition: automaton.h:320
bool included
True if automaton A is included in automaton B.
Definition: results.h:86
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
unsigned get_bound()
Returns the current bound.
Definition: antichain_algo_ind.h:168
const printer_base< Symbol > & symbol_printer() const
Returns a printer for symbols.
Definition: automaton.h:304
unsigned size() const
Returns the size of the antichain.
Definition: antichain.h:132
void initial_states(State_vector &states) const
Returns the initial states.
Definition: automaton.h:167
The antichain algorithm compares two automata for language inclusion module an independence relation...
Definition: antichain_algo_ind.h:67
Automata need to inherit from this class and implement certain methods.
Definition: automaton.h:49
bool bound_hit
Was the bound hit during automata exploration.
Definition: results.h:96
void add(const A &a, const pb_set &b, bool dirty=false)
Add element (a,b) to the antichain.
Definition: antichain.h:92