spot 2.3

- Main Page
- Related Pages
- Modules
- Classes
- Files

- File List

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
twagraph.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2014, 2015, 2016 Laboratoire de Recherche et Développement
3 // 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/twa/fwd.hh>
23 #include <spot/graph/graph.hh>
24 #include <spot/graph/ngraph.hh>
25 #include <spot/twa/bdddict.hh>
26 #include <spot/twa/twa.hh>
27 #include <spot/twaalgos/copy.hh>
28 #include <spot/tl/formula.hh>
29 #include <sstream>
30
31 namespace spot
32 {
33
34 struct SPOT_API twa_graph_state: public spot::state
35 {
36 public:
37 twa_graph_state() noexcept
38 {
39 }
40
41 virtual ~twa_graph_state() noexcept
42 {
43 }
44
45 virtual int compare(const spot::state* other) const override
46 {
47 auto o = down_cast<const twa_graph_state*>(other);
48 SPOT_ASSERT(o);
49
50 // Do not simply return "other - this", it might not fit in an int.
51 if (o < this)
52 return -1;
53 if (o > this)
54 return 1;
55 return 0;
56 }
57
58 virtual size_t hash() const override
59 {
60 return
61 reinterpret_cast<const char*>(this) - static_cast<const char*>(nullptr);
62 }
63
64 virtual twa_graph_state*
65 clone() const override
66 {
67 return const_cast<twa_graph_state*>(this);
68 }
69
70 virtual void destroy() const override
71 {
72 }
73 };
74
75 struct SPOT_API twa_graph_edge_data
76 {
77 bdd cond;
78 acc_cond::mark_t acc;
79
80 explicit twa_graph_edge_data() noexcept
81 : cond(bddfalse), acc(0)
82 {
83 }
84
85 twa_graph_edge_data(bdd cond, acc_cond::mark_t acc = 0U) noexcept
86 : cond(cond), acc(acc)
87 {
88 }
89
90 bool operator<(const twa_graph_edge_data& other) const
91 {
92 if (cond.id() < other.cond.id())
93 return true;
94 if (cond.id() > other.cond.id())
95 return false;
96 return acc < other.acc;
97 }
98
99 bool operator==(const twa_graph_edge_data& other) const
100 {
101 return cond.id() == other.cond.id() &&
102 acc == other.acc;
103 }
104 };
105
106
107 template<class Graph>
108 class SPOT_API twa_graph_succ_iterator final:
109 public twa_succ_iterator
110 {
111 private:
112 typedef typename Graph::edge edge;
113 typedef typename Graph::state_data_t state;
114 const Graph* g_;
115 edge t_;
116 edge p_;
117
118 public:
119 twa_graph_succ_iterator(const Graph* g, edge t)
120 : g_(g), t_(t)
121 {
122 }
123
124 void recycle(edge t)
125 {
126 t_ = t;
127 }
128
129 virtual bool first() override
130 {
131 p_ = t_;
132 return p_;
133 }
134
135 virtual bool next() override
136 {
137 p_ = g_->edge_storage(p_).next_succ;
138 return p_;
139 }
140
141 virtual bool done() const override
142 {
143 return !p_;
144 }
145
146 virtual const twa_graph_state* dst() const override
147 {
148 SPOT_ASSERT(!done());
149 return &g_->state_data(g_->edge_storage(p_).dst);
150 }
151
152 virtual bdd cond() const override
153 {
154 SPOT_ASSERT(!done());
155 return g_->edge_data(p_).cond;
156 }
157
158 virtual acc_cond::mark_t acc() const override
159 {
160 SPOT_ASSERT(!done());
161 return g_->edge_data(p_).acc;
162 }
163
164 edge pos() const
165 {
166 return p_;
167 }
168
169 };
170
171 class SPOT_API twa_graph final: public twa
172 {
173 public:
174 typedef digraph<twa_graph_state, twa_graph_edge_data> graph_t;
175 // We avoid using graph_t::edge_storage_t because graph_t is not
176 // instantiated in the SWIG bindings, and SWIG would therefore
177 // handle graph_t::edge_storage_t as an abstract type.
178 typedef spot::internal::edge_storage<unsigned, unsigned, unsigned,
179 internal::boxed_label
180 <twa_graph_edge_data, false>>
181 edge_storage_t;
182 static_assert(std::is_same<typename graph_t::edge_storage_t,
183 edge_storage_t>::value, "type mismatch");
184 // We avoid using graph_t::state for the very same reason.
185 typedef unsigned state_num;
186 static_assert(std::is_same<typename graph_t::state, state_num>::value,
187 "type mismatch");
188
189 protected:
190 graph_t g_;
191 mutable unsigned init_number_;
192
193 public:
194 twa_graph(const bdd_dict_ptr& dict)
195 : twa(dict),
196 init_number_(0)
197 {
198 }
199
200 explicit twa_graph(const const_twa_graph_ptr& other, prop_set p)
201 : twa(other->get_dict()),
202 g_(other->g_), init_number_(other->init_number_)
203 {
204 copy_acceptance_of(other);
205 copy_ap_of(other);
206 prop_copy(other, p);
207 }
208
209 virtual ~twa_graph()
210 {
211 }
212
213 #ifndef SWIG
214 template <typename State_Name,
215 typename Name_Hash = std::hash<State_Name>,
216 typename Name_Equal = std::equal_to<State_Name>>
217 using namer = named_graph<graph_t, State_Name, Name_Hash, Name_Equal>;
218
219 template <typename State_Name,
220 typename Name_Hash = std::hash<State_Name>,
221 typename Name_Equal = std::equal_to<State_Name>>
222 namer<State_Name, Name_Hash, Name_Equal>*
223 create_namer()
224 {
225 return new named_graph<graph_t, State_Name, Name_Hash, Name_Equal>(g_);
226 }
227
228 namer<formula>*
229 create_formula_namer()
230 {
231 return create_namer<formula>();
232 }
233
234 void
235 release_formula_namer(namer<formula>* namer, bool keep_names);
236 #endif
237
238 graph_t& get_graph()
239 {
240 return g_;
241 }
242
243 const graph_t& get_graph() const
244 {
245 return g_;
246 }
247
248 unsigned num_states() const
249 {
250 return g_.num_states();
251 }
252
253 unsigned num_edges() const
254 {
255 return g_.num_edges();
256 }
257
258 void set_init_state(state_num s)
259 {
260 if (SPOT_UNLIKELY(s >= num_states()))
261 throw std::invalid_argument
262 ("set_init_state() called with nonexisiting state");
263 init_number_ = s;
264 }
265
266 void set_init_state(const state* s)
267 {
268 set_init_state(state_number(s));
269 }
270
271 template<class I>
272 void set_univ_init_state(I dst_begin, I dst_end)
273 {
274 auto ns = num_states();
275 for (I i = dst_begin; i != dst_end; ++i)
276 if (SPOT_UNLIKELY(*i >= ns))
277 throw std::invalid_argument
278 ("set_univ_init_state() called with nonexisiting state");
279 init_number_ = g_.new_univ_dests(dst_begin, dst_end);
280 }
281
282 template<class I>
283 void set_univ_init_state(const std::initializer_list<state_num>& il)
284 {
285 set_univ_init_state(il.begin(), il.end());
286 }
287
288 state_num get_init_state_number() const
289 {
290 // If the automaton has no state, it has no initial state.
291 if (num_states() == 0)
292 throw std::runtime_error("automaton has no state at all");
293 return init_number_;
294 }
295
296 virtual const twa_graph_state* get_init_state() const override
297 {
298 unsigned n = get_init_state_number();
299 if (SPOT_UNLIKELY(is_alternating()))
300 throw std::runtime_error
301 ("the abstract interface does not support alternating automata");
302 return state_from_number(n);
303 }
304
305 virtual twa_succ_iterator*
306 succ_iter(const state* st) const override
307 {
308 auto s = down_cast<const typename graph_t::state_storage_t*>(st);
309 SPOT_ASSERT(s);
310 SPOT_ASSERT(!s->succ || g_.is_valid_edge(s->succ));
311
312 if (this->iter_cache_)
313 {
314 auto it =
315 down_cast<twa_graph_succ_iterator<graph_t>*>(this->iter_cache_);
316 it->recycle(s->succ);
317 this->iter_cache_ = nullptr;
318 return it;
319 }
320 return new twa_graph_succ_iterator<graph_t>(&g_, s->succ);
321 }
322
323 static constexpr bool is_univ_dest(const edge_storage_t& e)
324 {
325 return is_univ_dest(e.dst);
326 }
327
328 static constexpr bool is_univ_dest(unsigned s)
329 {
330 // Universal destinations are stored with their most-significant
331 // bit set.
332 return (int) s < 0;
333 }
334
335 state_num
336 state_number(const state* st) const
337 {
338 auto s = down_cast<const typename graph_t::state_storage_t*>(st);
339 SPOT_ASSERT(s);
340 return s - &g_.state_storage(0);
341 }
342
343 const twa_graph_state*
344 state_from_number(state_num n) const
345 {
346 return &g_.state_data(n);
347 }
348
349 std::string format_state(unsigned n) const
350 {
351 std::stringstream ss;
352 if (is_univ_dest(n))
353 {
354 bool notfirst = false;
355 for (unsigned d: univ_dests(n))
356 {
357 if (notfirst)
358 ss << '&';
359 notfirst = true;
360 ss << d;
361 }
362 }
363 else
364 {
365 ss << n;
366 }
367 return ss.str();
368 }
369
370 virtual std::string format_state(const state* st) const override
371 {
372 return format_state(state_number(st));
373 }
374
375 unsigned edge_number(const twa_succ_iterator* it) const
376 {
377 auto* i = down_cast<const twa_graph_succ_iterator<graph_t>*>(it);
378 return i->pos();
379 }
380
381 twa_graph_edge_data& edge_data(const twa_succ_iterator* it)
382 {
383 return g_.edge_data(edge_number(it));
384 }
385
386 twa_graph_edge_data& edge_data(unsigned t)
387 {
388 return g_.edge_data(t);
389 }
390
391 const twa_graph_edge_data& edge_data(const twa_succ_iterator* it) const
392 {
393 return g_.edge_data(edge_number(it));
394 }
395
396 const twa_graph_edge_data& edge_data(unsigned t) const
397 {
398 return g_.edge_data(t);
399 }
400
401 edge_storage_t& edge_storage(const twa_succ_iterator* it)
402 {
403 return g_.edge_storage(edge_number(it));
404 }
405
406 edge_storage_t& edge_storage(unsigned t)
407 {
408 return g_.edge_storage(t);
409 }
410
411 const edge_storage_t
412 edge_storage(const twa_succ_iterator* it) const
413 {
414 return g_.edge_storage(edge_number(it));
415 }
416
417 const edge_storage_t edge_storage(unsigned t) const
418 {
419 return g_.edge_storage(t);
420 }
421
422 unsigned new_state()
423 {
424 return g_.new_state();
425 }
426
427 unsigned new_states(unsigned n)
428 {
429 return g_.new_states(n);
430 }
431
432 unsigned new_edge(unsigned src, unsigned dst,
433 bdd cond, acc_cond::mark_t acc = 0U)
434 {
435 return g_.new_edge(src, dst, cond, acc);
436 }
437
438 unsigned new_acc_edge(unsigned src, unsigned dst,
439 bdd cond, bool acc = true)
440 {
441 if (acc)
442 return g_.new_edge(src, dst, cond, this->acc().all_sets());
443 else
444 return g_.new_edge(src, dst, cond);
445 }
446
447 template<class I>
448 unsigned new_univ_edge(unsigned src, I begin, I end,
449 bdd cond, acc_cond::mark_t acc = 0U)
450 {
451 return g_.new_univ_edge(src, begin, end, cond, acc);
452 }
453
454 unsigned new_univ_edge(unsigned src, std::initializer_list<unsigned> dst,
455 bdd cond, acc_cond::mark_t acc = 0U)
456 {
457 return g_.new_univ_edge(src, dst.begin(), dst.end(), cond, acc);
458 }
459
460 #ifndef SWIG
461 internal::state_out<const graph_t>
462 out(unsigned src) const
463 {
464 return g_.out(src);
465 }
466 #endif
467
468 internal::state_out<graph_t>
469 out(unsigned src)
470 {
471 return g_.out(src);
472 }
473
474 internal::const_universal_dests
475 univ_dests(unsigned d) const noexcept
476 {
477 return g_.univ_dests(d);
478 }
479
480 internal::const_universal_dests
481 univ_dests(const edge_storage_t& e) const noexcept
482 {
483 return g_.univ_dests(e);
484 }
485
486 bool is_alternating() const
487 {
488 return g_.is_alternating();
489 }
490
491 #ifndef SWIG
492 auto states() const
493 SPOT_RETURN(g_.states());
494 auto states()
495 SPOT_RETURN(g_.states());
496
497 internal::all_trans<const graph_t>
498 edges() const noexcept
499 {
500 return g_.edges();
501 }
502 #endif
503
504 internal::all_trans<graph_t>
505 edges() noexcept
506 {
507 return g_.edges();
508 }
509
510 #ifndef SWIG
511 auto edge_vector() const
512 SPOT_RETURN(g_.edge_vector());
513 auto edge_vector()
514 SPOT_RETURN(g_.edge_vector());
515
516 auto is_dead_edge(const graph_t::edge_storage_t& t) const
517 SPOT_RETURN(g_.is_dead_edge(t));
518 #endif
519
522 void merge_edges();
523
527 void merge_univ_dests();
528
537 void purge_dead_states();
538
550 void purge_unreachable_states();
551
556 void remove_unused_ap();
557
558 acc_cond::mark_t state_acc_sets(unsigned s) const
559 {
560 if (SPOT_UNLIKELY(!(bool)prop_state_acc()))
561 throw std::runtime_error
562 ("state_acc_sets() should only be called on "
563 "automata with state-based acceptance");
564 for (auto& t: g_.out(s))
565 // Stop at the first edge, since the remaining should be
566 // labeled identically.
567 return t.acc;
568 return 0U;
569 }
570
571 bool state_is_accepting(unsigned s) const
572 {
573 if (SPOT_UNLIKELY(!(bool)prop_state_acc()))
574 throw std::runtime_error
575 ("state_is_accepting() should only be called on "
576 "automata with state-based acceptance");
577 for (auto& t: g_.out(s))
578 // Stop at the first edge, since the remaining should be
579 // labeled identically.
580 return acc().accepting(t.acc);
581 return false;
582 }
583
584 bool state_is_accepting(const state* s) const
585 {
586 return state_is_accepting(state_number(s));
587 }
588
589 bool operator==(const twa_graph& aut) const
590 {
591 auto& dests1 = g_.dests_vector();
592 auto& dests2 = aut.get_graph().dests_vector();
593 if (num_states() != aut.num_states() ||
594 num_edges() != aut.num_edges() ||
595 num_sets() != aut.num_sets() ||
596 dests1.size() != dests2.size())
597 return false;
598 auto& trans1 = edge_vector();
599 auto& trans2 = aut.edge_vector();
600 if (!std::equal(trans1.begin() + 1, trans1.end(),
601 trans2.begin() + 1))
602 return false;
603 return std::equal(dests1.begin(), dests1.end(),
604 dests2.begin());
605 }
606
607 void defrag_states(std::vector<unsigned>&& newst, unsigned used_states);
608 };
609
610 inline twa_graph_ptr make_twa_graph(const bdd_dict_ptr& dict)
611 {
612 return std::make_shared<twa_graph>(dict);
613 }
614
615 inline twa_graph_ptr make_twa_graph(const twa_graph_ptr& aut,
616 twa::prop_set p)
617 {
618 return std::make_shared<twa_graph>(aut, p);
619 }
620
621 inline twa_graph_ptr make_twa_graph(const const_twa_graph_ptr& aut,
622 twa::prop_set p)
623 {
624 return std::make_shared<twa_graph>(aut, p);
625 }
626
627 inline twa_graph_ptr make_twa_graph(const const_twa_ptr& aut,
628 twa::prop_set p)
629 {
630 auto a = std::dynamic_pointer_cast<const twa_graph>(aut);
631 if (a)
632 return std::make_shared<twa_graph>(a, p);
633 else
634 return copy(aut, p);
635 }
636 }
spot
Definition: graph.hh:33
spot::internal::boxed_label
Definition: graph.hh:62
spot::digraph::state_storage
state_storage_t & state_storage(state s)
return a reference to the storage of a state
Definition: graph.hh:700
spot::twa_graph_state::destroy
virtual void destroy() const override
Release a state.
Definition: twagraph.hh:70
spot::digraph::is_dead_edge
bool is_dead_edge(unsigned t) const
Tests whether an edge has been erased.
Definition: graph.hh:982
spot::digraph::state_data
state_storage_t::data_t & state_data(state s)
return the State_Data associated to a state
Definition: graph.hh:718
spot::internal::const_universal_dests
Definition: graph.hh:524
spot::digraph::new_states
state new_states(unsigned n, Args &&...args)
Create n new states.
Definition: graph.hh:685
spot::twa
A Transition-based ω-Automaton.
Definition: twa.hh:622
formula.hh
LTL/PSL formula interface.
spot::digraph::edge_storage
edge_storage_t & edge_storage(edge s)
return a reference to the storage of an edge
Definition: graph.hh:736
spot::digraph::new_univ_dests
state new_univ_dests(I dst_begin, I dst_end)
Create a new universal destination group.
Definition: graph.hh:797
spot::state
Abstract class for states.
Definition: twa.hh:50
spot::digraph::num_edges
unsigned num_edges() const
The number of edges in the automaton.
Definition: graph.hh:654
spot::twa_graph_state::hash
virtual size_t hash() const override
Hash a state.
Definition: twagraph.hh:58
spot::internal::edge_storage
Definition: graph.hh:184
spot::digraph::dests_vector
const dests_vector_t & dests_vector() const
The vector used to store universal destinations.
Definition: graph.hh:998
spot::named_graph
Definition: ngraph.hh:32
spot::op::U
until
spot::digraph::states
const state_vector & states() const
Return the vector of states.
Definition: graph.hh:919
spot::internal::distate_storage
Definition: graph.hh:159
spot::copy
twa_graph_ptr copy(const const_twa_ptr &aut, twa::prop_set p, bool preserve_names=false, unsigned max_states=-1U)
Build an explicit automaton from all states of aut,.
spot::twa_graph_succ_iterator::first
virtual bool first() override
Position the iterator on the first successor (if any).
Definition: twagraph.hh:129
spot::digraph::edge_data
edge_storage_t::data_t & edge_data(edge s)
return the Edgeg_Data of an edge.
Definition: graph.hh:754
spot::twa_succ_iterator
Iterate over the successors of a state.
Definition: twa.hh:397
spot::internal::all_trans
Definition: graph.hh:496
spot::digraph::out
internal::state_out< digraph > out(state src)
Return a fake container with all edges leaving src.
Definition: graph.hh:875
spot::twa_graph_succ_iterator::cond
virtual bdd cond() const override
Get the condition on the edge leading to this successor.
Definition: twagraph.hh:152
spot::digraph::edge_vector
const edge_vector_t & edge_vector() const
Return the vector of all edges.
Definition: graph.hh:953
spot::digraph::new_edge
edge new_edge(state src, state dst, Args &&...args)
Create a new edge.
Definition: graph.hh:773
spot::twa_graph_succ_iterator::done
virtual bool done() const override
Check whether the iteration is finished.
Definition: twagraph.hh:141
spot::twa_graph_state::compare
virtual int compare(const spot::state *other) const override
Compares two states (that come from the same automaton).
Definition: twagraph.hh:45
spot::twa_graph_succ_iterator::dst
virtual const twa_graph_state * dst() const override
Get the destination state of the current edge.
Definition: twagraph.hh:146
spot::twa::num_sets
unsigned num_sets() const
Number of acceptance sets used by the automaton.
Definition: twa.hh:906
spot::twa_graph_succ_iterator::acc
virtual acc_cond::mark_t acc() const override
Get the acceptance mark of the edge leading to this successor.
Definition: twagraph.hh:158
spot::digraph::is_valid_edge
bool is_valid_edge(edge t) const
Test whether the given edge is valid.
Definition: graph.hh:970
spot::twa_graph_succ_iterator
Definition: twagraph.hh:108
spot::digraph
A directed graph.
Definition: graph.hh:36
spot::digraph::new_univ_edge
edge new_univ_edge(state src, I dst_begin, I dst_end, Args &&...args)
Create a new universal edge.
Definition: graph.hh:817
spot::digraph::is_alternating
bool is_alternating() const
Whether the automaton is alternating.
Definition: graph.hh:660
spot::internal::state_out
Definition: graph.hh:385
spot::twa_graph
Definition: twagraph.hh:171
spot::twa_graph_state
Definition: twagraph.hh:34
spot::digraph::new_state
state new_state(Args &&...args)
Create a new states.
Definition: graph.hh:671
spot::twa_graph_succ_iterator::next
virtual bool next() override
Jump to the next successor (if any).
Definition: twagraph.hh:135
spot::digraph::num_states
unsigned num_states() const
The number of states in the automaton.
Definition: graph.hh:646
spot::digraph::edges
internal::all_trans< const digraph > edges() const
Return a fake container with all edges (exluding erased edges)
Definition: graph.hh:934
spot::acc_cond::mark_t
Definition: acc.hh:34
spot::twa_graph_edge_data
Definition: twagraph.hh:75
spot::twa_graph_state::clone
virtual twa_graph_state * clone() const override
Duplicate a state.
Definition: twagraph.hh:65

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.