diff --git a/lemon/elevator.h b/lemon/elevator.h new file mode 100644 --- /dev/null +++ b/lemon/elevator.h @@ -0,0 +1,1003 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2008 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_ELEVATOR_H +#define LEMON_ELEVATOR_H + +///\ingroup auxdat +///\file +///\brief Elevator class +/// +///Elevator class implements an efficient data structure +///for labeling items in push-relabel type algorithms. +/// + +#include +namespace lemon { + + ///Class for handling "labels" in push-relabel type algorithms. + + ///A class for handling "labels" in push-relabel type algorithms. + /// + ///\ingroup auxdat + ///Using this class you can assign "labels" (nonnegative integer numbers) + ///to the edges or nodes of a graph, manipulate and query them through + ///operations typically arising in "push-relabel" type algorithms. + /// + ///Each item is either \em active or not, and you can also choose a + ///highest level active item. + /// + ///\sa LinkedElevator + /// + ///\param Graph the underlying graph type + ///\param Item Type of the items the data is assigned to (Graph::Node, + ///Graph::Edge, Graph::UEdge) + template + class Elevator + { + public: + + typedef Item Key; + typedef int Value; + + private: + + typedef typename std::vector::iterator Vit; + typedef typename ItemSetTraits::template Map::Type VitMap; + typedef typename ItemSetTraits::template Map::Type IntMap; + + const Graph &_g; + int _max_level; + int _item_num; + VitMap _where; + IntMap _level; + std::vector _items; + std::vector _first; + std::vector _last_active; + + int _highest_active; + + void copy(Item i, Vit p) + { + _where[*p=i]=p; + } + void copy(Vit s, Vit p) + { + if(s!=p) + { + Item i=*s; + *p=i; + _where[i]=p; + } + } + void swap(Vit i, Vit j) + { + Item ti=*i; + Vit ct = _where[ti]; + _where[ti]=_where[*i=*j]; + _where[*j]=ct; + *j=ti; + } + + public: + + ///Constructor with given maximum level. + + ///Constructor with given maximum level. + /// + ///\param g The underlying graph + ///\param max_level Set the range of the possible labels to + ///[0...\c max_level] + Elevator(const Graph &g,int max_level) : + _g(g), + _max_level(max_level), + _item_num(_max_level), + _where(g), + _level(g,0), + _items(_max_level), + _first(_max_level+2), + _last_active(_max_level+2), + _highest_active(-1) {} + ///Constructor. + + ///Constructor. + /// + ///\param g The underlying graph + ///The range of the possible labels is [0...\c max_level], + ///where \c max_level is equal to the number of labeled items in the graph. + Elevator(const Graph &g) : + _g(g), + _max_level(countItems(g)), + _item_num(_max_level), + _where(g), + _level(g,0), + _items(_max_level), + _first(_max_level+2), + _last_active(_max_level+2), + _highest_active(-1) + { + } + + ///Activate item \c i. + + ///Activate item \c i. + ///\pre Item \c i shouldn't be active before. + void activate(Item i) + { + const int l=_level[i]; + swap(_where[i],++_last_active[l]); + if(l>_highest_active) _highest_active=l; + } + + ///Deactivate item \c i. + + ///Deactivate item \c i. + ///\pre Item \c i must be active before. + void deactivate(Item i) + { + swap(_where[i],_last_active[_level[i]]--); + while(_highest_active>=0 && + _last_active[_highest_active]<_first[_highest_active]) + _highest_active--; + } + + ///Query whether item \c i is active + bool active(Item i) const { return _where[i]<=_last_active[_level[i]]; } + + ///Return the level of item \c i. + int operator[](Item i) const { return _level[i]; } + + ///Return the number of items on level \c l. + int onLevel(int l) const + { + return _first[l+1]-_first[l]; + } + ///Return true if the level is empty. + bool emptyLevel(int l) const + { + return _first[l+1]-_first[l]==0; + } + ///Return the number of items above level \c l. + int aboveLevel(int l) const + { + return _first[_max_level+1]-_first[l+1]; + } + ///Return the number of active items on level \c l. + int activesOnLevel(int l) const + { + return _last_active[l]-_first[l]+1; + } + ///Return true if there is not active item on level \c l. + bool activeFree(int l) const + { + return _last_active[l]<_first[l]; + } + ///Return the maximum allowed level. + int maxLevel() const + { + return _max_level; + } + + ///\name Highest Active Item + ///Functions for working with the highest level + ///active item. + + ///@{ + + ///Return a highest level active item. + + ///Return a highest level active item. + /// + ///\return the highest level active item or INVALID if there is no active + ///item. + Item highestActive() const + { + return _highest_active>=0?*_last_active[_highest_active]:INVALID; + } + + ///Return a highest active level. + + ///Return a highest active level. + /// + ///\return the level of the highest active item or -1 if there is no active + ///item. + int highestActiveLevel() const + { + return _highest_active; + } + + ///Lift the highest active item by one. + + ///Lift the item returned by highestActive() by one. + /// + void liftHighestActive() + { + ++_level[*_last_active[_highest_active]]; + swap(_last_active[_highest_active]--,_last_active[_highest_active+1]); + --_first[++_highest_active]; + } + + ///Lift the highest active item. + + ///Lift the item returned by highestActive() to level \c new_level. + /// + ///\warning \c new_level must be strictly higher + ///than the current level. + /// + void liftHighestActive(int new_level) + { + const Item li = *_last_active[_highest_active]; + + copy(--_first[_highest_active+1],_last_active[_highest_active]--); + for(int l=_highest_active+1;l=0 && + _last_active[_highest_active]<_first[_highest_active]) + _highest_active--; + } + + ///@} + + ///\name Active Item on Certain Level + ///Functions for working with the active items. + + ///@{ + + ///Returns an active item on level \c l. + + ///Returns an active item on level \c l. + /// + ///Returns an active item on level \c l or \ref INVALID if there is no such + ///an item. (\c l must be from the range [0...\c max_level]. + Item activeOn(int l) const + { + return _last_active[l]>=_first[l]?*_last_active[l]:INVALID; + } + + ///Lifts the active item returned by \c activeOn() member function. + + ///Lifts the active item returned by \c activeOn() member function + ///by one. + Item liftActiveOn(int level) + { + ++_level[*_last_active[level]]; + swap(_last_active[level]--, --_first[level+1]); + if (level+1>_highest_active) ++_highest_active; + } + + ///Lifts the active item returned by \c activeOn() member function. + + ///Lifts the active item returned by \c activeOn() member function + ///to the given level. + void liftActiveOn(int level, int new_level) + { + const Item ai = *_last_active[level]; + + copy(--_first[level+1], _last_active[level]--); + for(int l=level+1;l_highest_active) _highest_active=new_level; + } + + ///Lifts the active item returned by \c activeOn() member function. + + ///Lifts the active item returned by \c activeOn() member function + ///to the top level. + void liftActiveToTop(int level) + { + const Item ai = *_last_active[level]; + + copy(--_first[level+1],_last_active[level]--); + for(int l=level+1;l<_max_level;l++) + { + copy(_last_active[l],_first[l]); + copy(--_first[l+1], _last_active[l]--); + } + copy(ai,_first[_max_level]); + --_last_active[_max_level]; + _level[ai]=_max_level; + + if (_highest_active==level) { + while(_highest_active>=0 && + _last_active[_highest_active]<_first[_highest_active]) + _highest_active--; + } + } + + ///@} + + ///Lift an active item to a higher level. + + ///Lift an active item to a higher level. + ///\param i The item to be lifted. It must be active. + ///\param new_level The new level of \c i. It must be strictly higher + ///than the current level. + /// + void lift(Item i, int new_level) + { + const int lo = _level[i]; + const Vit w = _where[i]; + + copy(_last_active[lo],w); + copy(--_first[lo+1],_last_active[lo]--); + for(int l=lo+1;l_highest_active) _highest_active=new_level; + } + + ///Mark the node as it did not reach the max level + + ///Mark the node as it did not reach the max level. It sets the + ///level to the under the max level value. The node will be never + ///more activated because the push operation from the maximum + ///level is forbidden in the push-relabel algorithms. The node + ///should be lifted previously to the top level. + void markToBottom(Item i) { + _level[i] = _max_level - 1; + } + + ///Lift all nodes on and above a level to the top (and deactivate them). + + ///This function lifts all nodes on and above level \c l to \c + ///maxLevel(), and also deactivates them. + void liftToTop(int l) + { + const Vit f=_first[l]; + const Vit tl=_first[_max_level]; + for(Vit i=f;i!=tl;++i) + _level[*i]=_max_level; + for(int i=l;i<=_max_level;i++) + { + _first[i]=f; + _last_active[i]=f-1; + } + for(_highest_active=l-1; + _highest_active>=0 && + _last_active[_highest_active]<_first[_highest_active]; + _highest_active--) ; + } + + private: + int _init_lev; + Vit _init_num; + + public: + + ///\name Initialization + ///Using this function you can initialize the levels of the item. + ///\n + ///This initializatios is started with calling \c initStart(). + ///Then the + ///items should be listed levels by levels statring with the lowest one + ///(with level 0). This is done by using \c initAddItem() + ///and \c initNewLevel(). Finally \c initFinish() must be called. + ///The items not listed will be put on the highest level. + ///@{ + + ///Start the initialization process. + + void initStart() + { + _init_lev=0; + _init_num=_items.begin(); + _first[0]=_items.begin(); + _last_active[0]=_items.begin()-1; + Vit n=_items.begin(); + for(typename ItemSetTraits::ItemIt i(_g);i!=INVALID;++i) + { + *n=i; + _where[i]=n; + _level[i]=_max_level; + ++n; + } + } + + ///Add an item to the current level. + + void initAddItem(Item i) + { + swap(_where[i],_init_num); + _level[i]=_init_lev; + ++_init_num; + } + + ///Start a new level. + + ///Start a new level. + ///It shouldn't be used before the items on level 0 are listed. + void initNewLevel() + { + _init_lev++; + _first[_init_lev]=_init_num; + _last_active[_init_lev]=_init_num-1; + } + + ///Finalize the initialization process. + + void initFinish() + { + for(_init_lev++;_init_lev<=_max_level;_init_lev++) + { + _first[_init_lev]=_init_num; + _last_active[_init_lev]=_init_num-1; + } + _first[_max_level+1]=_items.begin()+_item_num; + _last_active[_max_level+1]=_items.begin()+_item_num-1; + _highest_active = -1; + } + + ///@} + + }; + + ///Class for handling "labels" in push-relabel type algorithms. + + ///A class for handling "labels" in push-relabel type algorithms. + /// + ///\ingroup auxdat + ///Using this class you can assign "labels" (nonnegative integer numbers) + ///to the edges or nodes of a graph, manipulate and query them through + ///operations typically arising in "push-relabel" type algorithms. + /// + ///Each item is either \em active or not, and you can also choose a + ///highest level active item. + /// + ///\sa Elevator + /// + ///\param Graph the underlying graph type + ///\param Item Type of the items the data is assigned to (Graph::Node, + ///Graph::Edge, Graph::UEdge) + template + class LinkedElevator { + public: + + typedef Item Key; + typedef int Value; + + private: + + typedef typename ItemSetTraits:: + template Map::Type ItemMap; + typedef typename ItemSetTraits:: + template Map::Type IntMap; + typedef typename ItemSetTraits:: + template Map::Type BoolMap; + + const Graph &_graph; + int _max_level; + int _item_num; + std::vector _first, _last; + ItemMap _prev, _next; + int _highest_active; + IntMap _level; + BoolMap _active; + + public: + ///Constructor with given maximum level. + + ///Constructor with given maximum level. + /// + ///\param g The underlying graph + ///\param max_level Set the range of the possible labels to + ///[0...\c max_level] + LinkedElevator(const Graph& graph, int max_level) + : _graph(graph), _max_level(max_level), _item_num(_max_level), + _first(_max_level + 1), _last(_max_level + 1), + _prev(graph), _next(graph), + _highest_active(-1), _level(graph), _active(graph) {} + + ///Constructor. + + ///Constructor. + /// + ///\param g The underlying graph + ///The range of the possible labels is [0...\c max_level], + ///where \c max_level is equal to the number of labeled items in the graph. + LinkedElevator(const Graph& graph) + : _graph(graph), _max_level(countItems(graph)), + _item_num(_max_level), + _first(_max_level + 1), _last(_max_level + 1), + _prev(graph, INVALID), _next(graph, INVALID), + _highest_active(-1), _level(graph), _active(graph) {} + + + ///Activate item \c i. + + ///Activate item \c i. + ///\pre Item \c i shouldn't be active before. + void activate(Item i) { + _active.set(i, true); + + int level = _level[i]; + if (level > _highest_active) { + _highest_active = level; + } + + if (_prev[i] == INVALID || _active[_prev[i]]) return; + //unlace + _next.set(_prev[i], _next[i]); + if (_next[i] != INVALID) { + _prev.set(_next[i], _prev[i]); + } else { + _last[level] = _prev[i]; + } + //lace + _next.set(i, _first[level]); + _prev.set(_first[level], i); + _prev.set(i, INVALID); + _first[level] = i; + + } + + ///Deactivate item \c i. + + ///Deactivate item \c i. + ///\pre Item \c i must be active before. + void deactivate(Item i) { + _active.set(i, false); + int level = _level[i]; + + if (_next[i] == INVALID || !_active[_next[i]]) + goto find_highest_level; + + //unlace + _prev.set(_next[i], _prev[i]); + if (_prev[i] != INVALID) { + _next.set(_prev[i], _next[i]); + } else { + _first[_level[i]] = _next[i]; + } + //lace + _prev.set(i, _last[level]); + _next.set(_last[level], i); + _next.set(i, INVALID); + _last[level] = i; + + find_highest_level: + if (level == _highest_active) { + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + } + + ///Query whether item \c i is active + bool active(Item i) const { return _active[i]; } + + ///Return the level of item \c i. + int operator[](Item i) const { return _level[i]; } + + ///Return the number of items on level \c l. + int onLevel(int l) const { + int num = 0; + Item n = _first[l]; + while (n != INVALID) { + ++num; + n = _next[n]; + } + return num; + } + + ///Return true if the level is empty. + bool emptyLevel(int l) const { + return _first[l] == INVALID; + } + + ///Return the number of items above level \c l. + int aboveLevel(int l) const { + int num = 0; + for (int level = l + 1; level < _max_level; ++level) + num += onLevel(level); + return num; + } + + ///Return the number of active items on level \c l. + int activesOnLevel(int l) const { + int num = 0; + Item n = _first[l]; + while (n != INVALID && _active[n]) { + ++num; + n = _next[n]; + } + return num; + } + + ///Return true if there is not active item on level \c l. + bool activeFree(int l) const { + return _first[l] == INVALID || !_active[_first[l]]; + } + + ///Return the maximum allowed level. + int maxLevel() const { + return _max_level; + } + + ///\name Highest Active Item + ///Functions for working with the highest level + ///active item. + + ///@{ + + ///Return a highest level active item. + + ///Return a highest level active item. + /// + ///\return the highest level active item or INVALID if there is no + ///active item. + Item highestActive() const { + return _highest_active >= 0 ? _first[_highest_active] : INVALID; + } + + ///Return a highest active level. + + ///Return a highest active level. + /// + ///\return the level of the highest active item or -1 if there is + ///no active item. + int highestActiveLevel() const { + return _highest_active; + } + + ///Lift the highest active item by one. + + ///Lift the item returned by highestActive() by one. + /// + void liftHighestActive() { + Item i = _first[_highest_active]; + if (_next[i] != INVALID) { + _prev.set(_next[i], INVALID); + _first[_highest_active] = _next[i]; + } else { + _first[_highest_active] = INVALID; + _last[_highest_active] = INVALID; + } + _level.set(i, ++_highest_active); + if (_first[_highest_active] == INVALID) { + _first[_highest_active] = i; + _last[_highest_active] = i; + _prev.set(i, INVALID); + _next.set(i, INVALID); + } else { + _prev.set(_first[_highest_active], i); + _next.set(i, _first[_highest_active]); + _first[_highest_active] = i; + } + } + + ///Lift the highest active item. + + ///Lift the item returned by highestActive() to level \c new_level. + /// + ///\warning \c new_level must be strictly higher + ///than the current level. + /// + void liftHighestActive(int new_level) { + Item i = _first[_highest_active]; + if (_next[i] != INVALID) { + _prev.set(_next[i], INVALID); + _first[_highest_active] = _next[i]; + } else { + _first[_highest_active] = INVALID; + _last[_highest_active] = INVALID; + } + _level.set(i, _highest_active = new_level); + if (_first[_highest_active] == INVALID) { + _first[_highest_active] = _last[_highest_active] = i; + _prev.set(i, INVALID); + _next.set(i, INVALID); + } else { + _prev.set(_first[_highest_active], i); + _next.set(i, _first[_highest_active]); + _first[_highest_active] = i; + } + } + + ///Lift the highest active to top. + + ///Lift the item returned by highestActive() to the top level and + ///deactivates the node. + /// + void liftHighestActiveToTop() { + Item i = _first[_highest_active]; + _level.set(i, _max_level); + if (_next[i] != INVALID) { + _prev.set(_next[i], INVALID); + _first[_highest_active] = _next[i]; + } else { + _first[_highest_active] = INVALID; + _last[_highest_active] = INVALID; + } + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + + ///@} + + ///\name Active Item on Certain Level + ///Functions for working with the active items. + + ///@{ + + ///Returns an active item on level \c l. + + ///Returns an active item on level \c l. + /// + ///Returns an active item on level \c l or \ref INVALID if there is no such + ///an item. (\c l must be from the range [0...\c max_level]. + Item activeOn(int l) const + { + return _active[_first[l]] ? _first[l] : INVALID; + } + + ///Lifts the active item returned by \c activeOn() member function. + + ///Lifts the active item returned by \c activeOn() member function + ///by one. + Item liftActiveOn(int l) + { + Item i = _first[l]; + if (_next[i] != INVALID) { + _prev.set(_next[i], INVALID); + _first[l] = _next[i]; + } else { + _first[l] = INVALID; + _last[l] = INVALID; + } + _level.set(i, ++l); + if (_first[l] == INVALID) { + _first[l] = _last[l] = i; + _prev.set(i, INVALID); + _next.set(i, INVALID); + } else { + _prev.set(_first[l], i); + _next.set(i, _first[l]); + _first[l] = i; + } + if (_highest_active < l) { + _highest_active = l; + } + } + + /// \brief Lifts the active item returned by \c activeOn() member function. + /// + /// Lifts the active item returned by \c activeOn() member function + /// to the given level. + void liftActiveOn(int l, int new_level) + { + Item i = _first[l]; + if (_next[i] != INVALID) { + _prev.set(_next[i], INVALID); + _first[l] = _next[i]; + } else { + _first[l] = INVALID; + _last[l] = INVALID; + } + _level.set(i, l = new_level); + if (_first[l] == INVALID) { + _first[l] = _last[l] = i; + _prev.set(i, INVALID); + _next.set(i, INVALID); + } else { + _prev.set(_first[l], i); + _next.set(i, _first[l]); + _first[l] = i; + } + if (_highest_active < l) { + _highest_active = l; + } + } + + ///Lifts the active item returned by \c activeOn() member function. + + ///Lifts the active item returned by \c activeOn() member function + ///to the top level. + void liftActiveToTop(int l) + { + Item i = _first[l]; + if (_next[i] != INVALID) { + _prev.set(_next[i], INVALID); + _first[l] = _next[i]; + } else { + _first[l] = INVALID; + _last[l] = INVALID; + } + _level.set(i, _max_level); + if (l == _highest_active) { + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + } + + ///@} + + /// \brief Lift an active item to a higher level. + /// + /// Lift an active item to a higher level. + /// \param i The item to be lifted. It must be active. + /// \param new_level The new level of \c i. It must be strictly higher + /// than the current level. + /// + void lift(Item i, int new_level) { + if (_next[i] != INVALID) { + _prev.set(_next[i], _prev[i]); + } else { + _last[new_level] = _prev[i]; + } + if (_prev[i] != INVALID) { + _next.set(_prev[i], _next[i]); + } else { + _first[new_level] = _next[i]; + } + _level.set(i, new_level); + if (_first[new_level] == INVALID) { + _first[new_level] = _last[new_level] = i; + _prev.set(i, INVALID); + _next.set(i, INVALID); + } else { + _prev.set(_first[new_level], i); + _next.set(i, _first[new_level]); + _first[new_level] = i; + } + if (_highest_active < new_level) { + _highest_active = new_level; + } + } + + ///Mark the node as it did not reach the max level + + ///Mark the node as it did not reach the max level. It sets the + ///level to the under the max level value. The node will be never + ///more activated because the push operation from the maximum + ///level is forbidden in the push-relabel algorithms. The node + ///should be lifted previously to the top level. + void markToBottom(Item i) { + _level.set(i, _max_level - 1); + } + + ///Lift all nodes on and above a level to the top (and deactivate them). + + ///This function lifts all nodes on and above level \c l to \c + ///maxLevel(), and also deactivates them. + void liftToTop(int l) { + for (int i = l + 1; _first[i] != INVALID; ++i) { + Item n = _first[i]; + while (n != INVALID) { + _level.set(n, _max_level); + n = _next[n]; + } + _first[i] = INVALID; + _last[i] = INVALID; + } + if (_highest_active > l - 1) { + _highest_active = l - 1; + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + } + + private: + + int _init_level; + + public: + + ///\name Initialization + ///Using this function you can initialize the levels of the item. + ///\n + ///This initializatios is started with calling \c initStart(). + ///Then the + ///items should be listed levels by levels statring with the lowest one + ///(with level 0). This is done by using \c initAddItem() + ///and \c initNewLevel(). Finally \c initFinish() must be called. + ///The items not listed will be put on the highest level. + ///@{ + + ///Start the initialization process. + + void initStart() { + + for (int i = 0; i <= _max_level; ++i) { + _first[i] = _last[i] = INVALID; + } + _init_level = 0; + for(typename ItemSetTraits::ItemIt i(_graph); + i != INVALID; ++i) { + _level.set(i, _max_level); + _active.set(i, false); + } + } + + ///Add an item to the current level. + + void initAddItem(Item i) { + _level.set(i, _init_level); + if (_last[_init_level] == INVALID) { + _first[_init_level] = i; + _last[_init_level] = i; + _prev.set(i, INVALID); + _next.set(i, INVALID); + } else { + _prev.set(i, _last[_init_level]); + _next.set(i, INVALID); + _next.set(_last[_init_level], i); + _last[_init_level] = i; + } + } + + ///Start a new level. + + ///Start a new level. + ///It shouldn't be used before the items on level 0 are listed. + void initNewLevel() { + ++_init_level; + } + + ///Finalize the initialization process. + + void initFinish() { + _highest_active = -1; + } + + ///@} + + }; + + +} //END OF NAMESPACE LEMON + +#endif +