spot 2.15
Loading...
Searching...
No Matches
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
25namespace spot
26{
30 template<typename State, typename SuccIterator,
31 typename StateHash, typename StateEqual>
32 class SPOT_API kripkecube_to_twa
33 {
34 public:
35
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.8