Commit 9d6941f0 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

* spot/graph/graph.hh: More Doxygen comments.

parent 5e47d4df
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement // Copyright (C) 2014, 2015, 2016 Laboratoire de Recherche et
// de l'Epita. // Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -553,11 +553,14 @@ namespace spot ...@@ -553,11 +553,14 @@ namespace spot
} }
}; };
} } // namespace internal
// The actual graph implementation /// \brief A directed graph
///
/// \tparam State_Data data to attach to states
/// \tparam Edge_Data data to attach to edges
/// \tparam Alternating whether the automaton should be alternating
template <typename State_Data, typename Edge_Data, bool Alternating> template <typename State_Data, typename Edge_Data, bool Alternating>
class digraph class digraph
{ {
...@@ -569,6 +572,7 @@ namespace spot ...@@ -569,6 +572,7 @@ namespace spot
typedef internal::edge_iterator<digraph> iterator; typedef internal::edge_iterator<digraph> iterator;
typedef internal::edge_iterator<const digraph> const_iterator; typedef internal::edge_iterator<const digraph> const_iterator;
/// Whether the automaton is alternating
static constexpr bool alternating() static constexpr bool alternating()
{ {
return Alternating; return Alternating;
...@@ -603,7 +607,7 @@ namespace spot ...@@ -603,7 +607,7 @@ namespace spot
// Number of erased edges. // Number of erased edges.
unsigned killed_edge_; unsigned killed_edge_;
public: public:
/// \brief construct an empty graph /// \brief Construct an empty graph
/// ///
/// Construct an empty graph, and reserve space for \a max_states /// Construct an empty graph, and reserve space for \a max_states
/// states and \a max_trans edges. These are not hard /// states and \a max_trans edges. These are not hard
...@@ -623,24 +627,25 @@ namespace spot ...@@ -623,24 +627,25 @@ namespace spot
edges_[0].next_succ = 0; edges_[0].next_succ = 0;
} }
/// The number of states in the automaton
unsigned num_states() const unsigned num_states() const
{ {
return states_.size(); return states_.size();
} }
/// \brief The number of edges in the automaton
///
/// Killed edges are omitted.
unsigned num_edges() const unsigned num_edges() const
{ {
return edges_.size() - killed_edge_ - 1; return edges_.size() - killed_edge_ - 1;
} }
bool valid_trans(edge t) const /// \brief Create a new states
{ ///
// Erased edges have their next_succ pointing to /// All arguments are forwarded to the State_Data constructor.
// themselves. ///
return (t < edges_.size() && /// \return a state number
edges_[t].next_succ != t);
}
template <typename... Args> template <typename... Args>
state new_state(Args&&... args) state new_state(Args&&... args)
{ {
...@@ -649,6 +654,12 @@ namespace spot ...@@ -649,6 +654,12 @@ namespace spot
return s; return s;
} }
/// \brief Create n new states
///
/// All arguments are forwarded to the State_Data constructor of
/// each of the n states.
///
/// \return the first state number
template <typename... Args> template <typename... Args>
state new_states(unsigned n, Args&&... args) state new_states(unsigned n, Args&&... args)
{ {
...@@ -659,6 +670,11 @@ namespace spot ...@@ -659,6 +670,11 @@ namespace spot
return s; return s;
} }
/// @{
/// \brief return a reference to the storage of a state
///
/// The storage includes any of the user-supplied State_Data, plus
/// some custom fields needed to find the outgoing transitions.
state_storage_t& state_storage_t&
state_storage(state s) state_storage(state s)
{ {
...@@ -672,9 +688,13 @@ namespace spot ...@@ -672,9 +688,13 @@ namespace spot
assert(s < states_.size()); assert(s < states_.size());
return states_[s]; return states_[s];
} }
///@}
// Do not use State_Data& as return type, because State_Data might ///@{
// be void. /// \brief return the State_Data associated to a state
///
/// This does not use State_Data& as return type, because
/// State_Data might be void.
typename state_storage_t::data_t& typename state_storage_t::data_t&
state_data(state s) state_data(state s)
{ {
...@@ -682,14 +702,19 @@ namespace spot ...@@ -682,14 +702,19 @@ namespace spot
return states_[s].data(); return states_[s].data();
} }
// May not be called on states with no data.
const typename state_storage_t::data_t& const typename state_storage_t::data_t&
state_data(state s) const state_data(state s) const
{ {
assert(s < states_.size()); assert(s < states_.size());
return states_[s].data(); return states_[s].data();
} }
///@}
///@{
/// \brief return a reference to the storage of an edge
///
/// The storage includes any of the user-supplied Edge_Data, plus
/// some custom fields needed to find the next transitions.
edge_storage_t& edge_storage_t&
edge_storage(edge s) edge_storage(edge s)
{ {
...@@ -703,7 +728,13 @@ namespace spot ...@@ -703,7 +728,13 @@ namespace spot
assert(s < edges_.size()); assert(s < edges_.size());
return edges_[s]; return edges_[s];
} }
///@}
///@{
/// \brief return the Edgeg_Data of an edge.
///
/// This does not use Edge_Data& as return type, because
/// Edge_Data might be void.
typename edge_storage_t::data_t& typename edge_storage_t::data_t&
edge_data(edge s) edge_data(edge s)
{ {
...@@ -717,7 +748,13 @@ namespace spot ...@@ -717,7 +748,13 @@ namespace spot
assert(s < edges_.size()); assert(s < edges_.size());
return edges_[s].data(); return edges_[s].data();
} }
///@}
/// \brief Create a new edge
///
/// \param src the source state
/// \param dst the destination state
/// \param args arguments to forward to the Edge_Data constructor
template <typename... Args> template <typename... Args>
edge edge
new_edge(state src, out_state dst, Args&&... args) new_edge(state src, out_state dst, Args&&... args)
...@@ -737,18 +774,22 @@ namespace spot ...@@ -737,18 +774,22 @@ namespace spot
return t; return t;
} }
/// Convert a storage reference into a state number
state index_of_state(const state_storage_t& ss) const state index_of_state(const state_storage_t& ss) const
{ {
assert(!states_.empty()); assert(!states_.empty());
return &ss - &states_.front(); return &ss - &states_.front();
} }
/// Conveart a storage reference into an edge number
edge index_of_edge(const edge_storage_t& tt) const edge index_of_edge(const edge_storage_t& tt) const
{ {
assert(!edges_.empty()); assert(!edges_.empty());
return &tt - &edges_.front(); return &tt - &edges_.front();
} }
/// @{
/// \brief Return a fake container with all edges leaving \a src
internal::state_out<digraph> internal::state_out<digraph>
out(state src) out(state src)
{ {
...@@ -772,7 +813,12 @@ namespace spot ...@@ -772,7 +813,12 @@ namespace spot
{ {
return out(index_of_state(src)); return out(index_of_state(src));
} }
/// @}
/// @{
///
/// \brief Return a fake container with all edges leaving \a src,
/// allowing erasure.
internal::killer_edge_iterator<digraph> internal::killer_edge_iterator<digraph>
out_iteraser(state_storage_t& src) out_iteraser(state_storage_t& src)
{ {
...@@ -784,7 +830,11 @@ namespace spot ...@@ -784,7 +830,11 @@ namespace spot
{ {
return out_iteraser(state_storage(src)); return out_iteraser(state_storage(src));
} }
///@}
/// @{
///
/// \brief Return the vector of states.
const state_vector& states() const const state_vector& states() const
{ {
return states_; return states_;
...@@ -794,7 +844,12 @@ namespace spot ...@@ -794,7 +844,12 @@ namespace spot
{ {
return states_; return states_;
} }
/// @}
/// @{
///
/// \brief Return a fake container with all edges (exluding erased
/// edges)
internal::all_trans<const digraph> edges() const internal::all_trans<const digraph> edges() const
{ {
return edges_; return edges_;
...@@ -804,12 +859,16 @@ namespace spot ...@@ -804,12 +859,16 @@ namespace spot
{ {
return edges_; return edges_;
} }
/// @}
// When using this method, beware that the first entry (edge /// @{
// #0) is not a real edge, and that any edge with /// \brief Return the vector of all edges.
// next_succ pointing to itself is an erased edge. ///
// /// When using this method, beware that the first entry (edge #0)
// You should probably use edges() instead. /// is not a real edge, and that any edge with next_succ pointing
/// to itself is an erased edge.
///
/// You should probably use edges() instead.
const edge_vector_t& edge_vector() const const edge_vector_t& edge_vector() const
{ {
return edges_; return edges_;
...@@ -819,7 +878,26 @@ namespace spot ...@@ -819,7 +878,26 @@ namespace spot
{ {
return edges_; return edges_;
} }
/// @}
/// \brief Test whether the given edge is valid.
///
/// An edge is valid if its number is less than the total number
/// of edges, and it does not correspond to an erased (dead) edge.
///
/// \see is_dead_edge()
bool is_valid_edge(edge t) const
{
// Erased edges have their next_succ pointing to
// themselves.
return (t < edges_.size() &&
edges_[t].next_succ != t);
}
/// @{
/// \brief Tests whether an edge has been erased.
///
/// \see is_valid_edge
bool is_dead_edge(unsigned t) const bool is_dead_edge(unsigned t) const
{ {
return edges_[t].next_succ == t; return edges_[t].next_succ == t;
...@@ -829,9 +907,10 @@ namespace spot ...@@ -829,9 +907,10 @@ namespace spot
{ {
return t.next_succ == index_of_edge(t); return t.next_succ == index_of_edge(t);
} }
/// @}
// To help debugging /// Dump the state and edge storage for debugging
void dump_storage(std::ostream& o) const void dump_storage(std::ostream& o) const
{ {
unsigned tend = edges_.size(); unsigned tend = edges_.size();
...@@ -851,10 +930,11 @@ namespace spot ...@@ -851,10 +930,11 @@ namespace spot
} }
} }
// Remove all dead edges. The edges_ vector is left /// \brief Remove all dead edges.
// in a state that is incorrect and should eventually be fixed by ///
// a call to chain_edges_() before any iteration on the /// The edges_ vector is left in a state that is incorrect and
// successor of a state is performed. /// should eventually be fixed by a call to chain_edges_() before
/// any iteration on the successor of a state is performed.
void remove_dead_edges_() void remove_dead_edges_()
{ {
if (killed_edge_ == 0) if (killed_edge_ == 0)
...@@ -867,9 +947,11 @@ namespace spot ...@@ -867,9 +947,11 @@ namespace spot
killed_edge_ = 0; killed_edge_ = 0;
} }
// This will invalidate all iterators, and also destroy edge /// \brief Sort all edge according to a predicate
// chains. Call chain_edges_() immediately afterwards ///
// unless you know what you are doing. /// This will invalidate all iterators, and also destroy edge
/// chains. Call chain_edges_() immediately afterwards unless you
/// know what you are doing.
template<class Predicate = std::less<edge_storage_t>> template<class Predicate = std::less<edge_storage_t>>
void sort_edges_(Predicate p = Predicate()) void sort_edges_(Predicate p = Predicate())
{ {
...@@ -878,8 +960,10 @@ namespace spot ...@@ -878,8 +960,10 @@ namespace spot
std::stable_sort(edges_.begin() + 1, edges_.end(), p); std::stable_sort(edges_.begin() + 1, edges_.end(), p);
} }
// Should be called only when it is known that all edges /// \brief Reconstruct the chain of outgoing edges
// with the same destination are consecutive in the vector. ///
/// Should be called only when it is known that all edges
/// with the same destination are consecutive in the vector.
void chain_edges_() void chain_edges_()
{ {
state last_src = -1U; state last_src = -1U;
...@@ -921,10 +1005,11 @@ namespace spot ...@@ -921,10 +1005,11 @@ namespace spot
//dump_storage(std::cerr); //dump_storage(std::cerr);
} }
// Rename all the states in the edge vector. The /// \brief Rename all the states in the edge vector.
// edges_ vector is left in a state that is incorrect and ///
// should eventually be fixed by a call to chain_edges_() /// The edges_ vector is left in a state that is incorrect and
// before any iteration on the successor of a state is performed. /// should eventually be fixed by a call to chain_edges_() before
/// any iteration on the successor of a state is performed.
void rename_states_(const std::vector<unsigned>& newst) void rename_states_(const std::vector<unsigned>& newst)
{ {
assert(newst.size() == states_.size()); assert(newst.size() == states_.size());
...@@ -936,6 +1021,11 @@ namespace spot ...@@ -936,6 +1021,11 @@ namespace spot
} }
} }
/// \brief Rename and remove states.
///
/// \param newst A vector indicating how each state should be renumbered.
/// Use -1U to erase a state.
/// \param the number of states used (after renumbering)
void defrag_states(std::vector<unsigned>&& newst, unsigned used_states) void defrag_states(std::vector<unsigned>&& newst, unsigned used_states)
{ {
assert(newst.size() == states_.size()); assert(newst.size() == states_.size());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment