spot 2.3.4

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

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