
https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Speed up iterations on line graph neighborhoods. * mln/core/line_graph_neighborhood_piter.hh (mln::line_graph_neighborhood_fwd_piter::neighbors_t) (mln::line_graph_neighborhood_bkd_piter::neighbors_t): New typedefs. (mln::line_graph_neighborhood_fwd_piter::first_) (mln::line_graph_neighborhood_fwd_piter::step_) (mln::line_graph_neighborhood_fwd_piter::adjacent_or_equal_to_p_ref_) (mln::line_graph_neighborhood_bkd_piter::first_) (mln::line_graph_neighborhood_bkd_piter::step_) (mln::line_graph_neighborhood_bkd_piter::adjacent_or_equal_to_p_ref_): Remove methods. (mln::line_graph_neighborhood_fwd_piter::id_) (mln::line_graph_neighborhood_bkd_piter::id_): Remove attributes. (mln::line_graph_neighborhood_fwd_piter::saved_p_ref_) (mln::line_graph_neighborhood_fwd_piter::neighbors_) (mln::line_graph_neighborhood_fwd_piter::i_) (mln::line_graph_neighborhood_bkd_piter::saved_p_ref_) (mln::line_graph_neighborhood_bkd_piter::neighbors_) (mln::line_graph_neighborhood_bkd_piter::i_): New attributes. (line_graph_neighborhood_fwd_piter) (line_graph_neighborhood_bkd_piter): Adjust ctors. (mln::line_graph_neighborhood_fwd_piter::p_ref) (mln::line_graph_neighborhood_fwd_piter::plg) (mln::line_graph_neighborhood_fwd_piter::neighbors) (mln::line_graph_neighborhood_bkd_piter::p_ref) (mln::line_graph_neighborhood_bkd_piter::plg) (mln::line_graph_neighborhood_bkd_piter::neighbors): New accessors. (mln::line_graph_neighborhood_fwd_piter::is_valid) (mln::line_graph_neighborhood_fwd_piter::invalidate) (mln::line_graph_neighborhood_fwd_piter::start) (mln::line_graph_neighborhood_fwd_piter::next_) (mln::line_graph_neighborhood_bkd_piter::is_valid) (mln::line_graph_neighborhood_bkd_piter::invalidate) (mln::line_graph_neighborhood_bkd_piter::start) (mln::line_graph_neighborhood_bkd_piter::next_): Change the algorithms used in these routines, so that they use a list of computed neighbors (new member neighbors_) instead of iterating over the whole set of edges. (mln::line_graph_neighborhood_fwd_piter::update_) (mln::line_graph_neighborhood_bkd_piter::update_): Adjust. * mln/core/line_graph_elt_neighborhood.hh: Catch up with the new interface of piters on line graph neighborhoods. (mln::line_graph_elt_neighborhood::neighbors_t): New typedef. (mln::line_graph_elt_neighborhood::start) (mln::line_graph_elt_neighborhood::next_): Remove methods. (mln::line_graph_elt_neighborhood::compute_neighbors_): New method. line_graph_elt_neighborhood.hh | 58 ++++---- line_graph_neighborhood_piter.hh | 262 ++++++++++++++++++--------------------- 2 files changed, 158 insertions(+), 162 deletions(-) Index: mln/core/line_graph_neighborhood_piter.hh --- mln/core/line_graph_neighborhood_piter.hh (revision 1854) +++ mln/core/line_graph_neighborhood_piter.hh (working copy) @@ -42,6 +42,8 @@ - mln::line_graph_window_bkd_piter - mln::line_graph_neighborhood_bkd_piter. */ +# include <set> + # include <mln/core/concept/point_iterator.hh> # include <mln/core/p_line_graph.hh> # include <mln/core/line_graph_psite.hh> @@ -80,6 +82,9 @@ // FIXME: Dummy typedef. typedef void mesh; + // The type of the set of neighbors (adjacent edge ids). + typedef std::set<util::edge_id> neighbors_t; + public: /// Construction. /// \{ @@ -114,28 +119,31 @@ /// Convert the iterator into a line graph psite. operator psite() const; + /// Return the reference psite. + const psite& p_ref() const; + /// Return the mln::p_line_graph corresponding to this piter. + const p_line_graph<P>& plg() const; + /// Return the set of neighbors (adjacent edge ids). + neighbors_t& neighbors(); + /// Read-only access to the \a i-th coordinate. // FIXME: Dummy. coord operator[](unsigned i) const; /// \} - /// Internals, used by the neighborhood. - /// \{ - public: - /// Set the iterator to the first site of the graph. - void first_(); - /// Advance the position of the iterator by one step. - void step_(); - - /// An internal iterator on the set of edges of the underlying graph. - util::edge_id id_; - /// \} - private: /// The neighborhood. const N& nbh_; /// The ``central'' psite of the neighborhood. const psite& p_ref_; + + /// The last reference psite whose ajacent psites have been computed. + psite saved_p_ref_; + /// The set of edge ids adjacent to the reference psite. + neighbors_t neighbors_; + /// An iterator on the set of adjacent edges. + neighbors_t::const_iterator i_; + /// The psite corresponding to this iterator. psite psite_; /// The point corresponding to this iterator. @@ -178,6 +186,9 @@ // FIXME: Dummy typedef. typedef void mesh; + // The type of the set of neighbors (adjacent edge ids). + typedef std::set<util::edge_id> neighbors_t; + public: /// Construction. /// \{ @@ -212,28 +223,31 @@ /// Convert the iterator into a line graph psite. operator psite() const; + /// Return the reference psite. + const psite& p_ref() const; + /// Return the mln::p_line_graph corresponding to this piter. + const p_line_graph<P>& plg() const; + /// Return the set of neighbors (adjacent edge ids). + neighbors_t& neighbors(); + /// Read-only access to the \a i-th coordinate. // FIXME: Dummy. coord operator[](unsigned i) const; /// \} - /// Internals, used by the neighborhood. - /// \{ - public: - /// Set the iterator to the first site of the graph. - void first_(); - /// Advance the position of the iterator by one step. - void step_(); - - /// An internal iterator on the set of edges of the underlying graph. - util::edge_id id_; - /// \} - private: /// The neighborhood. const N& nbh_; /// The ``central'' psite of the neighborhood. const psite& p_ref_; + + /// The last reference psite whose ajacent psites have been computed. + psite saved_p_ref_; + /// The set of edge ids adjacent to the reference psite. + neighbors_t neighbors_; + /// An iterator on the set of adjacent edges. + neighbors_t::const_reverse_iterator i_; + /// The psite corresponding to this iterator. psite psite_; /// The point corresponding to this iterator. @@ -260,7 +274,6 @@ | line_graph_neighborhood_fwd_piter<P, N>. | `------------------------------------------*/ - // FIXME: Currently, argument nbh is ignored. template <typename P, typename N> template <typename Pref> inline @@ -271,7 +284,7 @@ // Initialize psite_ to a dummy value. psite_() { - // Invalidate id_. + // Invalidate i_. invalidate(); } @@ -280,10 +293,14 @@ bool line_graph_neighborhood_fwd_piter<P, N>::is_valid() const { - // FIXME: We depend too much on the implementation of util::graph - // here. The util::graph should provide the service to abstract - // these manipulations. - return p_ref_.is_valid() && id_ < p_ref_.plg().gr_->nedges(); + return + // The reference point must be valid... + p_ref_.is_valid() + // ...and must not have changed since the neighborhood has been + // computed... + && p_ref_ == saved_p_ref_ + // ...and the iterator i_ must point a valid value. + && i_ != neighbors_.end(); } template <typename P, typename N> @@ -291,7 +308,7 @@ void line_graph_neighborhood_fwd_piter<P, N>::invalidate() { - id_ = -1; + i_ = neighbors_.end(); } template <typename P, typename N> @@ -299,7 +316,15 @@ void line_graph_neighborhood_fwd_piter<P, N>::start() { - nbh_.start(*this); + mln_precondition(p_ref_.is_valid()); + // Update the neighbors, if needed. + if (!saved_p_ref_.is_valid() || p_ref_ != saved_p_ref_) + { + saved_p_ref_ = p_ref_; + nbh_.compute_neighbors_(*this); + } + i_ = neighbors_.begin(); + // FIXME: We might move the is_valid condition within update_. if (is_valid()) update_(); } @@ -309,7 +334,10 @@ void line_graph_neighborhood_fwd_piter<P, N>::next_() { - nbh_.next_(*this); + // Ensure the p_ref_ has not changed. + mln_precondition(p_ref_ == saved_p_ref_); + ++i_; + // FIXME: We might move the is_valid condition within update_. if (is_valid()) update_(); } @@ -317,84 +345,58 @@ template <typename P, typename N> inline void - line_graph_neighborhood_fwd_piter<P, N>::first_() + line_graph_neighborhood_fwd_piter<P, N>::update_() { - id_ = 0; + // Update psite_. + psite_ = line_graph_psite<P>(plg(), *i_); } template <typename P, typename N> inline - void - line_graph_neighborhood_fwd_piter<P, N>::step_() + const P& + line_graph_neighborhood_fwd_piter<P, N>::to_point() const { - ++id_; + return p_; } - template <typename P, typename N> inline - bool - line_graph_neighborhood_fwd_piter<P, N>::adjacent_or_equal_to_p_ref_() const + const line_graph_psite<P>& + line_graph_neighborhood_fwd_piter<P, N>::to_psite() const { - // Check wether the iterator points to P_REF_. - if (id_ == p_ref_.id()) - return true; - - // Check whether the iterator is among the neighbors of P_REF_. - { - // Paranoid assertion. - assert (p_ref_.id() < p_ref_.plg().gr_->nedges()); - /* FIXME: We should have a convenient shortcut for these - repetitive accesses to p_ref_.plg().gr_ (e.g., a method gr() - or g() in this class. */ - const util::tracked_ptr<typename p_line_graph<P>::graph>& gr = - p_ref_.plg().gr_; - // Check whether the edge this iterator points to is adjacent to - // the one p_ref points to, by comparing their ajacent nodes. - /* FIXME: This is too low-level. Yet another service the graph - // should provide. */ - if (gr->edge(id_).n1() == gr->edge(p_ref_.id()).n1() || - gr->edge(id_).n1() == gr->edge(p_ref_.id()).n2() || - gr->edge(id_).n2() == gr->edge(p_ref_.id()).n1() || - gr->edge(id_).n2() == gr->edge(p_ref_.id()).n2()) - return true; - } - - // Otherwise, the iterator is not adjacent to P_REF_. - return false; + return psite_; } template <typename P, typename N> inline - void - line_graph_neighborhood_fwd_piter<P, N>::update_() + line_graph_neighborhood_fwd_piter<P, N>::operator line_graph_psite<P> () const { - // Update psite_. - psite_ = line_graph_psite<P>(p_ref_.plg(), id_); + mln_precondition(is_valid()); + return psite_; } template <typename P, typename N> inline - const P& - line_graph_neighborhood_fwd_piter<P, N>::to_point() const + const line_graph_psite<P>& + line_graph_neighborhood_fwd_piter<P, N>::p_ref() const { - return p_; + return p_ref_; } template <typename P, typename N> inline - const line_graph_psite<P>& - line_graph_neighborhood_fwd_piter<P, N>::to_psite() const + const p_line_graph<P>& + line_graph_neighborhood_fwd_piter<P, N>::plg() const { - return psite_; + return p_ref_.plg(); } template <typename P, typename N> inline - line_graph_neighborhood_fwd_piter<P, N>::operator line_graph_psite<P> () const + std::set<util::edge_id>& + line_graph_neighborhood_fwd_piter<P, N>::neighbors() { - mln_precondition(is_valid()); - return psite_; + return neighbors_; } template <typename P, typename N> @@ -420,7 +422,6 @@ | line_graph_neighborhood_bkd_piter<P, N>. | `------------------------------------------*/ - // FIXME: Currently, argument nbh is ignored. template <typename P, typename N> template <typename Pref> inline @@ -431,7 +432,7 @@ // Initialize psite_ to a dummy value. psite_() { - // Invalidate id_. + // Invalidate i_. invalidate(); } @@ -440,10 +441,14 @@ bool line_graph_neighborhood_bkd_piter<P, N>::is_valid() const { - // FIXME: We depend too much on the implementation of util::graph - // here. The util::graph should provide the service to abstract - // these manipulations. - return p_ref_.is_valid() && id_ < p_ref_.plg().gr_->nedges(); + return + // The reference point must be valid... + p_ref_.is_valid() + // ...and must not have changed since the neighborhood has been + // computed... + && p_ref_ == saved_p_ref_ + // ...and the iterator i_ must point a valid value. + && i_ != neighbors_.rend(); } template <typename P, typename N> @@ -451,7 +456,7 @@ void line_graph_neighborhood_bkd_piter<P, N>::invalidate() { - id_ = -1; + i_ = neighbors_.rend(); } template <typename P, typename N> @@ -459,7 +464,15 @@ void line_graph_neighborhood_bkd_piter<P, N>::start() { - nbh_.start(*this); + mln_precondition(p_ref_.is_valid()); + // Update the neighbors, if needed. + if (!saved_p_ref_.is_valid() || p_ref_ != saved_p_ref_) + { + saved_p_ref_ = p_ref_; + nbh_.compute_neighbors_(*this); + } + i_ = neighbors_.rbegin(); + // FIXME: We might move the is_valid condition within update_. if (is_valid()) update_(); } @@ -469,7 +482,10 @@ void line_graph_neighborhood_bkd_piter<P, N>::next_() { - nbh_.next_(*this); + // Ensure the p_ref_ has not changed. + mln_precondition(p_ref_ == saved_p_ref_); + ++i_; + // FIXME: We might move the is_valid condition within update_. if (is_valid()) update_(); } @@ -477,84 +493,58 @@ template <typename P, typename N> inline void - line_graph_neighborhood_bkd_piter<P, N>::first_() + line_graph_neighborhood_bkd_piter<P, N>::update_() { - id_ = p_ref_.plg().gr_->nedges() - 1; + // Update psite_. + psite_ = line_graph_psite<P>(plg(), *i_); } template <typename P, typename N> inline - void - line_graph_neighborhood_bkd_piter<P, N>::step_() + const P& + line_graph_neighborhood_bkd_piter<P, N>::to_point() const { - --id_; + return p_; } - template <typename P, typename N> inline - bool - line_graph_neighborhood_bkd_piter<P, N>::adjacent_or_equal_to_p_ref_() const + const line_graph_psite<P>& + line_graph_neighborhood_bkd_piter<P, N>::to_psite() const { - // Check wether the iterator points to P_REF_. - if (id_ == p_ref_.id()) - return true; - - // Check whether the iterator is among the neighbors of P_REF_. - { - // Paranoid assertion. - assert (p_ref_.id() < p_ref_.plg().gr_->nedges()); - /* FIXME: We should have a convenient shortcut for these - repetitive accesses to p_ref_.plg().gr_ (e.g., a method gr() - or g() in this class. */ - const util::tracked_ptr<typename p_line_graph<P>::graph>& gr = - p_ref_.plg().gr_; - // Check whether the edge this iterator points to is adjacent to - // the one p_ref points to, by comparing their ajacent nodes. - /* FIXME: This is too low-level. Yet another service the graph - // should provide. */ - if (gr->edge(id_).n1() == gr->edge(p_ref_.id()).n1() || - gr->edge(id_).n1() == gr->edge(p_ref_.id()).n2() || - gr->edge(id_).n2() == gr->edge(p_ref_.id()).n1() || - gr->edge(id_).n2() == gr->edge(p_ref_.id()).n2()) - return true; - } - - // Otherwise, the iterator is not adjacent to P_REF_. - return false; + return psite_; } template <typename P, typename N> inline - void - line_graph_neighborhood_bkd_piter<P, N>::update_() + line_graph_neighborhood_bkd_piter<P, N>::operator line_graph_psite<P> () const { - // Update psite_. - psite_ = line_graph_psite<P>(p_ref_.plg(), id_); + mln_precondition(is_valid()); + return psite_; } template <typename P, typename N> inline - const P& - line_graph_neighborhood_bkd_piter<P, N>::to_point() const + const line_graph_psite<P>& + line_graph_neighborhood_bkd_piter<P, N>::p_ref() const { - return p_; + return p_ref_; } template <typename P, typename N> inline - const line_graph_psite<P>& - line_graph_neighborhood_bkd_piter<P, N>::to_psite() const + const p_line_graph<P>& + line_graph_neighborhood_bkd_piter<P, N>::plg() const { - return psite_; + return p_ref_.plg(); } template <typename P, typename N> inline - line_graph_neighborhood_bkd_piter<P, N>::operator line_graph_psite<P> () const + std::set<util::edge_id>& + line_graph_neighborhood_bkd_piter<P, N>::neighbors() { - mln_precondition(is_valid()); - return psite_; + return neighbors_; } template <typename P, typename N> Index: mln/core/line_graph_elt_neighborhood.hh --- mln/core/line_graph_elt_neighborhood.hh (revision 1854) +++ mln/core/line_graph_elt_neighborhood.hh (working copy) @@ -29,7 +29,7 @@ # define MLN_CORE_LINE_GRAPH_ELT_NEIGHBORHOOD_HH /// \file mln/core/line_graph_elt_neighborhood.hh -/// \brief Definition of the elementary ``window'' on a line graph. +/// \brief Definition of the elementary ``neighborhood'' on a line graph. /* FIXME: Have a consistent naming: we have window (without '_') but point_, neighb_, etc. */ @@ -40,6 +40,8 @@ - mln::line_graph_elt_window - mln::line_graph_elt_neighborhood. */ +# include <set> + # include <mln/core/concept/neighborhood.hh> # include <mln/core/line_graph_psite.hh> # include <mln/core/line_graph_neighborhood_piter.hh> @@ -66,6 +68,9 @@ typedef P point; /// The type of psite corresponding to the neighborhood. typedef line_graph_psite<P> psite; + // The type of the set of neighbors (edge ids adjacent to the + // reference psite). + typedef std::set<util::edge_id> neighbors_t; // FIXME: This is a dummy value. typedef void dpoint; @@ -84,43 +89,44 @@ /// Services for iterators. /// \{ - /// Move \a piter to the beginning of the iteration on this neighborhood. - template <typename Piter> - void start(Point_Iterator<Piter>& piter) const; - /// Move \a piter to the next site on this neighborhood. template <typename Piter> - void next_(Point_Iterator<Piter>& piter) const; + void compute_neighbors_(Point_Iterator<Piter>& piter) const; /// \} }; -# ifndef MLN_INCLUDE_ONLY - template <typename P> - template <typename Piter> - inline - void - line_graph_elt_neighborhood<P>::start(Point_Iterator<Piter>& piter_) const - { - Piter& piter = exact(piter_); - piter.first_(); - if (!piter.adjacent_or_equal_to_p_ref_()) - next_(piter); - } + +# ifndef MLN_INCLUDE_ONLY template <typename P> template <typename Piter> inline void - line_graph_elt_neighborhood<P>::next_(Point_Iterator<Piter>& piter_) const + line_graph_elt_neighborhood<P>::compute_neighbors_(Point_Iterator<Piter>& piter_) const { Piter& piter = exact(piter_); - /* FIXME: This is inefficient. The graph structure should be able - to produce the set of adjacent nodes fast. Boost Graphs - probably provides adequates structures to fetch these - neighbors in constant time. */ - do - piter.step_(); - while (piter.is_valid() && !piter.adjacent_or_equal_to_p_ref_()); + neighbors_t& neighbors = piter.neighbors(); + neighbors.clear(); + // Add the reference piter itself. We might reconsider this, or + // create an elementary neighbors without the reference point. + neighbors.insert(piter.p_ref().id()); + /* FIXME: Move this computation out of the window. In fact, + this should be a service of the graph, also proposed by the + p_line_graph. */ + // Ajacent edges connected through node 1. + // FIXME: Far too low-level. + util::node_id id1 = piter.p_ref().first_id(); + const util::node<P>& node1 = piter.plg().gr_->node(id1); + for (std::vector<util::edge_id>::const_iterator e = + node1.edges.begin(); e != node1.edges.end(); ++e) + neighbors.insert(*e); + // Ajacent edges connected through node 2. + // FIXME: Likewise. + util::node_id id2 = piter.p_ref().second_id(); + const util::node<P>& node2 = piter.plg().gr_->node(id2); + for (std::vector<util::edge_id>::const_iterator e = + node2.edges.begin(); e != node2.edges.end(); ++e) + neighbors.insert(*e); } # endif // ! MLN_INCLUDE_ONLY