spot  1.99.3
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
graph.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2014, 2015 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 "misc/common.hh"
23 #include <vector>
24 #include <type_traits>
25 #include <tuple>
26 #include <cassert>
27 #include <iterator>
28 #include <algorithm>
29 #include <iostream>
30 
31 namespace spot
32 {
33  template <typename State_Data, typename Edge_Data, bool Alternating = false>
34  class SPOT_API digraph;
35 
36  namespace internal
37  {
38  template <typename Of, typename ...Args>
40  {
41  static const bool value = false;
42  };
43 
44  template <typename Of, typename Arg1, typename ...Args>
45  struct first_is_base_of<Of, Arg1, Args...>
46  {
47  static const bool value =
48  std::is_base_of<Of, typename std::decay<Arg1>::type>::value;
49  };
50 
51 
52  // The boxed_label class stores Data as an attribute called
53  // "label" if boxed is true. It is an empty class if Data is
54  // void, and it simply inherits from Data if boxed is false.
55  //
56  // The data() method offers an homogeneous access to the Data
57  // instance.
58  template <typename Data, bool boxed = !std::is_class<Data>::value>
59  struct SPOT_API boxed_label
60  {
61  typedef Data data_t;
62  Data label;
63 
64  template <typename... Args,
65  typename = typename std::enable_if<
66  !first_is_base_of<boxed_label, Args...>::value>::type>
67  boxed_label(Args&&... args):
68  label{std::forward<Args>(args)...}
69  {
70  }
71 
72  // if Data is a POD type, G++ 4.8.2 wants default values for all
73  // label fields unless we define this default constructor here.
74  explicit boxed_label()
75  {
76  }
77 
78  Data& data()
79  {
80  return label;
81  }
82 
83  const Data& data() const
84  {
85  return label;
86  }
87 
88  bool operator<(const boxed_label& other) const
89  {
90  return label < other.label;
91  }
92  };
93 
94  template <>
95  struct SPOT_API boxed_label<void, true>: public std::tuple<>
96  {
97  typedef std::tuple<> data_t;
98  std::tuple<>& data()
99  {
100  return *this;
101  }
102 
103  const std::tuple<>& data() const
104  {
105  return *this;
106  }
107 
108  };
109 
110  template <typename Data>
111  struct SPOT_API boxed_label<Data, false>: public Data
112  {
113  typedef Data data_t;
114 
115  template <typename... Args,
116  typename = typename std::enable_if<
117  !first_is_base_of<boxed_label, Args...>::value>::type>
118  boxed_label(Args&&... args):
119  Data{std::forward<Args>(args)...}
120  {
121  }
122 
123  // if Data is a POD type, G++ 4.8.2 wants default values for all
124  // label fields unless we define this default constructor here.
125  explicit boxed_label()
126  {
127  }
128 
129  Data& data()
130  {
131  return *this;
132  }
133 
134  const Data& data() const
135  {
136  return *this;
137  }
138  };
139 
141  // State storage for digraphs
143 
144  // We have two implementations, one with attached State_Data, and
145  // one without.
146 
147  template <typename Edge, typename State_Data>
148  struct SPOT_API distate_storage final: public State_Data
149  {
150  Edge succ = 0; // First outgoing edge (used when iterating)
151  Edge succ_tail = 0; // Last outgoing edge (used for
152  // appending new edges)
153 
154  template <typename... Args,
155  typename = typename std::enable_if<
156  !first_is_base_of<distate_storage, Args...>::value>::type>
157  distate_storage(Args&&... args):
158  State_Data{std::forward<Args>(args)...}
159  {
160  }
161  };
162 
164  // Edge storage
166 
167  // Again two implementation: one with label, and one without.
168 
169  template <typename StateIn,
170  typename StateOut, typename Edge, typename Edge_Data>
171  struct SPOT_API edge_storage final: public Edge_Data
172  {
173  typedef Edge edge;
174 
175  StateOut dst; // destination
176  Edge next_succ; // next outgoing edge with same
177  // source, or 0
178  StateIn src; // source
179 
180  explicit edge_storage()
181  : Edge_Data{}
182  {
183  }
184 
185  template <typename... Args>
186  edge_storage(StateOut dst, Edge next_succ,
187  StateIn src, Args&&... args)
188  : Edge_Data{std::forward<Args>(args)...},
189  dst(dst), next_succ(next_succ), src(src)
190  {
191  }
192 
193  bool operator<(const edge_storage& other) const
194  {
195  if (src < other.src)
196  return true;
197  if (src > other.src)
198  return false;
199  // This might be costly if the destination is a vector
200  if (dst < other.dst)
201  return true;
202  if (dst > other.dst)
203  return false;
204  return this->data() < other.data();
205  }
206 
207  bool operator==(const edge_storage& other) const
208  {
209  return src == other.src &&
210  dst == other.dst &&
211  this->data() == other.data();
212  }
213  };
214 
216  // Edge iterator
218 
219  // This holds a graph and a edge number that is the start of
220  // a list, and it iterates over all the edge_storage_t elements
221  // of that list.
222 
223  template <typename Graph>
224  class SPOT_API edge_iterator:
225  std::iterator<std::forward_iterator_tag,
226  typename
227  std::conditional<std::is_const<Graph>::value,
228  const typename Graph::edge_storage_t,
229  typename Graph::edge_storage_t>::type>
230  {
231  typedef
232  std::iterator<std::forward_iterator_tag,
233  typename
234  std::conditional<std::is_const<Graph>::value,
235  const typename Graph::edge_storage_t,
236  typename Graph::edge_storage_t>::type>
237  super;
238  public:
239  typedef typename Graph::edge edge;
240 
241  edge_iterator()
242  : g_(nullptr), t_(0)
243  {
244  }
245 
246  edge_iterator(Graph* g, edge t): g_(g), t_(t)
247  {
248  }
249 
250  bool operator==(edge_iterator o) const
251  {
252  return t_ == o.t_;
253  }
254 
255  bool operator!=(edge_iterator o) const
256  {
257  return t_ != o.t_;
258  }
259 
260  typename super::reference
261  operator*()
262  {
263  return g_->edge_storage(t_);
264  }
265 
266  typename super::pointer
267  operator->()
268  {
269  return &g_->edge_storage(t_);
270  }
271 
272  edge_iterator operator++()
273  {
274  t_ = operator*().next_succ;
275  return *this;
276  }
277 
278  edge_iterator operator++(int)
279  {
280  edge_iterator ti = *this;
281  t_ = operator*().next_succ;
282  return ti;
283  }
284 
285  operator bool() const
286  {
287  return t_;
288  }
289 
290  edge trans() const
291  {
292  return t_;
293  }
294 
295  protected:
296  Graph* g_;
297  edge t_;
298  };
299 
300  template <typename Graph>
301  class SPOT_API killer_edge_iterator: public edge_iterator<Graph>
302  {
303  typedef edge_iterator<Graph> super;
304  public:
305  typedef typename Graph::state_storage_t state_storage_t;
306  typedef typename Graph::edge edge;
307 
308  killer_edge_iterator(Graph* g, edge t, state_storage_t& src):
309  super(g, t), src_(src), prev_(0)
310  {
311  }
312 
313  killer_edge_iterator operator++()
314  {
315  prev_ = this->t_;
316  this->t_ = this->operator*().next_succ;
317  return *this;
318  }
319 
320  killer_edge_iterator operator++(int)
321  {
322  killer_edge_iterator ti = *this;
323  ++*this;
324  return ti;
325  }
326 
327  // Erase the current edge and advance the iterator.
328  void erase()
329  {
330  edge next = this->operator*().next_succ;
331 
332  // Update source state and previous edges
333  if (prev_)
334  {
335  this->g_->edge_storage(prev_).next_succ = next;
336  }
337  else
338  {
339  if (src_.succ == this->t_)
340  src_.succ = next;
341  }
342  if (src_.succ_tail == this->t_)
343  {
344  src_.succ_tail = prev_;
345  assert(next == 0);
346  }
347 
348  // Erased edges have themselves as next_succ.
349  this->operator*().next_succ = this->t_;
350 
351  // Advance iterator to next edge.
352  this->t_ = next;
353 
354  ++this->g_->killed_edge_;
355  }
356 
357  protected:
358  state_storage_t& src_;
359  edge prev_;
360  };
361 
362 
364  // State OUT
366 
367  // Fake container listing the outgoing edges of a state.
368 
369  template <typename Graph>
370  class SPOT_API state_out
371  {
372  public:
373  typedef typename Graph::edge edge;
374  state_out(Graph* g, edge t):
375  g_(g), t_(t)
376  {
377  }
378 
379  edge_iterator<Graph> begin()
380  {
381  return {g_, t_};
382  }
383 
385  {
386  return {};
387  }
388 
389  void recycle(edge t)
390  {
391  t_ = t;
392  }
393 
394  protected:
395  Graph* g_;
396  edge t_;
397  };
398 
400  // all_trans
402 
403  template <typename Graph>
404  class SPOT_API all_edge_iterator:
405  std::iterator<std::forward_iterator_tag,
406  typename
407  std::conditional<std::is_const<Graph>::value,
408  const typename Graph::edge_storage_t,
409  typename Graph::edge_storage_t>::type>
410  {
411  typedef
412  std::iterator<std::forward_iterator_tag,
413  typename
414  std::conditional<std::is_const<Graph>::value,
415  const typename Graph::edge_storage_t,
416  typename Graph::edge_storage_t>::type>
417  super;
418 
419  typedef typename std::conditional<std::is_const<Graph>::value,
420  const typename Graph::edge_vector_t,
421  typename Graph::edge_vector_t>::type
422  tv_t;
423 
424  unsigned t_;
425  tv_t& tv_;
426 
427  void skip_()
428  {
429  unsigned s = tv_.size();
430  do
431  ++t_;
432  while (t_ < s && tv_[t_].next_succ == t_);
433  }
434 
435  public:
436  all_edge_iterator(unsigned pos, tv_t& tv)
437  : t_(pos), tv_(tv)
438  {
439  skip_();
440  }
441 
442  all_edge_iterator(tv_t& tv)
443  : t_(tv.size()), tv_(tv)
444  {
445  }
446 
447  all_edge_iterator& operator++()
448  {
449  skip_();
450  return *this;
451  }
452 
453  all_edge_iterator operator++(int)
454  {
455  all_edge_iterator old = *this;
456  ++*this;
457  return old;
458  }
459 
460  bool operator==(all_edge_iterator o) const
461  {
462  return t_ == o.t_;
463  }
464 
465  bool operator!=(all_edge_iterator o) const
466  {
467  return t_ != o.t_;
468  }
469 
470  typename super::reference
471  operator*()
472  {
473  return tv_[t_];
474  }
475 
476  typename super::pointer
477  operator->()
478  {
479  return &tv_[t_];
480  }
481  };
482 
483 
484  template <typename Graph>
485  class SPOT_API all_trans
486  {
487  typedef typename std::conditional<std::is_const<Graph>::value,
488  const typename Graph::edge_vector_t,
489  typename Graph::edge_vector_t>::type
490  tv_t;
492  tv_t& tv_;
493  public:
494 
495  all_trans(tv_t& tv)
496  : tv_(tv)
497  {
498  }
499 
500  iter_t begin()
501  {
502  return {0, tv_};
503  }
504 
505  iter_t end()
506  {
507  return {tv_};
508  }
509  };
510 
511  }
512 
513 
514  // The actual graph implementation
515 
516  template <typename State_Data, typename Edge_Data, bool Alternating>
517  class digraph
518  {
519  friend class internal::edge_iterator<digraph>;
520  friend class internal::edge_iterator<const digraph>;
521  friend class internal::killer_edge_iterator<digraph>;
522 
523  public:
526 
527  static constexpr bool alternating()
528  {
529  return Alternating;
530  }
531 
532  // Extra data to store on each state or edge.
533  typedef State_Data state_data_t;
534  typedef Edge_Data edge_data_t;
535 
536  // State and edges are identified by their indices in some
537  // vector.
538  typedef unsigned state;
539  typedef unsigned edge;
540 
541  // The type of an output state (when seen from a edge)
542  // depends on the kind of graph we build
543  typedef typename std::conditional<Alternating,
544  std::vector<state>,
545  state>::type out_state;
546 
547  typedef internal::distate_storage<edge,
550  typedef internal::edge_storage<state, out_state, edge,
553  typedef std::vector<state_storage_t> state_vector;
554  typedef std::vector<edge_storage_t> edge_vector_t;
555  protected:
556  state_vector states_;
557  edge_vector_t edges_;
558  // Number of erased edges.
559  unsigned killed_edge_;
560  public:
567  digraph(unsigned max_states = 10, unsigned max_trans = 0)
568  : killed_edge_(0)
569  {
570  states_.reserve(max_states);
571  if (max_trans == 0)
572  max_trans = max_states * 2;
573  edges_.reserve(max_trans + 1);
574  // Edge number 0 is not used, because we use this index
575  // to mark the absence of a edge.
576  edges_.resize(1);
577  // This causes edge 0 to be considered as dead.
578  edges_[0].next_succ = 0;
579  }
580 
581  unsigned num_states() const
582  {
583  return states_.size();
584  }
585 
586  unsigned num_edges() const
587  {
588  return edges_.size() - killed_edge_ - 1;
589  }
590 
591  bool valid_trans(edge t) const
592  {
593  // Erased edges have their next_succ pointing to
594  // themselves.
595  return (t < edges_.size() &&
596  edges_[t].next_succ != t);
597  }
598 
599  template <typename... Args>
600  state new_state(Args&&... args)
601  {
602  state s = states_.size();
603  states_.emplace_back(std::forward<Args>(args)...);
604  return s;
605  }
606 
607  template <typename... Args>
608  state new_states(unsigned n, Args&&... args)
609  {
610  state s = states_.size();
611  states_.reserve(s + n);
612  while (n--)
613  states_.emplace_back(std::forward<Args>(args)...);
614  return s;
615  }
616 
617  state_storage_t&
618  state_storage(state s)
619  {
620  assert(s < states_.size());
621  return states_[s];
622  }
623 
624  const state_storage_t&
625  state_storage(state s) const
626  {
627  assert(s < states_.size());
628  return states_[s];
629  }
630 
631  // Do not use State_Data& as return type, because State_Data might
632  // be void.
633  typename state_storage_t::data_t&
634  state_data(state s)
635  {
636  assert(s < states_.size());
637  return states_[s].data();
638  }
639 
640  // May not be called on states with no data.
641  const typename state_storage_t::data_t&
642  state_data(state s) const
643  {
644  assert(s < states_.size());
645  return states_[s].data();
646  }
647 
648  edge_storage_t&
649  edge_storage(edge s)
650  {
651  assert(s < edges_.size());
652  return edges_[s];
653  }
654 
655  const edge_storage_t&
656  edge_storage(edge s) const
657  {
658  assert(s < edges_.size());
659  return edges_[s];
660  }
661 
662  typename edge_storage_t::data_t&
663  edge_data(edge s)
664  {
665  assert(s < edges_.size());
666  return edges_[s].data();
667  }
668 
669  const typename edge_storage_t::data_t&
670  edge_data(edge s) const
671  {
672  assert(s < edges_.size());
673  return edges_[s].data();
674  }
675 
676  template <typename... Args>
677  edge
678  new_edge(state src, out_state dst, Args&&... args)
679  {
680  assert(src < states_.size());
681 
682  edge t = edges_.size();
683  edges_.emplace_back(dst, 0, src, std::forward<Args>(args)...);
684 
685  edge st = states_[src].succ_tail;
686  assert(st < t || !st);
687  if (!st)
688  states_[src].succ = t;
689  else
690  edges_[st].next_succ = t;
691  states_[src].succ_tail = t;
692  return t;
693  }
694 
695  state index_of_state(const state_storage_t& ss) const
696  {
697  assert(!states_.empty());
698  return &ss - &states_.front();
699  }
700 
701  edge index_of_edge(const edge_storage_t& tt) const
702  {
703  assert(!edges_.empty());
704  return &tt - &edges_.front();
705  }
706 
707  internal::state_out<digraph>
708  out(state src)
709  {
710  return {this, states_[src].succ};
711  }
712 
713  internal::state_out<digraph>
714  out(state_storage_t& src)
715  {
716  return out(index_of_state(src));
717  }
718 
719  internal::state_out<const digraph>
720  out(state src) const
721  {
722  return {this, states_[src].succ};
723  }
724 
725  internal::state_out<const digraph>
726  out(state_storage_t& src) const
727  {
728  return out(index_of_state(src));
729  }
730 
731  internal::killer_edge_iterator<digraph>
732  out_iteraser(state_storage_t& src)
733  {
734  return {this, src.succ, src};
735  }
736 
737  internal::killer_edge_iterator<digraph>
738  out_iteraser(state src)
739  {
740  return out_iteraser(state_storage(src));
741  }
742 
743  const state_vector& states() const
744  {
745  return states_;
746  }
747 
748  state_vector& states()
749  {
750  return states_;
751  }
752 
753  internal::all_trans<const digraph> edges() const
754  {
755  return edges_;
756  }
757 
758  internal::all_trans<digraph> edges()
759  {
760  return edges_;
761  }
762 
763  // When using this method, beware that the first entry (edge
764  // #0) is not a real edge, and that any edge with
765  // next_succ pointing to itself is an erased edge.
766  //
767  // You should probably use edges() instead.
768  const edge_vector_t& edge_vector() const
769  {
770  return edges_;
771  }
772 
773  edge_vector_t& edge_vector()
774  {
775  return edges_;
776  }
777 
778  bool is_dead_edge(unsigned t) const
779  {
780  return edges_[t].next_succ == t;
781  }
782 
783  bool is_dead_edge(const edge_storage_t& t) const
784  {
785  return t.next_succ == index_of_edge(t);
786  }
787 
788 
789  // To help debugging
790  void dump_storage(std::ostream& o) const
791  {
792  unsigned tend = edges_.size();
793  for (unsigned t = 1; t < tend; ++t)
794  {
795  o << 't' << t << ": (s"
796  << edges_[t].src << ", s"
797  << edges_[t].dst << ") t"
798  << edges_[t].next_succ << '\n';
799  }
800  unsigned send = states_.size();
801  for (unsigned s = 0; s < send; ++s)
802  {
803  o << 's' << s << ": t"
804  << states_[s].succ << " t"
805  << states_[s].succ_tail << '\n';
806  }
807  }
808 
809  // Remove all dead edges. The edges_ vector is left
810  // in a state that is incorrect and should eventually be fixed by
811  // a call to chain_edges_() before any iteration on the
812  // successor of a state is performed.
813  void remove_dead_edges_()
814  {
815  if (killed_edge_ == 0)
816  return;
817  auto i = std::remove_if(edges_.begin() + 1, edges_.end(),
818  [this](const edge_storage_t& t) {
819  return this->is_dead_edge(t);
820  });
821  edges_.erase(i, edges_.end());
822  killed_edge_ = 0;
823  }
824 
825  // This will invalidate all iterators, and also destroy edge
826  // chains. Call chain_edges_() immediately afterwards
827  // unless you know what you are doing.
828  template<class Predicate = std::less<edge_storage_t>>
829  void sort_edges_(Predicate p = Predicate())
830  {
831  //std::cerr << "\nbefore\n";
832  //dump_storage(std::cerr);
833  std::stable_sort(edges_.begin() + 1, edges_.end(), p);
834  }
835 
836  // Should be called only when it is known that all edges
837  // with the same destination are consecutive in the vector.
838  void chain_edges_()
839  {
840  state last_src = -1U;
841  edge tend = edges_.size();
842  for (edge t = 1; t < tend; ++t)
843  {
844  state src = edges_[t].src;
845  if (src != last_src)
846  {
847  states_[src].succ = t;
848  if (last_src != -1U)
849  {
850  states_[last_src].succ_tail = t - 1;
851  edges_[t - 1].next_succ = 0;
852  }
853  while (++last_src != src)
854  {
855  states_[last_src].succ = 0;
856  states_[last_src].succ_tail = 0;
857  }
858  }
859  else
860  {
861  edges_[t - 1].next_succ = t;
862  }
863  }
864  if (last_src != -1U)
865  {
866  states_[last_src].succ_tail = tend - 1;
867  edges_[tend - 1].next_succ = 0;
868  }
869  unsigned send = states_.size();
870  while (++last_src != send)
871  {
872  states_[last_src].succ = 0;
873  states_[last_src].succ_tail = 0;
874  }
875  //std::cerr << "\nafter\n";
876  //dump_storage(std::cerr);
877  }
878 
879  // Rename all the states in the edge vector. The
880  // edges_ vector is left in a state that is incorrect and
881  // should eventually be fixed by a call to chain_edges_()
882  // before any iteration on the successor of a state is performed.
883  void rename_states_(const std::vector<unsigned>& newst)
884  {
885  assert(newst.size() == states_.size());
886  unsigned tend = edges_.size();
887  for (unsigned t = 1; t < tend; t++)
888  {
889  edges_[t].dst = newst[edges_[t].dst];
890  edges_[t].src = newst[edges_[t].src];
891  }
892  }
893 
894  void defrag_states(std::vector<unsigned>&& newst, unsigned used_states)
895  {
896  assert(newst.size() == states_.size());
897  assert(used_states > 0);
898 
899  //std::cerr << "\nbefore defrag\n";
900  //dump_storage(std::cerr);
901 
902  // Shift all states in states_, as indicated by newst.
903  unsigned send = states_.size();
904  for (state s = 0; s < send; ++s)
905  {
906  state dst = newst[s];
907  if (dst == s)
908  continue;
909  if (dst == -1U)
910  {
911  // This is an erased state. Mark all its edges as
912  // dead (i.e., t.next_succ should point to t for each of
913  // them).
914  auto t = states_[s].succ;
915  while (t)
916  std::swap(t, edges_[t].next_succ);
917  continue;
918  }
919  states_[dst] = std::move(states_[s]);
920  }
921  states_.resize(used_states);
922 
923  // Shift all edges in edges_. The algorithm is
924  // similar to remove_if, but it also keeps the correspondence
925  // between the old and new index as newidx[old] = new.
926  unsigned tend = edges_.size();
927  std::vector<edge> newidx(tend);
928  unsigned dest = 1;
929  for (edge t = 1; t < tend; ++t)
930  {
931  if (is_dead_edge(t))
932  continue;
933  if (t != dest)
934  edges_[dest] = std::move(edges_[t]);
935  newidx[t] = dest;
936  ++dest;
937  }
938  edges_.resize(dest);
939  killed_edge_ = 0;
940 
941  // Adjust next_succ and dst pointers in all edges.
942  for (edge t = 1; t < dest; ++t)
943  {
944  auto& tr = edges_[t];
945  tr.next_succ = newidx[tr.next_succ];
946  tr.dst = newst[tr.dst];
947  tr.src = newst[tr.src];
948  assert(tr.dst != -1U);
949  }
950 
951  // Adjust succ and succ_tails pointers in all states.
952  for (auto& s: states_)
953  {
954  s.succ = newidx[s.succ];
955  s.succ_tail = newidx[s.succ_tail];
956  }
957 
958  //std::cerr << "\nafter defrag\n";
959  //dump_storage(std::cerr);
960  }
961  };
962 }
Definition: public.hh:31
Definition: graph.hh:59
digraph(unsigned max_states=10, unsigned max_trans=0)
construct an empty graph
Definition: graph.hh:567
Definition: graph.hh:517
Definition: graph.hh:224
Definition: graph.hh:171
Definition: graph.hh:148
Definition: graph.hh:485
Definition: graph.hh:39
Definition: graph.hh:404
Definition: graph.hh:370
Definition: graph.hh:301

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Wed Aug 26 2015 08:42:37 for spot by doxygen 1.8.8