spot 2.3.3

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

- File List

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
graph.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2014, 2015, 2016, 2017 Laboratoire de Recherche et
3 // Développement 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/misc/common.hh>
23 #include <vector>
24 #include <type_traits>
25 #include <tuple>
26 #include <cassert>
27 #include <iterator>
28 #include <algorithm>
29 #include <map>
30 #include <iostream>
31 #include <type_traits>
32
33 namespace spot
34 {
35 template <typename State_Data, typename Edge_Data>
36 class SPOT_API digraph;
37
38 namespace internal
39 {
40 #ifndef SWIG
41 template <typename Of, typename ...Args>
42 struct first_is_base_of
43 {
44 static const bool value = false;
45 };
46
47 template <typename Of, typename Arg1, typename ...Args>
48 struct first_is_base_of<Of, Arg1, Args...>
49 {
50 static const bool value =
51 std::is_base_of<Of, typename std::decay<Arg1>::type>::value;
52 };
53 #endif
54
55 // The boxed_label class stores Data as an attribute called
56 // "label" if boxed is true. It is an empty class if Data is
57 // void, and it simply inherits from Data if boxed is false.
58 //
59 // The data() method offers an homogeneous access to the Data
60 // instance.
61 template <typename Data, bool boxed = !std::is_class<Data>::value>
62 struct SPOT_API boxed_label
63 {
64 typedef Data data_t;
65 Data label;
66
67 #ifndef SWIG
68 template <typename... Args,
69 typename = typename std::enable_if<
70 !first_is_base_of<boxed_label, Args...>::value>::type>
71 boxed_label(Args&&... args)
72 noexcept(std::is_nothrow_constructible<Data, Args...>::value)
73 : label{std::forward<Args>(args)...}
74 {
75 }
76 #endif
77
78 // if Data is a POD type, G++ 4.8.2 wants default values for all
79 // label fields unless we define this default constructor here.
80 explicit boxed_label()
81 noexcept(std::is_nothrow_constructible<Data>::value)
82 {
83 }
84
85 Data& data()
86 {
87 return label;
88 }
89
90 const Data& data() const
91 {
92 return label;
93 }
94
95 bool operator<(const boxed_label& other) const
96 {
97 return label < other.label;
98 }
99 };
100
101 template <>
102 struct SPOT_API boxed_label<void, true>: public std::tuple<>
103 {
104 typedef std::tuple<> data_t;
105 std::tuple<>& data()
106 {
107 return *this;
108 }
109
110 const std::tuple<>& data() const
111 {
112 return *this;
113 }
114
115 };
116
117 template <typename Data>
118 struct SPOT_API boxed_label<Data, false>: public Data
119 {
120 typedef Data data_t;
121
122 #ifndef SWIG
123 template <typename... Args,
124 typename = typename std::enable_if<
125 !first_is_base_of<boxed_label, Args...>::value>::type>
126 boxed_label(Args&&... args)
127 noexcept(std::is_nothrow_constructible<Data, Args...>::value)
128 : Data{std::forward<Args>(args)...}
129 {
130 }
131 #endif
132
133 // if Data is a POD type, G++ 4.8.2 wants default values for all
134 // label fields unless we define this default constructor here.
135 explicit boxed_label()
136 noexcept(std::is_nothrow_constructible<Data>::value)
137 {
138 }
139
140 Data& data()
141 {
142 return *this;
143 }
144
145 const Data& data() const
146 {
147 return *this;
148 }
149 };
150
152 // State storage for digraphs
154
155 // We have two implementations, one with attached State_Data, and
156 // one without.
157
158 template <typename Edge, typename State_Data>
159 struct SPOT_API distate_storage final: public State_Data
160 {
161 Edge succ = 0; // First outgoing edge (used when iterating)
162 Edge succ_tail = 0; // Last outgoing edge (used for
163 // appending new edges)
164 #ifndef SWIG
165 template <typename... Args,
166 typename = typename std::enable_if<
167 !first_is_base_of<distate_storage, Args...>::value>::type>
168 distate_storage(Args&&... args)
169 noexcept(std::is_nothrow_constructible<State_Data, Args...>::value)
170 : State_Data{std::forward<Args>(args)...}
171 {
172 }
173 #endif
174 };
175
177 // Edge storage
179
180 // Again two implementation: one with label, and one without.
181
182 template <typename StateIn,
183 typename StateOut, typename Edge, typename Edge_Data>
184 struct SPOT_API edge_storage final: public Edge_Data
185 {
186 typedef Edge edge;
187
188 StateOut dst; // destination
189 Edge next_succ; // next outgoing edge with same
190 // source, or 0
191 StateIn src; // source
192
193 explicit edge_storage()
194 noexcept(std::is_nothrow_constructible<Edge_Data>::value)
195 : Edge_Data{}
196 {
197 }
198
199 #ifndef SWIG
200 template <typename... Args>
201 edge_storage(StateOut dst, Edge next_succ,
202 StateIn src, Args&&... args)
203 noexcept(std::is_nothrow_constructible<Edge_Data, Args...>::value
204 && std::is_nothrow_constructible<StateOut, StateOut>::value
205 && std::is_nothrow_constructible<Edge, Edge>::value)
206 : Edge_Data{std::forward<Args>(args)...},
207 dst(dst), next_succ(next_succ), src(src)
208 {
209 }
210 #endif
211
212 bool operator<(const edge_storage& other) const
213 {
214 if (src < other.src)
215 return true;
216 if (src > other.src)
217 return false;
218 // This might be costly if the destination is a vector
219 if (dst < other.dst)
220 return true;
221 if (dst > other.dst)
222 return false;
223 return this->data() < other.data();
224 }
225
226 bool operator==(const edge_storage& other) const
227 {
228 return src == other.src &&
229 dst == other.dst &&
230 this->data() == other.data();
231 }
232 };
233
235 // Edge iterator
237
238 // This holds a graph and a edge number that is the start of
239 // a list, and it iterates over all the edge_storage_t elements
240 // of that list.
241
242 template <typename Graph>
243 class SPOT_API edge_iterator
244 {
245 public:
246 typedef typename std::conditional<std::is_const<Graph>::value,
247 const typename Graph::edge_storage_t,
248 typename Graph::edge_storage_t>::type
249 value_type;
250 typedef value_type& reference;
251 typedef value_type* pointer;
252 typedef std::ptrdiff_t difference_type;
253 typedef std::forward_iterator_tag iterator_category;
254
255 typedef typename Graph::edge edge;
256
257 edge_iterator() noexcept
258 : g_(nullptr), t_(0)
259 {
260 }
261
262 edge_iterator(Graph* g, edge t) noexcept
263 : g_(g), t_(t)
264 {
265 }
266
267 bool operator==(edge_iterator o) const
268 {
269 return t_ == o.t_;
270 }
271
272 bool operator!=(edge_iterator o) const
273 {
274 return t_ != o.t_;
275 }
276
277 reference operator*() const
278 {
279 return g_->edge_storage(t_);
280 }
281
282 pointer operator->() const
283 {
284 return &g_->edge_storage(t_);
285 }
286
287 edge_iterator operator++()
288 {
289 t_ = operator*().next_succ;
290 return *this;
291 }
292
293 edge_iterator operator++(int)
294 {
295 edge_iterator ti = *this;
296 t_ = operator*().next_succ;
297 return ti;
298 }
299
300 operator bool() const
301 {
302 return t_;
303 }
304
305 edge trans() const
306 {
307 return t_;
308 }
309
310 protected:
311 Graph* g_;
312 edge t_;
313 };
314
315 template <typename Graph>
316 class SPOT_API killer_edge_iterator: public edge_iterator<Graph>
317 {
318 typedef edge_iterator<Graph> super;
319 public:
320 typedef typename Graph::state_storage_t state_storage_t;
321 typedef typename Graph::edge edge;
322
323 killer_edge_iterator(Graph* g, edge t, state_storage_t& src) noexcept
324 : super(g, t), src_(src), prev_(0)
325 {
326 }
327
328 killer_edge_iterator operator++()
329 {
330 prev_ = this->t_;
331 this->t_ = this->operator*().next_succ;
332 return *this;
333 }
334
335 killer_edge_iterator operator++(int)
336 {
337 killer_edge_iterator ti = *this;
338 ++*this;
339 return ti;
340 }
341
342 // Erase the current edge and advance the iterator.
343 void erase()
344 {
345 edge next = this->operator*().next_succ;
346
347 // Update source state and previous edges
348 if (prev_)
349 {
350 this->g_->edge_storage(prev_).next_succ = next;
351 }
352 else
353 {
354 if (src_.succ == this->t_)
355 src_.succ = next;
356 }
357 if (src_.succ_tail == this->t_)
358 {
359 src_.succ_tail = prev_;
360 SPOT_ASSERT(next == 0);
361 }
362
363 // Erased edges have themselves as next_succ.
364 this->operator*().next_succ = this->t_;
365
366 // Advance iterator to next edge.
367 this->t_ = next;
368
369 ++this->g_->killed_edge_;
370 }
371
372 protected:
373 state_storage_t& src_;
374 edge prev_;
375 };
376
377
379 // State OUT
381
382 // Fake container listing the outgoing edges of a state.
383
384 template <typename Graph>
385 class SPOT_API state_out
386 {
387 public:
388 typedef typename Graph::edge edge;
389 state_out(Graph* g, edge t) noexcept
390 : g_(g), t_(t)
391 {
392 }
393
394 edge_iterator<Graph> begin() const
395 {
396 return {g_, t_};
397 }
398
399 edge_iterator<Graph> end() const
400 {
401 return {};
402 }
403
404 void recycle(edge t)
405 {
406 t_ = t;
407 }
408
409 protected:
410 Graph* g_;
411 edge t_;
412 };
413
415 // all_trans
417
418 template <typename Graph>
419 class SPOT_API all_edge_iterator
420 {
421 public:
422 typedef typename std::conditional<std::is_const<Graph>::value,
423 const typename Graph::edge_storage_t,
424 typename Graph::edge_storage_t>::type
425 value_type;
426 typedef value_type& reference;
427 typedef value_type* pointer;
428 typedef std::ptrdiff_t difference_type;
429 typedef std::forward_iterator_tag iterator_category;
430
431 protected:
432 typedef typename std::conditional<std::is_const<Graph>::value,
433 const typename Graph::edge_vector_t,
434 typename Graph::edge_vector_t>::type
435 tv_t;
436
437 unsigned t_;
438 tv_t& tv_;
439
440 void skip_()
441 {
442 unsigned s = tv_.size();
443 do
444 ++t_;
445 while (t_ < s && tv_[t_].next_succ == t_);
446 }
447
448 public:
449 all_edge_iterator(unsigned pos, tv_t& tv) noexcept
450 : t_(pos), tv_(tv)
451 {
452 skip_();
453 }
454
455 all_edge_iterator(tv_t& tv) noexcept
456 : t_(tv.size()), tv_(tv)
457 {
458 }
459
460 all_edge_iterator& operator++()
461 {
462 skip_();
463 return *this;
464 }
465
466 all_edge_iterator operator++(int)
467 {
468 all_edge_iterator old = *this;
469 ++*this;
470 return old;
471 }
472
473 bool operator==(all_edge_iterator o) const
474 {
475 return t_ == o.t_;
476 }
477
478 bool operator!=(all_edge_iterator o) const
479 {
480 return t_ != o.t_;
481 }
482
483 reference operator*() const
484 {
485 return tv_[t_];
486 }
487
488 pointer operator->() const
489 {
490 return &tv_[t_];
491 }
492 };
493
494
495 template <typename Graph>
496 class SPOT_API all_trans
497 {
498 public:
499 typedef typename std::conditional<std::is_const<Graph>::value,
500 const typename Graph::edge_vector_t,
501 typename Graph::edge_vector_t>::type
502 tv_t;
503 typedef all_edge_iterator<Graph> iter_t;
504 private:
505 tv_t& tv_;
506 public:
507
508 all_trans(tv_t& tv) noexcept
509 : tv_(tv)
510 {
511 }
512
513 iter_t begin() const
514 {
515 return {0, tv_};
516 }
517
518 iter_t end() const
519 {
520 return {tv_};
521 }
522 };
523
524 class SPOT_API const_universal_dests
525 {
526 private:
527 const unsigned* begin_;
528 const unsigned* end_;
529 unsigned tmp_;
530 public:
531 const_universal_dests(const unsigned* begin, const unsigned* end) noexcept
532 : begin_(begin), end_(end)
533 {
534 }
535
536 const_universal_dests(unsigned state) noexcept
537 : begin_(&tmp_), end_(&tmp_ + 1), tmp_(state)
538 {
539 }
540
541 const unsigned* begin() const
542 {
543 return begin_;
544 }
545
546 const unsigned* end() const
547 {
548 return end_;
549 }
550 };
551
552 template<class G>
553 class univ_dest_mapper
554 {
555 std::map<std::vector<unsigned>, unsigned> uniq_;
556 G& g_;
557 public:
558
559 univ_dest_mapper(G& graph)
560 : g_(graph)
561 {
562 }
563
564 template<class I>
565 unsigned new_univ_dests(I begin, I end)
566 {
567 std::vector<unsigned> tmp(begin, end);
568 std::sort(tmp.begin(), tmp.end());
569 tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
570 auto p = uniq_.emplace(tmp, 0);
571 if (p.second)
572 p.first->second = g_.new_univ_dests(tmp.begin(), tmp.end());
573 return p.first->second;
574 }
575
576 };
577
578 } // namespace internal
579
580
585 template <typename State_Data, typename Edge_Data>
586 class digraph
587 {
588 friend class internal::edge_iterator<digraph>;
589 friend class internal::edge_iterator<const digraph>;
590 friend class internal::killer_edge_iterator<digraph>;
591
592 public:
593 typedef internal::edge_iterator<digraph> iterator;
594 typedef internal::edge_iterator<const digraph> const_iterator;
595
596 // Extra data to store on each state or edge.
597 typedef State_Data state_data_t;
598 typedef Edge_Data edge_data_t;
599
600 // State and edges are identified by their indices in some
601 // vector.
602 typedef unsigned state;
603 typedef unsigned edge;
604
605 typedef internal::distate_storage<edge,
606 internal::boxed_label<State_Data>>
607 state_storage_t;
608 typedef internal::edge_storage<state, state, edge,
609 internal::boxed_label<Edge_Data>>
610 edge_storage_t;
611 typedef std::vector<state_storage_t> state_vector;
612 typedef std::vector<edge_storage_t> edge_vector_t;
613
614 // A sequence of universal destination groups of the form:
615 // (n state_1 state_2 ... state_n)*
616 typedef std::vector<unsigned> dests_vector_t;
617
618 protected:
619 state_vector states_;
620 edge_vector_t edges_;
621 dests_vector_t dests_; // Only used by alternating automata.
622 // Number of erased edges.
623 unsigned killed_edge_;
624 public:
631 digraph(unsigned max_states = 10, unsigned max_trans = 0)
632 : killed_edge_(0)
633 {
634 states_.reserve(max_states);
635 if (max_trans == 0)
636 max_trans = max_states * 2;
637 edges_.reserve(max_trans + 1);
638 // Edge number 0 is not used, because we use this index
639 // to mark the absence of a edge.
640 edges_.resize(1);
641 // This causes edge 0 to be considered as dead.
642 edges_[0].next_succ = 0;
643 }
644
646 unsigned num_states() const
647 {
648 return states_.size();
649 }
650
654 unsigned num_edges() const
655 {
656 return edges_.size() - killed_edge_ - 1;
657 }
658
660 bool is_existential() const
661 {
662 return dests_.empty();
663 }
664
665 #ifndef SWIG
666 SPOT_DEPRECATED("use !is_existential() instead")
671 bool is_alternating() const
672 {
673 return !is_existential();
674 }
675 #endif
676
682 template <typename... Args>
683 state new_state(Args&&... args)
684 {
685 state s = states_.size();
686 states_.emplace_back(std::forward<Args>(args)...);
687 return s;
688 }
689
696 template <typename... Args>
697 state new_states(unsigned n, Args&&... args)
698 {
699 state s = states_.size();
700 states_.reserve(s + n);
701 while (n--)
702 states_.emplace_back(std::forward<Args>(args)...);
703 return s;
704 }
705
711 state_storage_t&
712 state_storage(state s)
713 {
714 return states_[s];
715 }
716
717 const state_storage_t&
718 state_storage(state s) const
719 {
720 return states_[s];
721 }
723
729 typename state_storage_t::data_t&
730 state_data(state s)
731 {
732 return states_[s].data();
733 }
734
735 const typename state_storage_t::data_t&
736 state_data(state s) const
737 {
738 return states_[s].data();
739 }
741
747 edge_storage_t&
748 edge_storage(edge s)
749 {
750 return edges_[s];
751 }
752
753 const edge_storage_t&
754 edge_storage(edge s) const
755 {
756 return edges_[s];
757 }
759
765 typename edge_storage_t::data_t&
766 edge_data(edge s)
767 {
768 return edges_[s].data();
769 }
770
771 const typename edge_storage_t::data_t&
772 edge_data(edge s) const
773 {
774 return edges_[s].data();
775 }
777
783 template <typename... Args>
784 edge
785 new_edge(state src, state dst, Args&&... args)
786 {
787 edge t = edges_.size();
788 edges_.emplace_back(dst, 0, src, std::forward<Args>(args)...);
789
790 edge st = states_[src].succ_tail;
791 SPOT_ASSERT(st < t || !st);
792 if (!st)
793 states_[src].succ = t;
794 else
795 edges_[st].next_succ = t;
796 states_[src].succ_tail = t;
797 return t;
798 }
799
807 template <typename I>
808 state
809 new_univ_dests(I dst_begin, I dst_end)
810 {
811 unsigned sz = std::distance(dst_begin, dst_end);
812 if (sz == 1)
813 return *dst_begin;
814 SPOT_ASSERT(sz > 1);
815 unsigned d = dests_.size();
816 dests_.emplace_back(sz);
817 dests_.insert(dests_.end(), dst_begin, dst_end);
818 return ~d;
819 }
820
827 template <typename I, typename... Args>
828 edge
829 new_univ_edge(state src, I dst_begin, I dst_end, Args&&... args)
830 {
831 return new_edge(src, new_univ_dests(dst_begin, dst_end),
832 std::forward<Args>(args)...);
833 }
834
840 template <typename... Args>
841 edge
842 new_univ_edge(state src, const std::initializer_list<state>& dsts,
843 Args&&... args)
844 {
845 return new_univ_edge(src, dsts.begin(), dsts.end(),
846 std::forward<Args>(args)...);
847 }
848
849 internal::const_universal_dests univ_dests(state src) const
850 {
851 if ((int)src < 0)
852 {
853 unsigned pos = ~src;
854 const unsigned* d = dests_.data();
855 d += pos;
856 unsigned num = *d;
857 return { d + 1, d + num + 1 };
858 }
859 else
860 {
861 return src;
862 }
863 }
864
865 internal::const_universal_dests univ_dests(const edge_storage_t& e) const
866 {
867 return univ_dests(e.dst);
868 }
869
871 state index_of_state(const state_storage_t& ss) const
872 {
873 SPOT_ASSERT(!states_.empty());
874 return &ss - &states_.front();
875 }
876
878 edge index_of_edge(const edge_storage_t& tt) const
879 {
880 SPOT_ASSERT(!edges_.empty());
881 return &tt - &edges_.front();
882 }
883
886 internal::state_out<digraph>
887 out(state src)
888 {
889 return {this, states_[src].succ};
890 }
891
892 internal::state_out<digraph>
893 out(state_storage_t& src)
894 {
895 return out(index_of_state(src));
896 }
897
898 internal::state_out<const digraph>
899 out(state src) const
900 {
901 return {this, states_[src].succ};
902 }
903
904 internal::state_out<const digraph>
905 out(state_storage_t& src) const
906 {
907 return out(index_of_state(src));
908 }
910
915 internal::killer_edge_iterator<digraph>
916 out_iteraser(state_storage_t& src)
917 {
918 return {this, src.succ, src};
919 }
920
921 internal::killer_edge_iterator<digraph>
922 out_iteraser(state src)
923 {
924 return out_iteraser(state_storage(src));
925 }
927
931 const state_vector& states() const
932 {
933 return states_;
934 }
935
936 state_vector& states()
937 {
938 return states_;
939 }
941
946 internal::all_trans<const digraph> edges() const
947 {
948 return edges_;
949 }
950
951 internal::all_trans<digraph> edges()
952 {
953 return edges_;
954 }
956
965 const edge_vector_t& edge_vector() const
966 {
967 return edges_;
968 }
969
970 edge_vector_t& edge_vector()
971 {
972 return edges_;
973 }
975
982 bool is_valid_edge(edge t) const
983 {
984 // Erased edges have their next_succ pointing to
985 // themselves.
986 return (t < edges_.size() &&
987 edges_[t].next_succ != t);
988 }
989
994 bool is_dead_edge(unsigned t) const
995 {
996 return edges_[t].next_succ == t;
997 }
998
999 bool is_dead_edge(const edge_storage_t& t) const
1000 {
1001 return t.next_succ == index_of_edge(t);
1002 }
1004
1010 const dests_vector_t& dests_vector() const
1011 {
1012 return dests_;
1013 }
1014
1015 dests_vector_t& dests_vector()
1016 {
1017 return dests_;
1018 }
1020
1022 void dump_storage(std::ostream& o) const
1023 {
1024 unsigned tend = edges_.size();
1025 for (unsigned t = 1; t < tend; ++t)
1026 {
1027 o << 't' << t << ": (s"
1028 << edges_[t].src << ", ";
1029 int d = edges_[t].dst;
1030 if (d < 0)
1031 o << 'd' << ~d;
1032 else
1033 o << 's' << d;
1034 o << ") t" << edges_[t].next_succ << '\n';
1035 }
1036 unsigned send = states_.size();
1037 for (unsigned s = 0; s < send; ++s)
1038 {
1039 o << 's' << s << ": t"
1040 << states_[s].succ << " t"
1041 << states_[s].succ_tail << '\n';
1042 }
1043 unsigned dend = dests_.size();
1044 unsigned size = 0;
1045 for (unsigned s = 0; s < dend; ++s)
1046 {
1047 o << 'd' << s << ": ";
1048 if (size == 0)
1049 {
1050 o << '#';
1051 size = dests_[s];
1052 }
1053 else
1054 {
1055 o << 's';
1056 --size;
1057 }
1058 o << dests_[s] << '\n';
1059 }
1060 }
1061
1067 void remove_dead_edges_()
1068 {
1069 if (killed_edge_ == 0)
1070 return;
1071 auto i = std::remove_if(edges_.begin() + 1, edges_.end(),
1072 [this](const edge_storage_t& t) {
1073 return this->is_dead_edge(t);
1074 });
1075 edges_.erase(i, edges_.end());
1076 killed_edge_ = 0;
1077 }
1078
1084 template<class Predicate = std::less<edge_storage_t>>
1085 void sort_edges_(Predicate p = Predicate())
1086 {
1087 //std::cerr << "\nbefore\n";
1088 //dump_storage(std::cerr);
1089 std::stable_sort(edges_.begin() + 1, edges_.end(), p);
1090 }
1091
1096 void chain_edges_()
1097 {
1098 state last_src = -1U;
1099 edge tend = edges_.size();
1100 for (edge t = 1; t < tend; ++t)
1101 {
1102 state src = edges_[t].src;
1103 if (src != last_src)
1104 {
1105 states_[src].succ = t;
1106 if (last_src != -1U)
1107 {
1108 states_[last_src].succ_tail = t - 1;
1109 edges_[t - 1].next_succ = 0;
1110 }
1111 while (++last_src != src)
1112 {
1113 states_[last_src].succ = 0;
1114 states_[last_src].succ_tail = 0;
1115 }
1116 }
1117 else
1118 {
1119 edges_[t - 1].next_succ = t;
1120 }
1121 }
1122 if (last_src != -1U)
1123 {
1124 states_[last_src].succ_tail = tend - 1;
1125 edges_[tend - 1].next_succ = 0;
1126 }
1127 unsigned send = states_.size();
1128 while (++last_src != send)
1129 {
1130 states_[last_src].succ = 0;
1131 states_[last_src].succ_tail = 0;
1132 }
1133 //std::cerr << "\nafter\n";
1134 //dump_storage(std::cerr);
1135 }
1136
1142 void rename_states_(const std::vector<unsigned>& newst)
1143 {
1144 SPOT_ASSERT(newst.size() == states_.size());
1145 unsigned tend = edges_.size();
1146 for (unsigned t = 1; t < tend; t++)
1147 {
1148 edges_[t].dst = newst[edges_[t].dst];
1149 edges_[t].src = newst[edges_[t].src];
1150 }
1151 }
1152
1158 void defrag_states(std::vector<unsigned>&& newst, unsigned used_states)
1159 {
1160 SPOT_ASSERT(newst.size() >= states_.size());
1161 SPOT_ASSERT(used_states > 0);
1162
1163 //std::cerr << "\nbefore defrag\n";
1164 //dump_storage(std::cerr);
1165
1166 // Shift all states in states_, as indicated by newst.
1167 unsigned send = states_.size();
1168 for (state s = 0; s < send; ++s)
1169 {
1170 state dst = newst[s];
1171 if (dst == s)
1172 continue;
1173 if (dst == -1U)
1174 {
1175 // This is an erased state. Mark all its edges as
1176 // dead (i.e., t.next_succ should point to t for each of
1177 // them).
1178 auto t = states_[s].succ;
1179 while (t)
1180 std::swap(t, edges_[t].next_succ);
1181 continue;
1182 }
1183 states_[dst] = std::move(states_[s]);
1184 }
1185 states_.resize(used_states);
1186
1187 // Shift all edges in edges_. The algorithm is
1188 // similar to remove_if, but it also keeps the correspondence
1189 // between the old and new index as newidx[old] = new.
1190 unsigned tend = edges_.size();
1191 std::vector<edge> newidx(tend);
1192 unsigned dest = 1;
1193 for (edge t = 1; t < tend; ++t)
1194 {
1195 if (is_dead_edge(t))
1196 continue;
1197 if (t != dest)
1198 edges_[dest] = std::move(edges_[t]);
1199 newidx[t] = dest;
1200 ++dest;
1201 }
1202 edges_.resize(dest);
1203 killed_edge_ = 0;
1204
1205 // Adjust next_succ and dst pointers in all edges.
1206 for (edge t = 1; t < dest; ++t)
1207 {
1208 auto& tr = edges_[t];
1209 tr.src = newst[tr.src];
1210 tr.dst = newst[tr.dst];
1211 tr.next_succ = newidx[tr.next_succ];
1212 }
1213
1214 // Adjust succ and succ_tails pointers in all states.
1215 for (auto& s: states_)
1216 {
1217 s.succ = newidx[s.succ];
1218 s.succ_tail = newidx[s.succ_tail];
1219 }
1220
1221 //std::cerr << "\nafter defrag\n";
1222 //dump_storage(std::cerr);
1223 }
1224 };
1225 }
spot::digraph::out_iteraser
internal::killer_edge_iterator< digraph > out_iteraser(state src)
Return a fake container with all edges leaving src, allowing erasure.
Definition: graph.hh:922
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::digraph::edge_storage
const edge_storage_t & edge_storage(edge s) const
return a reference to the storage of an edge
Definition: graph.hh:754
spot::digraph::state_storage
const state_storage_t & state_storage(state s) const
return a reference to the storage of a state
Definition: graph.hh:718
spot::digraph::edge_vector
edge_vector_t & edge_vector()
Return the vector of all edges.
Definition: graph.hh:970
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::out
internal::state_out< digraph > out(state_storage_t &src)
Return a fake container with all edges leaving src.
Definition: graph.hh:893
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::internal::edge_iterator
Definition: graph.hh:243
spot::digraph::states
state_vector & states()
Return the vector of states.
Definition: graph.hh:936
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::out_iteraser
internal::killer_edge_iterator< digraph > out_iteraser(state_storage_t &src)
Return a fake container with all edges leaving src, allowing erasure.
Definition: graph.hh:916
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::internal::edge_storage
Definition: graph.hh:184
spot::internal::boxed_label< void, true >
Definition: graph.hh:102
spot::digraph::dests_vector
dests_vector_t & dests_vector()
The vector used to store universal destinations.
Definition: graph.hh:1015
spot::digraph::dests_vector
const dests_vector_t & dests_vector() const
The vector used to store universal destinations.
Definition: graph.hh:1010
spot::op::G
Globally.
spot::digraph::new_univ_edge
edge new_univ_edge(state src, const std::initializer_list< state > &dsts, Args &&...args)
Create a new universal edge.
Definition: graph.hh:842
spot::op::U
until
spot::internal::univ_dest_mapper
Definition: graph.hh:553
spot::digraph::states
const state_vector & states() const
Return the vector of states.
Definition: graph.hh:931
spot::digraph::sort_edges_
void sort_edges_(Predicate p=Predicate())
Sort all edge according to a predicate.
Definition: graph.hh:1085
spot::internal::distate_storage
Definition: graph.hh:159
spot::digraph::out
internal::state_out< const digraph > out(state_storage_t &src) const
Return a fake container with all edges leaving src.
Definition: graph.hh:905
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::digraph::dump_storage
void dump_storage(std::ostream &o) const
Dump the state and edge storage for debugging.
Definition: graph.hh:1022
spot::digraph::remove_dead_edges_
void remove_dead_edges_()
Remove all dead edges.
Definition: graph.hh:1067
spot::internal::all_trans
Definition: graph.hh:496
spot::digraph::rename_states_
void rename_states_(const std::vector< unsigned > &newst)
Rename all the states in the edge vector.
Definition: graph.hh:1142
spot::digraph::out
internal::state_out< digraph > out(state src)
Return a fake container with all edges leaving src.
Definition: graph.hh:887
spot::digraph::out
internal::state_out< const digraph > out(state src) const
Return a fake container with all edges leaving src.
Definition: graph.hh:899
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::op::tt
True.
spot::digraph::is_existential
bool is_existential() const
Whether the automaton uses only existential branching.
Definition: graph.hh:660
spot::internal::first_is_base_of
Definition: graph.hh:42
spot::digraph::state_data
const state_storage_t::data_t & state_data(state s) const
return the State_Data associated to a state
Definition: graph.hh:736
spot::internal::all_edge_iterator
Definition: graph.hh:419
internal
Definition: twa.hh:1531
spot::digraph::defrag_states
void defrag_states(std::vector< unsigned > &&newst, unsigned used_states)
Rename and remove states.
Definition: graph.hh:1158
spot::digraph::is_valid_edge
bool is_valid_edge(edge t) const
Test whether the given edge is valid.
Definition: graph.hh:982
spot::digraph::index_of_state
state index_of_state(const state_storage_t &ss) const
Convert a storage reference into a state number.
Definition: graph.hh:871
spot::digraph::chain_edges_
void chain_edges_()
Reconstruct the chain of outgoing edges.
Definition: graph.hh:1096
spot::digraph::edges
internal::all_trans< digraph > edges()
Return a fake container with all edges (exluding erased edges)
Definition: graph.hh:951
spot::digraph::edge_data
const edge_storage_t::data_t & edge_data(edge s) const
return the Edgeg_Data of an edge.
Definition: graph.hh:772
spot::digraph::is_dead_edge
bool is_dead_edge(const edge_storage_t &t) const
Tests whether an edge has been erased.
Definition: graph.hh:999
spot::digraph
A directed graph.
Definition: graph.hh:36
spot::digraph::index_of_edge
edge index_of_edge(const edge_storage_t &tt) const
Conveart a storage reference into an edge number.
Definition: graph.hh:878
spot::digraph::digraph
digraph(unsigned max_states=10, unsigned max_trans=0)
Construct an empty graph.
Definition: graph.hh:631
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::internal::boxed_label< Data, false >
Definition: graph.hh:118
spot::digraph::new_state
state new_state(Args &&...args)
Create a new states.
Definition: graph.hh:683
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::internal::killer_edge_iterator
Definition: graph.hh:316

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