Limi
antichain_algo.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_H
21 #define LIMI_ANTICHAINALGO_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 
40 namespace Limi {
41 
55 template <class ImplementationA, class ImplementationB>
57 {
58  using StateA = typename ImplementationA::State_;
59  using Symbol = typename ImplementationA::Symbol_;
60  using StateB = typename ImplementationB::State_;
61 
62  using StateA_vector = std::vector<StateA>;
63  using StateB_set = std::unordered_set<StateB>;
64  using StateBI_set = std::shared_ptr<const StateB_set>;
65  using Symbol_set = std::unordered_set<Symbol>;
66  using Symbol_vector = std::vector<Symbol>;
69 
71  using pcounter_chain = std::shared_ptr<counter_chain>;
72 
73  struct pair {
74  StateA a;
75  StateBI_set b;
76  Symbol_set sleep_set;
77  pair(StateA a, StateBI_set b) : a(a), b(b), cex_chain(nullptr) {}
78  pair(StateA a, StateBI_set b, const pcounter_chain& parent, const Symbol& sym) : pair(a,b)
79  {
80  cex_chain = std::make_shared<counter_chain>(sym, parent);
81  }
82  pcounter_chain cex_chain;
83  };
84 
86 
87  std::deque<pair> initial_states(const AutomatonA& a, const AutomatonB& b) {
88  std::shared_ptr<StateB_set> states_b = std::make_shared<StateB_set>();
89  b.initial_states(*states_b);
90  std::deque< pair > result;
91  for(StateA state_a : a.initial_states()) {
92  pair p(state_a, states_b);
93  result.push_back(p);
94  antichain.add_unchecked(state_a, states_b, false);
95  }
96  return result;
97  }
98 
99  const AutomatonA& a;
100  const AutomatonB& b;
101  pair_antichain antichain;
102 
103  std::deque<pair> frontier = initial_states(a,b);
104 
105 public:
106 
114  antichain_algo(const AutomatonA& a, const AutomatonB& b) :
115  a(a), b(b) {
116  if (!b.collapse_epsilon && !b.no_epsilon_produced) {
117  throw std::logic_error("For the automaton B in the language inclusion algorithm either collapse_epsilon must be true or no_epsilon_produced");
118  }
119  }
120 
121 
130  {
132  result.included = true;
133  result.bound_hit = false;
134 
135 #ifdef DEBUG_PRINTING
136  unsigned loop_counter = 0;
137  unsigned transitions = 0;
138 #endif
139  while (frontier.size() > 0) {
140 #ifdef DEBUG_PRINTING
141  if (DEBUG_PRINTING>=2 && loop_counter % 1000 == 0) std::cout << loop_counter << " rounds; A states: " << antichain.size() << std::endl;
142 #endif
143  pair current = frontier.front();
144  frontier.pop_front();
145 
146  Symbol_vector next_symbols;
147  a.next_symbols(current.a, next_symbols);
148 
149 #ifdef DEBUG_PRINTING
150  ++ loop_counter;
151 #endif
152  if ((a.is_final_state(current.a) && !b.is_final_state(*current.b))) {
153  result.counter_example = current.cex_chain->to_vector();
154  result.included = false;
155  break;
156  }
157 
158 #ifdef DEBUG_PRINTING
159  if (DEBUG_PRINTING>=3) {
160  std::cout << "Next pair: ";
161  std::cout << a.state_printer()(current.a) << " - ";
162  internal::print_set(*current.b, std::cout, b.state_printer());
163  std::cout << std::endl;
164  }
165 #endif
166 
167  for (Symbol sigma : next_symbols) {
168 #ifdef DEBUG_PRINTING
169  ++transitions;
170  if (DEBUG_PRINTING>=4) {
171  std::cout << "Symbol: ";
172  std::cout << a.symbol_printer()(sigma);
173  std::cout << std::endl;
174  }
175 #endif
176  StateA_vector states_a = a.successors(current.a, sigma);
177  StateBI_set unpruned;
178  StateBI_set states_b;
179  if (a.is_epsilon(sigma)) states_b=current.b; else {
180  auto states_b1 = std::make_shared<StateB_set>();
181  b.successors(*current.b, sigma, *states_b1);
182  states_b = states_b1;
183  }
184 
185  Symbol_set next_sleep_set(current.sleep_set);
186  // sort out the non-independent ones
187 
188  for (StateA state_a : states_a) {
189  antichain_algo::pair next(state_a, states_b, current.cex_chain, sigma);
190 
191  if (!antichain.contains(next.a, next.b)) {
192  antichain.add(next.a, next.b, false);
193 
194  frontier.push_front(std::move(next));
195  }
196  }
197 
198  current.sleep_set.insert(sigma);
199  }
200 
201  }
202 
203 #ifdef DEBUG_PRINTING
204  if (DEBUG_PRINTING>=1) std::cout << loop_counter << " rounds; seen states: " << antichain.size() << "; transitions: " << transitions << std::endl;
205 
206  if (DEBUG_PRINTING >= 4) {
207  antichain.print(std::cout, a.state_printer(), b.state_printer());
208  }
209 #endif
210 
211  return result;
212  }
213 
214 };
215 
216 
217 }
218 
219 #endif // LIMI_ANTICHAINALGO_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
antichain_algo(const AutomatonA &a, const AutomatonB &b)
Constructor that initialises the language inclusion algorithm.
Definition: antichain_algo.h:114
The result of the language inclusion test.
Definition: results.h:78
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
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.h:129
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
bool no_epsilon_produced
Indicates that the implementation of next_symbols(const State&,Symbol_set&) const will never produce ...
Definition: automaton.h:350
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
bool collapse_epsilon
If true during exploration of the next state the epsilons will be fully explored. If false then epsil...
Definition: automaton.h:344
The classic antichain algorithm compares two automata for language inclusion (no independence relatio...
Definition: antichain_algo.h:56
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