spot  2.3.3.dev
intersect.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2015, 2016 Laboratoire de Recherche et
3 // Developpement de l'Epita
4 //
5 // This file is part of Spot, a model checking library.
6 //
7 // Spot is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // Spot is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 
20 #pragma once
21 
22 #include <spot/kripke/kripke.hh>
23 #include <spot/twacube/twacube.hh>
24 #include <queue>
25 
26 namespace spot
27 {
30  struct SPOT_API istats
31  {
32  unsigned states;
33  unsigned transitions;
34  unsigned sccs;
35  unsigned instack_sccs;
36  unsigned instack_item;
37  bool is_empty;
38  };
39 
56  template<typename State, typename SuccIterator,
57  typename StateHash, typename StateEqual,
58  typename EmptinessCheck>
59  class SPOT_API intersect
60  {
61  public:
63  twacube_ptr twa, unsigned tid, bool& stop):
64  sys_(sys), twa_(twa), tid_(tid), stop_(stop)
65  {
66  SPOT_ASSERT(is_a_kripkecube(sys));
67  map.reserve(2000000);
68  todo.reserve(100000);
69  }
70 
71  ~intersect()
72  {
73  map.clear();
74  }
75 
80  EmptinessCheck& self()
81  {
82  return static_cast<EmptinessCheck&>(*this);
83  }
84 
88  bool run()
89  {
90  self().setup();
91  product_state initial = {sys_.initial(tid_), twa_->get_initial()};
92  if (SPOT_LIKELY(self().push_state(initial, dfs_number+1, 0U)))
93  {
94  todo.push_back({initial, sys_.succ(initial.st_kripke, tid_),
95  twa_->succ(initial.st_prop)});
96 
97  // Not going further! It's a product with a single state.
98  if (todo.back().it_prop->done())
99  return false;
100 
101  forward_iterators(true);
102  map[initial] = ++dfs_number;
103  }
104  while (!todo.empty() && !stop_)
105  {
106  // Check the kripke is enough since it's the outer loop. More
107  // details in forward_iterators.
108  if (todo.back().it_kripke->done())
109  {
110  bool is_init = todo.size() == 1;
111  auto newtop = is_init? todo.back().st: todo[todo.size() -2].st;
112  if (SPOT_LIKELY(self().pop_state(todo.back().st,
113  map[todo.back().st],
114  is_init,
115  newtop,
116  map[newtop])))
117  {
118  sys_.recycle(todo.back().it_kripke, tid_);
119  // FIXME a local storage for twacube iterator?
120  todo.pop_back();
121  if (SPOT_UNLIKELY(self().counterexample_found()))
122  return true;
123  }
124  }
125  else
126  {
127  ++transitions;
128  product_state dst = {
129  todo.back().it_kripke->state(),
130  twa_->trans_storage(todo.back().it_prop, tid_).dst
131  };
132  auto acc = twa_->trans_data(todo.back().it_prop, tid_).acc_;
133  forward_iterators(false);
134  auto it = map.find(dst);
135  if (it == map.end())
136  {
137  if (SPOT_LIKELY(self().push_state(dst, dfs_number+1, acc)))
138  {
139  map[dst] = ++dfs_number;
140  todo.push_back({dst, sys_.succ(dst.st_kripke, tid_),
141  twa_->succ(dst.st_prop)});
142  forward_iterators(true);
143  }
144  }
145  else if (SPOT_UNLIKELY(self().update(todo.back().st,
146  dfs_number,
147  dst, map[dst], acc)))
148  return true;
149  }
150  }
151  return false;
152  }
153 
154  unsigned int states()
155  {
156  return dfs_number;
157  }
158 
159  unsigned int trans()
160  {
161  return transitions;
162  }
163 
164  std::string counterexample()
165  {
166  return self().trace();
167  }
168 
169  virtual istats stats()
170  {
171  return {dfs_number, transitions, 0U, 0U, 0U, false};
172  }
173 
174  protected:
175 
180  void forward_iterators(bool just_pushed)
181  {
182  SPOT_ASSERT(!todo.empty());
183  SPOT_ASSERT(!(todo.back().it_prop->done() &&
184  todo.back().it_kripke->done()));
185 
186  // Sometimes kripke state may have no successors.
187  if (todo.back().it_kripke->done())
188  return;
189 
190  // The state has just been push and the 2 iterators intersect.
191  // There is no need to move iterators forward.
192  SPOT_ASSERT(!(todo.back().it_prop->done()));
193  if (just_pushed && twa_->get_cubeset()
194  .intersect(twa_->trans_data(todo.back().it_prop, tid_).cube_,
195  todo.back().it_kripke->condition()))
196  return;
197 
198  // Otherwise we have to compute the next valid successor (if it exits).
199  // This requires two loops. The most inner one is for the twacube since
200  // its costless
201  if (todo.back().it_prop->done())
202  todo.back().it_prop->reset();
203  else
204  todo.back().it_prop->next();
205 
206  while (!todo.back().it_kripke->done())
207  {
208  while (!todo.back().it_prop->done())
209  {
210  if (SPOT_UNLIKELY(twa_->get_cubeset()
211  .intersect(twa_->trans_data(todo.back().it_prop, tid_).cube_,
212  todo.back().it_kripke->condition())))
213  return;
214  todo.back().it_prop->next();
215  }
216  todo.back().it_prop->reset();
217  todo.back().it_kripke->next();
218  }
219  }
220 
221  public:
223  {
224  State st_kripke;
225  unsigned st_prop;
226  };
227 
229  {
230  bool
231  operator()(const product_state lhs,
232  const product_state rhs) const
233  {
234  StateEqual equal;
235  return (lhs.st_prop == rhs.st_prop) &&
236  equal(lhs.st_kripke, rhs.st_kripke);
237  }
238  };
239 
241  {
242  size_t
243  operator()(const product_state that) const
244  {
245  // FIXME! wang32_hash(that.st_prop) could have
246  // been pre-calculated!
247  StateHash hasher;
248  return wang32_hash(that.st_prop) ^ hasher(that.st_kripke);
249  }
250  };
251 
253  {
254  product_state st;
255  SuccIterator* it_kripke;
256  std::shared_ptr<trans_index> it_prop;
257  };
259  twacube_ptr twa_;
260  std::vector<todo_element> todo;
261  typedef std::unordered_map<const product_state, int,
263  product_state_equal> visited_map;
264  visited_map map;
265  unsigned int dfs_number = 0;
266  unsigned int transitions = 0;
267  unsigned tid_;
268  bool& stop_; // Do not need to be atomic.
269  };
270 }
Definition: graph.hh:33
size_t wang32_hash(size_t key)
Thomas Wang&#39;s 32 bit hash function.
Definition: hashfunc.hh:40
A Transition-based ω-Automaton.
Definition: twa.hh:622
This class explores (with a DFS) a product between a system and a twa. This exploration is performed ...
Definition: intersect.hh:59
bool is_a_kripkecube(kripkecube< State, SuccIter > &)
This method allows to ensure (at compile time) if a given parameter is of type kripkecube. It also check if the iterator has the good interface.
Definition: kripke.hh:63
This class is a template representation of a Kripke structure. It is composed of two template paramet...
Definition: kripke.hh:37
Wrapper to accumulate results from intersection and emptiness checks.
Definition: intersect.hh:30
Definition: intersect.hh:252
Definition: intersect.hh:240
void forward_iterators(bool just_pushed)
Find the first couple of iterator (from the top of the todo stack) that intersect. The parameter indicates wheter the state has just been pushed since the underlying job is slightly different.
Definition: intersect.hh:180
bool run()
The main function that will perform the product on-the-fly and call the emptiness check when necessar...
Definition: intersect.hh:88
Definition: intersect.hh:228
Definition: intersect.hh:222

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Tue Apr 18 2017 14:42:56 for spot by doxygen 1.8.13