jacint@109: // -*- C++ -*- jacint@372: jacint@109: /* jacint@109: Heuristics: jacint@109: 2 phase jacint@109: gap jacint@109: list 'level_list' on the nodes on level i implemented by hand jacint@451: stack 'active' on the active nodes on level i jacint@109: runs heuristic 'highest label' for H1*n relabels jacint@113: runs heuristic 'bound decrease' for H0*n relabels, starts with 'highest label' jacint@109: jacint@451: Parameters H0 and H1 are initialized to 20 and 1. jacint@109: jacint@211: Constructors: jacint@109: jacint@372: Preflow(Graph, Node, Node, CapMap, FlowMap, bool) : bool must be false if jacint@372: FlowMap is not constant zero, and should be true if it is jacint@109: jacint@109: Members: jacint@109: jacint@211: void run() jacint@109: jacint@211: T flowValue() : returns the value of a maximum flow jacint@109: jacint@109: void minMinCut(CutMap& M) : sets M to the characteristic vector of the jacint@451: minimum min cut. M should be a map of bools initialized to false. ??Is it OK? jacint@109: jacint@109: void maxMinCut(CutMap& M) : sets M to the characteristic vector of the jacint@109: maximum min cut. M should be a map of bools initialized to false. jacint@109: jacint@109: void minCut(CutMap& M) : sets M to the characteristic vector of jacint@109: a min cut. M should be a map of bools initialized to false. jacint@109: jacint@109: */ jacint@109: jacint@211: #ifndef HUGO_PREFLOW_H jacint@211: #define HUGO_PREFLOW_H jacint@109: jacint@109: #define H0 20 jacint@109: #define H1 1 jacint@109: jacint@109: #include jacint@109: #include jacint@451: #include jacint@109: jacint@109: namespace hugo { jacint@109: jacint@109: template , marci@389: typename FlowMap=typename Graph::template EdgeMap > jacint@211: class Preflow { jacint@109: jacint@211: typedef typename Graph::Node Node; jacint@109: typedef typename Graph::NodeIt NodeIt; jacint@109: typedef typename Graph::OutEdgeIt OutEdgeIt; jacint@109: typedef typename Graph::InEdgeIt InEdgeIt; jacint@451: jacint@451: typedef typename std::vector > VecStack; jacint@451: typedef typename Graph::template NodeMap NNMap; jacint@451: typedef typename std::vector VecNode; jacint@451: jacint@211: const Graph& G; jacint@211: Node s; jacint@211: Node t; jacint@451: CapMap* capacity; jacint@451: FlowMap* flow; jacint@451: int n; //the number of nodes of G jacint@451: typename Graph::template NodeMap level; jacint@451: typename Graph::template NodeMap excess; jacint@451: jacint@109: jacint@109: public: jacint@451: jacint@451: enum flowEnum{ jacint@451: ZERO_FLOW=0, jacint@451: GEN_FLOW=1, jacint@451: PREFLOW=2 jacint@451: }; jacint@451: jacint@372: Preflow(Graph& _G, Node _s, Node _t, CapMap& _capacity, jacint@451: FlowMap& _flow) : jacint@451: G(_G), s(_s), t(_t), capacity(&_capacity), jacint@451: flow(&_flow), n(_G.nodeNum()), level(_G), excess(_G,0) {} jacint@451: jacint@451: void run() { jacint@451: preflow( ZERO_FLOW ); jacint@451: } jacint@372: jacint@451: void preflow( flowEnum fe ) { jacint@451: preflowPhase0(fe); jacint@451: preflowPhase1(); jacint@451: } jacint@451: jacint@451: void preflowPhase0( flowEnum fe ) { jacint@372: jacint@109: int heur0=(int)(H0*n); //time while running 'bound decrease' jacint@109: int heur1=(int)(H1*n); //time while running 'highest label' jacint@109: int heur=heur1; //starting time interval (#of relabels) jacint@451: int numrelabel=0; jacint@451: jacint@109: bool what_heur=1; jacint@451: //It is 0 in case 'bound decrease' and 1 in case 'highest label' jacint@451: jacint@109: bool end=false; jacint@451: //Needed for 'bound decrease', true means no active nodes are above bound b. jacint@451: jacint@109: int k=n-2; //bound on the highest level under n containing a node jacint@109: int b=k; //bound on the highest level under n of an active node jacint@109: jacint@451: VecStack active(n); jacint@451: jacint@451: NNMap left(G,INVALID); jacint@451: NNMap right(G,INVALID); jacint@451: VecNode level_list(n,INVALID); jacint@451: //List of the nodes in level i 0 && lev < n && v != t ) active[lev].push(v); jacint@451: } jacint@451: break; jacint@451: } jacint@451: case GEN_FLOW: jacint@451: { jacint@451: //Counting the excess of t jacint@451: T exc=0; jacint@372: jacint@372: InEdgeIt e; jacint@451: for(G.first(e,t); G.valid(e); G.next(e)) exc+=(*flow)[e]; jacint@451: OutEdgeIt f; jacint@451: for(G.first(f,t); G.valid(f); G.next(f)) exc-=(*flow)[f]; jacint@451: jacint@451: excess.set(t,exc); jacint@451: jacint@451: break; jacint@451: } jacint@451: } jacint@451: jacint@451: preflowPreproc( fe, active, level_list, left, right ); jacint@451: //End of preprocessing jacint@451: jacint@451: jacint@451: //Push/relabel on the highest level active nodes. jacint@451: while ( true ) { jacint@451: if ( b == 0 ) { jacint@451: if ( !what_heur && !end && k > 0 ) { jacint@451: b=k; jacint@451: end=true; jacint@451: } else break; jacint@451: } jacint@451: jacint@451: if ( active[b].empty() ) --b; jacint@451: else { jacint@451: end=false; jacint@451: Node w=active[b].top(); jacint@451: active[b].pop(); jacint@451: int newlevel=push(w,active); jacint@451: if ( excess[w] > 0 ) relabel(w, newlevel, active, level_list, jacint@451: left, right, b, k, what_heur); jacint@451: jacint@451: ++numrelabel; jacint@451: if ( numrelabel >= heur ) { jacint@451: numrelabel=0; jacint@451: if ( what_heur ) { jacint@451: what_heur=0; jacint@451: heur=heur0; jacint@451: end=false; jacint@451: } else { jacint@451: what_heur=1; jacint@451: heur=heur1; jacint@451: b=k; jacint@372: } jacint@109: } jacint@451: } jacint@451: } jacint@451: } jacint@451: jacint@451: jacint@451: void preflowPhase1() { jacint@451: jacint@451: int k=n-2; //bound on the highest level under n containing a node jacint@451: int b=k; //bound on the highest level under n of an active node jacint@451: jacint@451: VecStack active(n); jacint@451: level.set(s,0); jacint@451: std::queue bfs_queue; jacint@451: bfs_queue.push(s); jacint@451: jacint@451: while (!bfs_queue.empty()) { jacint@451: jacint@451: Node v=bfs_queue.front(); jacint@451: bfs_queue.pop(); jacint@451: int l=level[v]+1; jacint@451: jacint@451: InEdgeIt e; jacint@451: for(G.first(e,v); G.valid(e); G.next(e)) { jacint@451: if ( (*capacity)[e] == (*flow)[e] ) continue; jacint@451: Node u=G.tail(e); jacint@451: if ( level[u] >= n ) { jacint@451: bfs_queue.push(u); jacint@451: level.set(u, l); jacint@451: if ( excess[u] > 0 ) active[l].push(u); jacint@451: } jacint@109: } jacint@451: jacint@451: OutEdgeIt f; jacint@451: for(G.first(f,v); G.valid(f); G.next(f)) { jacint@451: if ( 0 == (*flow)[f] ) continue; jacint@451: Node u=G.head(f); jacint@451: if ( level[u] >= n ) { jacint@451: bfs_queue.push(u); jacint@451: level.set(u, l); jacint@451: if ( excess[u] > 0 ) active[l].push(u); jacint@109: } jacint@109: } jacint@372: } jacint@451: b=n-2; jacint@372: jacint@109: while ( true ) { jacint@109: jacint@451: if ( b == 0 ) break; jacint@451: jacint@451: if ( active[b].empty() ) --b; jacint@109: else { jacint@451: Node w=active[b].top(); jacint@451: active[b].pop(); jacint@451: int newlevel=push(w,active); jacint@109: jacint@451: //relabel jacint@451: if ( excess[w] > 0 ) { jacint@109: level.set(w,++newlevel); jacint@451: active[newlevel].push(w); jacint@109: b=newlevel; jacint@451: } jacint@109: } // if stack[b] is nonempty jacint@109: } // while(true) jacint@109: } jacint@109: jacint@109: jacint@451: //Returns the maximum value of a flow. jacint@451: T flowValue() { jacint@451: return excess[t]; jacint@451: } jacint@109: jacint@451: //should be used only between preflowPhase0 and preflowPhase1 jacint@451: template jacint@451: void actMinCut(_CutMap& M) { jacint@211: NodeIt v; jacint@451: for(G.first(v); G.valid(v); G.next(v)) jacint@451: if ( level[v] < n ) M.set(v,false); jacint@451: else M.set(v,true); jacint@211: } jacint@109: jacint@109: jacint@109: jacint@109: /* jacint@109: Returns the minimum min cut, by a bfs from s in the residual graph. jacint@109: */ jacint@109: template jacint@109: void minMinCut(_CutMap& M) { jacint@109: jacint@211: std::queue queue; jacint@109: jacint@109: M.set(s,true); jacint@109: queue.push(s); jacint@109: jacint@109: while (!queue.empty()) { jacint@211: Node w=queue.front(); jacint@109: queue.pop(); jacint@109: jacint@211: OutEdgeIt e; jacint@211: for(G.first(e,w) ; G.valid(e); G.next(e)) { jacint@211: Node v=G.head(e); jacint@451: if (!M[v] && (*flow)[e] < (*capacity)[e] ) { jacint@109: queue.push(v); jacint@109: M.set(v, true); jacint@109: } jacint@109: } jacint@109: jacint@211: InEdgeIt f; jacint@211: for(G.first(f,w) ; G.valid(f); G.next(f)) { jacint@211: Node v=G.tail(f); jacint@451: if (!M[v] && (*flow)[f] > 0 ) { jacint@109: queue.push(v); jacint@109: M.set(v, true); jacint@109: } jacint@109: } jacint@109: } jacint@109: } jacint@109: jacint@109: jacint@109: jacint@109: /* jacint@109: Returns the maximum min cut, by a reverse bfs jacint@109: from t in the residual graph. jacint@109: */ jacint@109: jacint@109: template jacint@109: void maxMinCut(_CutMap& M) { jacint@451: jacint@451: NodeIt v; jacint@451: for(G.first(v) ; G.valid(v); G.next(v)) { jacint@451: M.set(v, true); jacint@451: } jacint@451: jacint@211: std::queue queue; jacint@109: jacint@451: M.set(t,false); jacint@109: queue.push(t); jacint@109: jacint@109: while (!queue.empty()) { jacint@211: Node w=queue.front(); jacint@109: queue.pop(); jacint@109: jacint@211: jacint@211: InEdgeIt e; jacint@211: for(G.first(e,w) ; G.valid(e); G.next(e)) { jacint@211: Node v=G.tail(e); jacint@451: if (M[v] && (*flow)[e] < (*capacity)[e] ) { jacint@109: queue.push(v); jacint@451: M.set(v, false); jacint@109: } jacint@109: } jacint@211: jacint@211: OutEdgeIt f; jacint@211: for(G.first(f,w) ; G.valid(f); G.next(f)) { jacint@211: Node v=G.head(f); jacint@451: if (M[v] && (*flow)[f] > 0 ) { jacint@109: queue.push(v); jacint@451: M.set(v, false); jacint@109: } jacint@109: } jacint@109: } jacint@109: } jacint@109: jacint@109: jacint@109: template jacint@109: void minCut(CutMap& M) { jacint@109: minMinCut(M); jacint@109: } jacint@109: jacint@372: jacint@451: void resetTarget (const Node _t) {t=_t;} jacint@451: jacint@451: void resetSource (const Node _s) {s=_s;} jacint@372: jacint@451: void resetCap (const CapMap& _cap) { jacint@451: capacity=&_cap; jacint@451: } jacint@451: jacint@451: void resetFlow (FlowMap& _flow) { jacint@451: flow=&_flow; jacint@372: } jacint@372: jacint@372: jacint@451: private: jacint@451: jacint@451: int push(const Node w, VecStack& active) { jacint@451: jacint@451: int lev=level[w]; jacint@451: T exc=excess[w]; jacint@451: int newlevel=n; //bound on the next level of w jacint@451: jacint@451: OutEdgeIt e; jacint@451: for(G.first(e,w); G.valid(e); G.next(e)) { jacint@451: jacint@451: if ( (*flow)[e] == (*capacity)[e] ) continue; jacint@451: Node v=G.head(e); jacint@451: jacint@451: if( lev > level[v] ) { //Push is allowed now jacint@451: jacint@451: if ( excess[v]==0 && v!=t && v!=s ) { jacint@451: int lev_v=level[v]; jacint@451: active[lev_v].push(v); jacint@451: } jacint@451: jacint@451: T cap=(*capacity)[e]; jacint@451: T flo=(*flow)[e]; jacint@451: T remcap=cap-flo; jacint@451: jacint@451: if ( remcap >= exc ) { //A nonsaturating push. jacint@451: jacint@451: flow->set(e, flo+exc); jacint@451: excess.set(v, excess[v]+exc); jacint@451: exc=0; jacint@451: break; jacint@451: jacint@451: } else { //A saturating push. jacint@451: flow->set(e, cap); jacint@451: excess.set(v, excess[v]+remcap); jacint@451: exc-=remcap; jacint@451: } jacint@451: } else if ( newlevel > level[v] ) newlevel = level[v]; jacint@451: } //for out edges wv jacint@451: jacint@451: if ( exc > 0 ) { jacint@451: InEdgeIt e; jacint@451: for(G.first(e,w); G.valid(e); G.next(e)) { jacint@451: jacint@451: if( (*flow)[e] == 0 ) continue; jacint@451: Node v=G.tail(e); jacint@451: jacint@451: if( lev > level[v] ) { //Push is allowed now jacint@451: jacint@451: if ( excess[v]==0 && v!=t && v!=s ) { jacint@451: int lev_v=level[v]; jacint@451: active[lev_v].push(v); jacint@451: } jacint@451: jacint@451: T flo=(*flow)[e]; jacint@451: jacint@451: if ( flo >= exc ) { //A nonsaturating push. jacint@451: jacint@451: flow->set(e, flo-exc); jacint@451: excess.set(v, excess[v]+exc); jacint@451: exc=0; jacint@451: break; jacint@451: } else { //A saturating push. jacint@451: jacint@451: excess.set(v, excess[v]+flo); jacint@451: exc-=flo; jacint@451: flow->set(e,0); jacint@451: } jacint@451: } else if ( newlevel > level[v] ) newlevel = level[v]; jacint@451: } //for in edges vw jacint@451: jacint@451: } // if w still has excess after the out edge for cycle jacint@451: jacint@451: excess.set(w, exc); jacint@451: jacint@451: return newlevel; jacint@451: } jacint@451: jacint@451: jacint@451: void preflowPreproc ( flowEnum fe, VecStack& active, jacint@451: VecNode& level_list, NNMap& left, NNMap& right ) { jacint@451: jacint@451: std::queue bfs_queue; jacint@451: jacint@451: switch ( fe ) { jacint@451: case ZERO_FLOW: jacint@451: { jacint@451: //Reverse_bfs from t, to find the starting level. jacint@451: level.set(t,0); jacint@451: bfs_queue.push(t); jacint@451: jacint@451: while (!bfs_queue.empty()) { jacint@451: jacint@451: Node v=bfs_queue.front(); jacint@451: bfs_queue.pop(); jacint@451: int l=level[v]+1; jacint@451: jacint@451: InEdgeIt e; jacint@451: for(G.first(e,v); G.valid(e); G.next(e)) { jacint@451: Node w=G.tail(e); jacint@451: if ( level[w] == n && w != s ) { jacint@451: bfs_queue.push(w); jacint@451: Node first=level_list[l]; jacint@451: if ( G.valid(first) ) left.set(first,w); jacint@451: right.set(w,first); jacint@451: level_list[l]=w; jacint@451: level.set(w, l); jacint@451: } jacint@451: } jacint@451: } jacint@451: jacint@451: //the starting flow jacint@451: OutEdgeIt e; jacint@451: for(G.first(e,s); G.valid(e); G.next(e)) jacint@451: { jacint@451: T c=(*capacity)[e]; jacint@451: if ( c == 0 ) continue; jacint@451: Node w=G.head(e); jacint@451: if ( level[w] < n ) { jacint@451: if ( excess[w] == 0 && w!=t ) active[level[w]].push(w); jacint@451: flow->set(e, c); jacint@451: excess.set(w, excess[w]+c); jacint@451: } jacint@451: } jacint@451: break; jacint@451: } jacint@451: jacint@451: case GEN_FLOW: jacint@451: case PREFLOW: jacint@451: { jacint@451: //Reverse_bfs from t in the residual graph, jacint@451: //to find the starting level. jacint@451: level.set(t,0); jacint@451: bfs_queue.push(t); jacint@451: jacint@451: while (!bfs_queue.empty()) { jacint@451: jacint@451: Node v=bfs_queue.front(); jacint@451: bfs_queue.pop(); jacint@451: int l=level[v]+1; jacint@451: jacint@451: InEdgeIt e; jacint@451: for(G.first(e,v); G.valid(e); G.next(e)) { jacint@451: if ( (*capacity)[e] == (*flow)[e] ) continue; jacint@451: Node w=G.tail(e); jacint@451: if ( level[w] == n && w != s ) { jacint@451: bfs_queue.push(w); jacint@451: Node first=level_list[l]; jacint@451: if ( G.valid(first) ) left.set(first,w); jacint@451: right.set(w,first); jacint@451: level_list[l]=w; jacint@451: level.set(w, l); jacint@451: } jacint@451: } jacint@451: jacint@451: OutEdgeIt f; jacint@451: for(G.first(f,v); G.valid(f); G.next(f)) { jacint@451: if ( 0 == (*flow)[f] ) continue; jacint@451: Node w=G.head(f); jacint@451: if ( level[w] == n && w != s ) { jacint@451: bfs_queue.push(w); jacint@451: Node first=level_list[l]; jacint@451: if ( G.valid(first) ) left.set(first,w); jacint@451: right.set(w,first); jacint@451: level_list[l]=w; jacint@451: level.set(w, l); jacint@451: } jacint@451: } jacint@451: } jacint@451: jacint@451: jacint@451: //the starting flow jacint@451: OutEdgeIt e; jacint@451: for(G.first(e,s); G.valid(e); G.next(e)) jacint@451: { jacint@451: T rem=(*capacity)[e]-(*flow)[e]; jacint@451: if ( rem == 0 ) continue; jacint@451: Node w=G.head(e); jacint@451: if ( level[w] < n ) { jacint@451: if ( excess[w] == 0 && w!=t ) active[level[w]].push(w); jacint@451: flow->set(e, (*capacity)[e]); jacint@451: excess.set(w, excess[w]+rem); jacint@451: } jacint@451: } jacint@451: jacint@451: InEdgeIt f; jacint@451: for(G.first(f,s); G.valid(f); G.next(f)) jacint@451: { jacint@451: if ( (*flow)[f] == 0 ) continue; jacint@451: Node w=G.tail(f); jacint@451: if ( level[w] < n ) { jacint@451: if ( excess[w] == 0 && w!=t ) active[level[w]].push(w); jacint@451: excess.set(w, excess[w]+(*flow)[f]); jacint@451: flow->set(f, 0); jacint@451: } jacint@451: } jacint@451: break; jacint@451: } //case PREFLOW jacint@451: } jacint@451: } //preflowPreproc jacint@451: jacint@451: jacint@451: jacint@451: void relabel( const Node w, int newlevel, VecStack& active, jacint@451: VecNode& level_list, NNMap& left, jacint@451: NNMap& right, int& b, int& k, const bool what_heur ) { jacint@451: jacint@451: T lev=level[w]; jacint@451: jacint@451: Node right_n=right[w]; jacint@451: Node left_n=left[w]; jacint@451: jacint@451: //unlacing starts jacint@451: if ( G.valid(right_n) ) { jacint@451: if ( G.valid(left_n) ) { jacint@451: right.set(left_n, right_n); jacint@451: left.set(right_n, left_n); jacint@451: } else { jacint@451: level_list[lev]=right_n; jacint@451: left.set(right_n, INVALID); jacint@451: } jacint@451: } else { jacint@451: if ( G.valid(left_n) ) { jacint@451: right.set(left_n, INVALID); jacint@451: } else { jacint@451: level_list[lev]=INVALID; jacint@451: } jacint@451: } jacint@451: //unlacing ends jacint@451: jacint@451: if ( !G.valid(level_list[lev]) ) { jacint@451: jacint@451: //gapping starts jacint@451: for (int i=lev; i!=k ; ) { jacint@451: Node v=level_list[++i]; jacint@451: while ( G.valid(v) ) { jacint@451: level.set(v,n); jacint@451: v=right[v]; jacint@451: } jacint@451: level_list[i]=INVALID; jacint@451: if ( !what_heur ) { jacint@451: while ( !active[i].empty() ) { jacint@451: active[i].pop(); //FIXME: ezt szebben kene jacint@451: } jacint@451: } jacint@451: } jacint@451: jacint@451: level.set(w,n); jacint@451: b=lev-1; jacint@451: k=b; jacint@451: //gapping ends jacint@451: jacint@451: } else { jacint@451: jacint@451: if ( newlevel == n ) level.set(w,n); jacint@451: else { jacint@451: level.set(w,++newlevel); jacint@451: active[newlevel].push(w); jacint@451: if ( what_heur ) b=newlevel; jacint@451: if ( k < newlevel ) ++k; //now k=newlevel jacint@451: Node first=level_list[newlevel]; jacint@451: if ( G.valid(first) ) left.set(first,w); jacint@451: right.set(w,first); jacint@451: left.set(w,INVALID); jacint@451: level_list[newlevel]=w; jacint@451: } jacint@451: } jacint@451: jacint@451: } //relabel jacint@451: jacint@109: jacint@109: }; jacint@109: marci@174: } //namespace hugo jacint@109: jacint@451: #endif //HUGO_PREFLOW_H jacint@109: jacint@109: marci@174: marci@174: