spot  2.15.1
utils.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) by the Spot authors, see the AUTHORS file for details.
3 //
4 // This file is part of Spot, a model checking library.
5 //
6 // Spot is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU 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 // Spot is distributed in the hope that it will be useful, but WITHOUT
12 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 // License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19 #pragma once
20 
21 #include <spot/mc/intersect.hh>
22 #include <spot/twa/twa.hh>
23 #include <spot/twacube_algos/convert.hh>
24 
25 namespace spot
26 {
30  template<typename State, typename SuccIterator,
31  typename StateHash, typename StateEqual>
32  class SPOT_API kripkecube_to_twa
33  {
34  public:
35 
36  kripkecube_to_twa(kripkecube<State, SuccIterator>& sys, bdd_dict_ptr dict):
37  sys_(sys), dict_(dict)
38  {
39  static_assert(spot::is_a_kripkecube_ptr<decltype(&sys),
40  State, SuccIterator>::value,
41  "error: does not match the kripkecube requirements");
42  }
43 
45  {
46  visited_.clear();
47  }
48 
49  void run()
50  {
51  setup();
52  State initial = sys_.initial(0);
53  if (SPOT_LIKELY(push(initial, dfs_number_+1)))
54  {
55  visited_[initial] = dfs_number_++;
56  todo_.push_back({initial, sys_.succ(initial, 0)});
57  }
58  while (!todo_.empty())
59  {
60  if (todo_.back().it->done())
61  {
62  if (SPOT_LIKELY(pop(todo_.back().s)))
63  {
64  sys_.recycle(todo_.back().it, 0);
65  todo_.pop_back();
66  }
67  }
68  else
69  {
70  ++transitions_;
71  State dst = todo_.back().it->state();
72  auto it = visited_.find(dst);
73  if (it == visited_.end())
74  {
75  if (SPOT_LIKELY(push(dst, dfs_number_+1)))
76  {
77  visited_[dst] = dfs_number_++;
78  todo_.back().it->next();
79  todo_.push_back({dst, sys_.succ(dst, 0)});
80  }
81  }
82  else
83  {
84  edge(visited_[todo_.back().s], visited_[dst]);
85  todo_.back().it->next();
86  }
87  }
88  }
89  finalize();
90  }
91 
92  void setup()
93  {
94  auto d = spot::make_bdd_dict();
95  res_ = make_twa_graph(d);
96  names_ = new std::vector<std::string>();
97 
98  int i = 0;
99  for (auto ap : sys_.ap())
100  {
101  auto idx = res_->register_ap(ap);
102  reverse_binder_[i++] = idx;
103  }
104  }
105 
106  bool push(State s, unsigned i)
107  {
108 
109  unsigned st = res_->new_state();
110  names_->push_back(sys_.to_string(s));
111  if (!todo_.empty())
112  {
113  edge(visited_[todo_.back().s], st);
114  }
115 
116  SPOT_ASSERT(st+1 == i);
117  return true;
118  }
119 
120  bool pop(State)
121  {
122  return true;
123  }
124 
125  void edge(unsigned src, unsigned dst)
126  {
127  cubeset cs(sys_.ap().size());
128  bdd cond = cube_to_bdd(todo_.back().it->condition(),
129  cs, reverse_binder_);
130  res_->new_edge(src, dst, cond);
131  }
132 
133  void finalize()
134  {
135  res_->purge_unreachable_states();
136  res_->set_named_prop<std::vector<std::string>>("state-names", names_);
137  }
138 
139  twa_graph_ptr twa()
140  {
141  return res_;
142  }
143 
144  protected:
146  {
147  State s;
148  SuccIterator* it;
149  };
150 
151  typedef std::unordered_map<const State, int,
152  StateHash, StateEqual> visited__map;
153 
155  std::vector<todo__element> todo_;
156  visited__map visited_;
157  unsigned int dfs_number_ = 0;
158  unsigned int transitions_ = 0;
159  spot::twa_graph_ptr res_;
160  std::vector<std::string>* names_;
161  bdd_dict_ptr dict_;
162  std::unordered_map<int, int> reverse_binder_;
163  };
164 
168  template<typename State, typename SuccIterator,
169  typename StateHash, typename StateEqual>
170  class SPOT_API product_to_twa
171  {
172  struct product_state
173  {
174  State st_kripke;
175  unsigned st_prop;
176  };
177 
178  struct product_state_equal
179  {
180  bool
181  operator()(const product_state lhs,
182  const product_state rhs) const
183  {
184  StateEqual equal;
185  return (lhs.st_prop == rhs.st_prop) &&
186  equal(lhs.st_kripke, rhs.st_kripke);
187  }
188  };
189 
190  struct product_state_hash
191  {
192  size_t
193  operator()(const product_state lhs) const noexcept
194  {
195  StateHash hash;
196  unsigned u = hash(lhs.st_kripke) % (1<<30);
197  u = wang32_hash(lhs.st_prop) ^ u;
198  u = u % (1<<30);
199  return u;
200  }
201  };
202 
203  public:
205  twacube_ptr twa):
206  sys_(sys), twa_(twa)
207  {
208  static_assert(spot::is_a_kripkecube_ptr<decltype(&sys),
209  State, SuccIterator>::value,
210  "error: does not match the kripkecube requirements");
211  }
212 
213  virtual ~product_to_twa()
214  {
215  map.clear();
216  }
217 
218  bool run()
219  {
220  setup();
221  product_state initial = {sys_.initial(0), twa_->get_initial()};
222  if (SPOT_LIKELY(push_state(initial, dfs_number_+1, {})))
223  {
224  todo_.push_back({initial, sys_.succ(initial.st_kripke, 0),
225  twa_->succ(initial.st_prop)});
226 
227  // Not going further! It's a product with a single state.
228  if (todo_.back().it_prop->done())
229  return false;
230 
231  forward_iterators(sys_, twa_, todo_.back().it_kripke,
232  todo_.back().it_prop, true, 0);
233  map[initial] = ++dfs_number_;
234  }
235  while (!todo_.empty())
236  {
237  // Check the kripke is enough since it's the outer loop. More
238  // details in forward_iterators.
239  if (todo_.back().it_kripke->done())
240  {
241  bool is_init = todo_.size() == 1;
242  auto newtop = is_init? todo_.back().st: todo_[todo_.size() -2].st;
243  if (SPOT_LIKELY(pop_state(todo_.back().st,
244  map[todo_.back().st],
245  is_init,
246  newtop,
247  map[newtop])))
248  {
249  sys_.recycle(todo_.back().it_kripke, 0);
250  todo_.pop_back();
251  }
252  }
253  else
254  {
255  ++transitions_;
256  product_state dst = {
257  todo_.back().it_kripke->state(),
258  twa_->trans_storage(todo_.back().it_prop, 0).dst
259  };
260  auto acc = twa_->trans_data(todo_.back().it_prop, 0).acc_;
261  forward_iterators(sys_, twa_, todo_.back().it_kripke,
262  todo_.back().it_prop, false, 0);
263  auto it = map.find(dst);
264  if (it == map.end())
265  {
266  if (SPOT_LIKELY(push_state(dst, dfs_number_+1, acc)))
267  {
268  map[dst] = ++dfs_number_;
269  todo_.push_back({dst, sys_.succ(dst.st_kripke, 0),
270  twa_->succ(dst.st_prop)});
271  forward_iterators(sys_, twa_, todo_.back().it_kripke,
272  todo_.back().it_prop, true, 0);
273  }
274  }
275  else if (SPOT_UNLIKELY(update(todo_.back().st, dfs_number_,
276  dst, map[dst], acc)))
277  return true;
278  }
279  }
280  return false;
281  }
282 
283  twa_graph_ptr twa()
284  {
285  res_->purge_unreachable_states();
286  res_->set_named_prop<std::vector<std::string>>("state-names", names_);
287  return res_;
288  }
289 
290  void setup()
291  {
292  auto d = spot::make_bdd_dict();
293  res_ = make_twa_graph(d);
294  names_ = new std::vector<std::string>();
295 
296  int i = 0;
297  for (auto ap : sys_.ap())
298  {
299  auto idx = res_->register_ap(ap);
300  reverse_binder_[i++] = idx;
301  }
302  }
303 
304  bool push_state(product_state s, unsigned i, acc_cond::mark_t)
305  {
306  unsigned st = res_->new_state();
307 
308  if (!todo_.empty())
309  {
310  auto c = twa_->get_cubeset()
311  .intersection(twa_->trans_data
312  (todo_.back().it_prop).cube_,
313  todo_.back().it_kripke->condition());
314 
315  bdd x = spot::cube_to_bdd(c, twa_->get_cubeset(),
316  reverse_binder_);
317  twa_->get_cubeset().release(c);
318  res_->new_edge(map[todo_.back().st]-1, st, x,
319  twa_->trans_data
320  (todo_.back().it_prop).acc_);
321  }
322 
323 
324  names_->push_back(sys_.to_string(s.st_kripke) +
325  ('*' + std::to_string(s.st_prop)));
326  SPOT_ASSERT(st+1 == i);
327  return true;
328  }
329 
330  bool update(product_state, unsigned src,
331  product_state, unsigned dst,
332  acc_cond::mark_t cond)
333  {
334  auto c = twa_->get_cubeset()
335  .intersection(twa_->trans_data
336  (todo_.back().it_prop).cube_,
337  todo_.back().it_kripke->condition());
338 
339  bdd x = spot::cube_to_bdd(c, twa_->get_cubeset(),
340  reverse_binder_);
341  twa_->get_cubeset().release(c);
342  res_->new_edge(src-1, dst-1, x, cond);
343  return false;
344  }
345 
346  bool pop_state(product_state, unsigned, bool, product_state, unsigned)
347  {
348  return true;
349  }
350 
351  private:
352  struct todo__element
353  {
354  product_state st;
355  SuccIterator* it_kripke;
356  std::shared_ptr<trans_index> it_prop;
357  };
358 
359  typedef std::unordered_map<const product_state, int,
360  product_state_hash,
361  product_state_equal> visited_map;
362 
364  twacube_ptr twa_;
365  std::vector<todo__element> todo_;
366  visited_map map;
367  unsigned int dfs_number_ = 0;
368  unsigned int transitions_ = 0;
369  spot::twa_graph_ptr res_;
370  std::vector<std::string>* names_;
371  std::unordered_map<int, int> reverse_binder_;
372  };
373 }
Definition: cube.hh:68
This class allows to ensure (at compile time) if a given parameter is of type kripkecube....
Definition: kripke.hh:71
convert a (cube) model into a twa. Note that this algorithm cannot be run in parallel but could.
Definition: utils.hh:33
This class is a template representation of a Kripke structure. It is composed of two template paramet...
Definition: kripke.hh:40
convert a (cube) product automaton into a twa Note that this algorithm cannot be run in parallel.
Definition: utils.hh:171
A Transition-based ω-Automaton.
Definition: twa.hh:619
void set_named_prop(std::string s, void *val, std::function< void(void *)> destructor)
Declare a named property.
size_t wang32_hash(size_t key)
Thomas Wang's 32 bit hash function.
Definition: hashfunc.hh:37
@ ap
Atomic proposition.
twa_graph_ptr make_twa_graph(const bdd_dict_ptr &dict)
Build an explicit automaton from all states of aut,.
Definition: twagraph.hh:786
Definition: automata.hh:26
bdd cube_to_bdd(spot::cube cube, const cubeset &cubeset, std::unordered_map< int, int > &reverse_binder)
Transform a cube cube into bdd using the map that bind cube indexes to bdd indexes.
An acceptance mark.
Definition: acc.hh:84

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Fri Feb 27 2015 10:00:07 for spot by doxygen 1.9.1