21#include <spot/misc/common.hh>
22#include <spot/misc/_config.h>
23#include <spot/misc/permute.hh>
32#ifdef SPOT_ENABLE_PTHREAD
38 template <
typename State_Data,
typename Edge_Data>
39 class SPOT_API digraph;
44 template <
typename Of,
typename ...Args>
47 static const bool value =
false;
50 template <
typename Of,
typename Arg1,
typename ...Args>
53 static const bool value =
54 std::is_base_of<Of, typename std::decay<Arg1>::type>::value;
64 template <typename Data, bool boxed = !std::is_class<Data>::value>
71 template <
typename... Args,
72 typename =
typename std::enable_if<
75 noexcept(std::is_nothrow_constructible<Data, Args...>::value)
76 : label{std::forward<Args>(args)...}
84 noexcept(std::is_nothrow_constructible<Data>::value)
93 const Data& data()
const
100 return label < other.label;
107 typedef std::tuple<> data_t;
113 const std::tuple<>& data()
const
120 template <
typename Data>
126 template <
typename... Args,
127 typename =
typename std::enable_if<
130 noexcept(std::is_nothrow_constructible<Data, Args...>::value)
131 : Data{std::forward<Args>(args)...}
139 noexcept(std::is_nothrow_constructible<Data>::value)
148 const Data& data()
const
161 template <
typename Edge,
typename State_Data>
168 template <
typename... Args,
169 typename =
typename std::enable_if<
172 noexcept(std::is_nothrow_constructible<State_Data, Args...>::value)
173 : State_Data{std::forward<Args>(args)...}
185 template <
typename StateIn,
186 typename StateOut,
typename Edge,
typename Edge_Data>
197 noexcept(std::is_nothrow_constructible<Edge_Data>::value)
203 template <
typename... Args>
205 StateIn src, Args&&... args)
206 noexcept(std::is_nothrow_constructible<Edge_Data, Args...>::value
207 && std::is_nothrow_constructible<StateOut, StateOut>::value
208 && std::is_nothrow_constructible<Edge, Edge>::value)
209 : Edge_Data{std::forward<Args>(args)...},
210 dst(dst), next_succ(next_succ), src(src)
226 return this->data() < other.data();
231 return src == other.src &&
233 this->data() == other.data();
245 template <
typename Graph>
249 typedef typename std::conditional<std::is_const<Graph>::value,
250 const typename Graph::edge_storage_t,
251 typename Graph::edge_storage_t>::type
253 typedef value_type& reference;
254 typedef value_type* pointer;
255 typedef std::ptrdiff_t difference_type;
256 typedef std::forward_iterator_tag iterator_category;
258 typedef typename Graph::edge edge;
280 reference operator*()
const
282 return g_->edge_storage(t_);
285 pointer operator->()
const
287 return &g_->edge_storage(t_);
292 t_ = operator*().next_succ;
299 t_ = operator*().next_succ;
303 operator bool()
const
318 template <
typename Graph>
323 typedef typename Graph::state_storage_t state_storage_t;
324 typedef typename Graph::edge edge;
327 :
super(g, t), src_(src), prev_(0)
334 this->t_ = this->operator*().next_succ;
348 edge next = this->operator*().next_succ;
353 this->g_->edge_storage(prev_).next_succ = next;
357 if (src_.succ == this->t_)
360 if (src_.succ_tail == this->t_)
362 src_.succ_tail = prev_;
363 SPOT_ASSERT(next == 0);
367 this->operator*().next_succ = this->t_;
372 ++this->g_->killed_edge_;
376 state_storage_t& src_;
387 template <
typename Graph>
391 typedef typename Graph::edge edge;
421 template <
typename Graph>
425 typedef typename std::conditional<std::is_const<Graph>::value,
426 const typename Graph::edge_storage_t,
427 typename Graph::edge_storage_t>::type
429 typedef value_type& reference;
430 typedef value_type* pointer;
431 typedef std::ptrdiff_t difference_type;
432 typedef std::forward_iterator_tag iterator_category;
435 typedef typename std::conditional<std::is_const<Graph>::value,
436 const typename Graph::edge_vector_t,
437 typename Graph::edge_vector_t>::type
445 unsigned s = tv_.size();
448 while (t_ < s && tv_[t_].next_succ == t_);
459 : t_(tv.size()), tv_(tv)
486 reference operator*()
const
491 pointer operator->()
const
498 template <
typename Graph>
502 typedef typename std::conditional<std::is_const<Graph>::value,
503 const typename Graph::edge_vector_t,
504 typename Graph::edge_vector_t>::type
530 const unsigned* begin_;
531 const unsigned* end_;
535 : begin_(begin), end_(end)
540 : begin_(&tmp_), end_(&tmp_ + 1), tmp_(
state)
544 const unsigned* begin()
const
549 const unsigned* end()
const
558 std::map<std::vector<unsigned>,
unsigned> uniq_;
568 unsigned new_univ_dests(I begin, I end)
570 std::vector<unsigned> tmp(begin, end);
571 std::sort(tmp.begin(), tmp.end());
572 tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
573 auto p = uniq_.emplace(tmp, 0);
575 p.first->second = g_.new_univ_dests(tmp.begin(), tmp.end());
576 return p.first->second;
579 unsigned new_univ_dests(std::vector<unsigned>&& tmp)
581 std::sort(tmp.begin(), tmp.end());
582 tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
583 auto p = uniq_.emplace(tmp, 0);
585 p.first->second = g_.new_univ_dests(tmp.begin(), tmp.end());
586 return p.first->second;
597 template <
typename State_Data,
typename Edge_Data>
609 typedef State_Data state_data_t;
610 typedef Edge_Data edge_data_t;
614 typedef unsigned state;
615 typedef unsigned edge;
623 typedef std::vector<state_storage_t> state_vector;
624 typedef std::vector<edge_storage_t> edge_vector_t;
628 typedef std::vector<unsigned> dests_vector_t;
631 state_vector states_;
632 edge_vector_t edges_;
633 dests_vector_t dests_;
635 unsigned killed_edge_;
643 digraph(
unsigned max_states = 10,
unsigned max_trans = 0)
646 states_.reserve(max_states);
648 max_trans = max_states * 2;
649 edges_.reserve(max_trans + 1);
654 edges_[0].next_succ = 0;
660 return states_.size();
668 return edges_.size() - killed_edge_ - 1;
674 return dests_.empty();
682 template <
typename... Args>
685 state s = states_.size();
686 states_.emplace_back(std::forward<Args>(args)...);
696 template <
typename... Args>
699 state s = states_.size();
700 states_.reserve(s + n);
702 states_.emplace_back(std::forward<Args>(args)...);
717 const state_storage_t&
729 typename state_storage_t::data_t&
732 return states_[s].data();
735 const typename state_storage_t::data_t&
738 return states_[s].data();
753 const edge_storage_t&
765 typename edge_storage_t::data_t&
768 return edges_[s].data();
771 const typename edge_storage_t::data_t&
774 return edges_[s].data();
783 template <
typename... Args>
787 edge t = edges_.size();
788 edges_.emplace_back(dst, 0, src, std::forward<Args>(args)...);
790 edge st = states_[src].succ_tail;
791 SPOT_ASSERT(st < t || !st);
793 states_[src].succ = t;
795 edges_[st].next_succ = t;
796 states_[src].succ_tail = t;
807 template <
typename I>
811 unsigned sz = std::distance(dst_begin, dst_end);
815 unsigned d = dests_.size();
817 && &*dst_begin >= &dests_.front()
818 && &*dst_begin <= &dests_.back()
819 && (dests_.capacity() - dests_.size()) < (sz + 1))
824 std::vector<unsigned> tmp(dst_begin, dst_end);
825 dests_.emplace_back(sz);
826 dests_.insert(dests_.end(), tmp.begin(), tmp.end());
830 dests_.emplace_back(sz);
831 dests_.insert(dests_.end(), dst_begin, dst_end);
842 template <
typename I,
typename... Args>
847 std::forward<Args>(args)...);
855 template <
typename... Args>
861 std::forward<Args>(args)...);
869 const unsigned* d = dests_.data();
872 return { d + 1, d + num + 1 };
880 internal::const_universal_dests univ_dests(
const edge_storage_t& e)
const
882 return univ_dests(e.dst);
888 SPOT_ASSERT(!states_.empty());
889 return &ss - &states_.front();
895 SPOT_ASSERT(!edges_.empty());
896 return &
tt - &edges_.front();
904 return {
this, states_[src].succ};
916 return {
this, states_[src].succ};
933 return {
this, src.succ, src};
1001 return (t < edges_.size() &&
1002 edges_[t].next_succ != t);
1011 return edges_[t].next_succ == t;
1039 unsigned tend = edges_.size();
1040 for (
unsigned t = 1; t < tend; ++t)
1042 o <<
't' << t <<
": (s"
1043 << edges_[t].src <<
", ";
1044 int d = edges_[t].dst;
1049 o <<
") t" << edges_[t].next_succ <<
'\n';
1051 unsigned send = states_.size();
1052 for (
unsigned s = 0; s < send; ++s)
1054 o <<
's' << s <<
": t"
1055 << states_[s].succ <<
" t"
1056 << states_[s].succ_tail <<
'\n';
1058 unsigned dend = dests_.size();
1060 for (
unsigned s = 0; s < dend; ++s)
1062 o <<
'd' << s <<
": ";
1073 o << dests_[s] <<
'\n';
1077 enum dump_storage_items {
1078 DSI_GraphHeader = 1,
1079 DSI_GraphFooter = 2,
1080 DSI_StatesHeader = 4,
1082 DSI_StatesFooter = 16,
1083 DSI_States = DSI_StatesHeader | DSI_StatesBody | DSI_StatesFooter,
1084 DSI_EdgesHeader = 32,
1086 DSI_EdgesFooter = 128,
1087 DSI_Edges = DSI_EdgesHeader | DSI_EdgesBody | DSI_EdgesFooter,
1088 DSI_DestsHeader = 256,
1089 DSI_DestsBody = 512,
1090 DSI_DestsFooter = 1024,
1091 DSI_Dests = DSI_DestsHeader | DSI_DestsBody | DSI_DestsFooter,
1093 DSI_GraphHeader | DSI_States | DSI_Edges | DSI_Dests | DSI_GraphFooter,
1099 if (dsi & DSI_GraphHeader)
1100 o <<
"digraph g { \nnode [shape=plaintext]\n";
1101 unsigned send = states_.size();
1102 if (dsi & DSI_StatesHeader)
1104 o << (
"states [label=<\n"
1105 "<table border='0' cellborder='1' cellspacing='0'>\n"
1106 "<tr><td sides='b' bgcolor='yellow' port='s'>states</td>\n");
1107 for (
unsigned s = 0; s < send; ++s)
1108 o <<
"<td sides='b' bgcolor='yellow' port='s" << s <<
"'>"
1112 if (dsi & DSI_StatesBody)
1114 o <<
"<tr><td port='ss'>succ</td>\n";
1115 for (
unsigned s = 0; s < send; ++s)
1117 o <<
"<td port='ss" << s;
1118 if (states_[s].succ)
1119 o <<
"' bgcolor='cyan";
1120 o <<
"'>" << states_[s].succ <<
"</td>\n";
1122 o <<
"</tr><tr><td port='st'>succ_tail</td>\n";
1123 for (
unsigned s = 0; s < send; ++s)
1125 o <<
"<td port='st" << s;
1126 if (states_[s].succ_tail)
1127 o <<
"' bgcolor='cyan";
1128 o <<
"'>" << states_[s].succ_tail <<
"</td>\n";
1132 if (dsi & DSI_StatesFooter)
1133 o <<
"</table>>]\n";
1134 unsigned eend = edges_.size();
1135 if (dsi & DSI_EdgesHeader)
1137 o << (
"edges [label=<\n"
1138 "<table border='0' cellborder='1' cellspacing='0'>\n"
1139 "<tr><td sides='b' bgcolor='cyan' port='e'>edges</td>\n");
1140 for (
unsigned e = 1; e < eend; ++e)
1142 o <<
"<td sides='b' bgcolor='"
1143 << (e != edges_[e].next_succ ?
"cyan" :
"gray")
1144 <<
"' port='e" << e <<
"'>" << e <<
"</td>\n";
1148 if (dsi & DSI_EdgesBody)
1150 o <<
"<tr><td port='ed'>dst</td>\n";
1151 for (
unsigned e = 1; e < eend; ++e)
1153 o <<
"<td port='ed" << e;
1154 int d = edges_[e].dst;
1156 o <<
"' bgcolor='pink'>~" << ~d;
1158 o <<
"' bgcolor='yellow'>" << d;
1161 o <<
"</tr><tr><td port='en'>next_succ</td>\n";
1162 for (
unsigned e = 1; e < eend; ++e)
1164 o <<
"<td port='en" << e;
1165 if (edges_[e].next_succ)
1167 if (edges_[e].next_succ != e)
1168 o <<
"' bgcolor='cyan";
1170 o <<
"' bgcolor='gray";
1172 o <<
"'>" << edges_[e].next_succ <<
"</td>\n";
1174 o <<
"</tr><tr><td port='es'>src</td>\n";
1175 for (
unsigned e = 1; e < eend; ++e)
1176 o <<
"<td port='es" << e <<
"' bgcolor='yellow'>"
1177 << edges_[e].src <<
"</td>\n";
1180 if (dsi & DSI_EdgesFooter)
1181 o <<
"</table>>]\n";
1182 if (!dests_.empty())
1184 unsigned dend = dests_.size();
1185 if (dsi & DSI_DestsHeader)
1187 o << (
"dests [label=<\n"
1188 "<table border='0' cellborder='1' cellspacing='0'>\n"
1189 "<tr><td sides='b' bgcolor='pink' port='d'>dests</td>\n");
1193 o <<
"<td sides='b' bgcolor='pink' port='d"
1194 << d <<
"'>~" << d <<
"</td>\n";
1195 unsigned cnt = dests_[d];
1198 o <<
"<td sides='b'></td>\n";
1202 if (dsi & DSI_DestsBody)
1204 o <<
"<tr><td port='dd'>#cnt/dst</td>\n";
1208 unsigned cnt = dests_[d];
1209 o <<
"<td port='d'>#" << cnt <<
"</td>\n";
1213 o <<
"<td bgcolor='yellow' port='dd"
1214 << d <<
"'>" << dests_[d] <<
"</td>\n";
1220 if (dsi & DSI_DestsFooter)
1221 o <<
"</table>>]\n";
1223 if (dsi & DSI_GraphFooter)
1234 if (killed_edge_ == 0)
1236 auto i = std::remove_if(edges_.begin() + 1, edges_.end(),
1238 return this->is_dead_edge(t);
1240 edges_.erase(i, edges_.end());
1249 template<
class Predicate = std::less<edge_storage_t>>
1254 std::stable_sort(edges_.begin() + 1, edges_.end(), p);
1266 template<
class Predicate = std::less<edge_storage_t>>
1270 SPOT_ASSERT(!edges_.empty());
1272 std::vector<unsigned> idx_list(ns+1);
1273 edge_vector_t new_edges;
1274 new_edges.reserve(edges_.size());
1275 new_edges.resize(1);
1277 new_edges[0].next_succ = 0;
1279 for (
unsigned s = 0; s < ns; ++s)
1281 idx_list[s] = new_edges.size();
1282 for (
const auto& e :
out(s))
1283 new_edges.push_back(e);
1285 idx_list[ns] = new_edges.size();
1289 auto bne = new_edges.begin();
1290#ifndef SPOT_ENABLE_PTHREAD
1293 unsigned nthreads = ppolicy.nthreads();
1297 for (
unsigned s = 0u; s < ns; ++s)
1298 std::stable_sort(bne + idx_list[s],
1299 bne + idx_list[s+1], p);
1301#ifdef SPOT_ENABLE_PTHREAD
1304 static std::vector<std::thread> tv;
1305 SPOT_ASSERT(tv.empty());
1306 tv.resize(nthreads);
1311 for (
unsigned id = 0;
id < nthreads; ++id)
1312 tv[
id] = std::thread(
1313 [bne,
id, ns, &idx_list, p, nthreads]()
1315 for (
unsigned s =
id; s < ns; s += nthreads)
1316 std::stable_sort(bne + idx_list[s],
1317 bne + idx_list[s+1], p);
1325 std::swap(edges_, new_edges);
1336 template<
bool Stable = false,
class Predicate = std::less<edge_storage_t>>
1338 const std::vector<bool>* to_sort_ptr =
nullptr)
1340 SPOT_ASSERT((to_sort_ptr ==
nullptr)
1344 auto pi = [&](
unsigned t1,
unsigned t2)
1345 {
return p(edges_[t1], edges_[t2]); };
1349 std::vector<unsigned> sort_idx_;
1351 for (
unsigned i = 0; i < ns; ++i)
1353 if (to_sort_ptr && !(*to_sort_ptr)[i])
1355 unsigned t = states_[i].succ;
1361 sort_idx_.push_back(t);
1362 t = edges_[t].next_succ;
1364 if constexpr (Stable)
1365 std::stable_sort(sort_idx_.begin(), sort_idx_.end(), pi);
1367 std::sort(sort_idx_.begin(), sort_idx_.end(), pi);
1369 states_[i].succ = sort_idx_.front();
1370 states_[i].succ_tail = sort_idx_.back();
1371 const unsigned n_outs_n1 = sort_idx_.size() - 1;
1372 for (
unsigned k = 0; k < n_outs_n1; ++k)
1373 edges_[sort_idx_[k]].next_succ = sort_idx_[k+1];
1374 edges_[sort_idx_.back()].next_succ = 0;
1385 state last_src = -1U;
1386 edge tend = edges_.size();
1387 for (edge t = 1; t < tend; ++t)
1389 state src = edges_[t].src;
1390 if (src != last_src)
1392 states_[src].succ = t;
1393 if (last_src != -1U)
1395 states_[last_src].succ_tail = t - 1;
1396 edges_[t - 1].next_succ = 0;
1398 while (++last_src != src)
1400 states_[last_src].succ = 0;
1401 states_[last_src].succ_tail = 0;
1406 edges_[t - 1].next_succ = t;
1409 if (last_src != -1U)
1411 states_[last_src].succ_tail = tend - 1;
1412 edges_[tend - 1].next_succ = 0;
1414 unsigned send = states_.size();
1415 while (++last_src != send)
1417 states_[last_src].succ = 0;
1418 states_[last_src].succ_tail = 0;
1431 SPOT_ASSERT(newst.size() == states_.size());
1432 unsigned tend = edges_.size();
1433 for (
unsigned t = 1; t < tend; t++)
1435 edges_[t].dst = newst[edges_[t].dst];
1436 edges_[t].src = newst[edges_[t].src];
1458 SPOT_ASSERT(newst.size() >= states_.size());
1459 SPOT_ASSERT(used_states > 0);
1466 permute_vector(states_, newst);
1467 unsigned send = states_.size();
1468 for (state s = used_states; s < send; ++s)
1473 auto t = states_[s].succ;
1475 std::swap(t, edges_[t].next_succ);
1478 states_.resize(used_states);
1488 unsigned tend = edges_.size();
1489 std::vector<edge> newidx(tend);
1491 for (edge t = 1; t < tend; ++t)
1496 edges_[dest] = std::move(edges_[t]);
1500 edges_.resize(dest);
1504 for (edge t = 1; t < dest; ++t)
1506 auto& tr = edges_[t];
1507 tr.src = newst[tr.src];
1508 tr.dst = newst[tr.dst];
1509 tr.next_succ = newidx[tr.next_succ];
1513 for (
auto& s: states_)
1515 s.succ = newidx[s.succ];
1516 s.succ_tail = newidx[s.succ_tail];
A directed graph.
Definition: graph.hh:599
unsigned num_states() const
The number of states in the automaton.
Definition: graph.hh:658
const dests_vector_t & dests_vector() const
The vector used to store universal destinations.
Definition: graph.hh:1025
void dump_storage_as_dot(std::ostream &o, int dsi=DSI_All) const
Dump the state and edge storage for debugging.
Definition: graph.hh:1097
bool is_dead_edge(const edge_storage_t &t) const
Tests whether an edge has been erased.
Definition: graph.hh:1014
void dump_storage(std::ostream &o) const
Dump the state and edge storage for debugging.
Definition: graph.hh:1037
internal::state_out< digraph > out(state_storage_t &src)
Return a fake container with all edges leaving src.
Definition: graph.hh:908
internal::all_trans< digraph > edges()
Return a fake container with all edges (excluding erased edges)
Definition: graph.hh:966
dests_vector_t & dests_vector()
The vector used to store universal destinations.
Definition: graph.hh:1030
void sort_edges_of_(Predicate p=Predicate(), const std::vector< bool > *to_sort_ptr=nullptr)
Sort edges of the given states.
Definition: graph.hh:1337
state new_states(unsigned n, Args &&... args)
Create n new states.
Definition: graph.hh:697
state new_state(Args &&... args)
Create a new states.
Definition: graph.hh:683
edge index_of_edge(const edge_storage_t &tt) const
Convert a storage reference into an edge number.
Definition: graph.hh:893
const edge_vector_t & edge_vector() const
Return the vector of all edges.
Definition: graph.hh:980
internal::killer_edge_iterator< digraph > out_iteraser(state src)
Return a fake container with all edges leaving src, allowing erasure.
Definition: graph.hh:937
bool is_valid_edge(edge t) const
Test whether the given edge is valid.
Definition: graph.hh:997
internal::state_out< digraph > out(state src)
Return a fake container with all edges leaving src.
Definition: graph.hh:902
internal::state_out< const digraph > out(state_storage_t &src) const
Return a fake container with all edges leaving src.
Definition: graph.hh:920
void sort_edges_srcfirst_(Predicate p=Predicate(), parallel_policy ppolicy=parallel_policy())
Sort all edges by src first, then, within edges of the same source use the predicate.
Definition: graph.hh:1267
edge new_univ_edge(state src, const std::initializer_list< state > &dsts, Args &&... args)
Create a new universal edge.
Definition: graph.hh:857
bool is_existential() const
Whether the automaton uses only existential branching.
Definition: graph.hh:672
edge_vector_t & edge_vector()
Return the vector of all edges.
Definition: graph.hh:985
const state_storage_t::data_t & state_data(state s) const
return the State_Data associated to a state
Definition: graph.hh:736
internal::state_out< const digraph > out(state src) const
Return a fake container with all edges leaving src.
Definition: graph.hh:914
state_storage_t::data_t & state_data(state s)
return the State_Data associated to a state
Definition: graph.hh:730
void remove_dead_edges_()
Remove all dead edges.
Definition: graph.hh:1232
digraph(unsigned max_states=10, unsigned max_trans=0)
Construct an empty graph.
Definition: graph.hh:643
state new_univ_dests(I dst_begin, I dst_end)
Create a new universal destination group.
Definition: graph.hh:809
const edge_storage_t::data_t & edge_data(edge s) const
return the Edge_Data of an edge.
Definition: graph.hh:772
edge_storage_t & edge_storage(edge s)
return a reference to the storage of an edge
Definition: graph.hh:748
void rename_states_(const std::vector< unsigned > &newst)
Rename all the states in the edge vector.
Definition: graph.hh:1429
void defrag_states(const std::vector< unsigned > &newst, unsigned used_states)
Rename and remove states.
Definition: graph.hh:1456
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:931
const state_vector & states() const
Return the vector of states.
Definition: graph.hh:946
internal::all_trans< const digraph > edges() const
Return a fake container with all edges (excluding erased edges)
Definition: graph.hh:961
unsigned num_edges() const
The number of edges in the automaton.
Definition: graph.hh:666
edge_storage_t::data_t & edge_data(edge s)
return the Edge_Data of an edge.
Definition: graph.hh:766
state_storage_t & state_storage(state s)
return a reference to the storage of a state
Definition: graph.hh:712
state index_of_state(const state_storage_t &ss) const
Convert a storage reference into a state number.
Definition: graph.hh:886
void sort_edges_(Predicate p=Predicate())
Sort all edges according to a predicate.
Definition: graph.hh:1250
bool is_dead_edge(unsigned t) const
Tests whether an edge has been erased.
Definition: graph.hh:1009
edge new_univ_edge(state src, I dst_begin, I dst_end, Args &&... args)
Create a new universal edge.
Definition: graph.hh:844
void chain_edges_()
Reconstruct the chain of outgoing edges.
Definition: graph.hh:1383
const edge_storage_t & edge_storage(edge s) const
return a reference to the storage of an edge
Definition: graph.hh:754
edge new_edge(state src, state dst, Args &&... args)
Create a new edge.
Definition: graph.hh:785
state_vector & states()
Return the vector of states.
Definition: graph.hh:951
const state_storage_t & state_storage(state s) const
return a reference to the storage of a state
Definition: graph.hh:718
This class is used to tell parallel algorithms what resources they may use.
Definition: common.hh:155
Abstract class for states.
Definition: twa.hh:47
Definition: automata.hh:26