void BidirectionalIBFS::Adopt() { auto start = Clock::now(); while (!m_source_orphans.empty()) { Node& n = m_source_orphans.front(); NodeId i = n.id; m_source_orphans.pop_front(); int old_dist = n.dis; while (n.parent_arc != m_graph->ArcsEnd(i) && (m_graph->node(n.parent).state == NodeState::T || m_graph->node(n.parent).state == NodeState::T_orphan || m_graph->node(n.parent).state == NodeState::N || m_graph->node(n.parent).dis != old_dist - 1 || !m_graph->NonzeroCap(n.parent_arc, false))) { ++n.parent_arc; if (n.parent_arc != m_graph->ArcsEnd(i)) n.parent = n.parent_arc.Target(); } if (n.parent_arc == m_graph->ArcsEnd(i)) { RemoveFromLayer(i); // We didn't find a new parent with the same label, so do a relabel n.dis = std::numeric_limits<int>::max()-1; for (auto newParentArc = m_graph->ArcsBegin(i); newParentArc != m_graph->ArcsEnd(i); ++newParentArc) { auto target = newParentArc.Target(); if (m_graph->node(target).dis < n.dis && (m_graph->node(target).state == NodeState::S || m_graph->node(target).state == NodeState::S_orphan) && m_graph->NonzeroCap(newParentArc, false)) { n.dis = m_graph->node(target).dis; n.parent_arc = newParentArc; ASSERT(m_graph->NonzeroCap(n.parent_arc, false)); n.parent = target; } } n.dis++; int cutoff_distance = m_source_tree_d; if (m_forward_search) cutoff_distance += 1; if (n.dis > cutoff_distance) { n.state = NodeState::N; } else { n.state = NodeState::S; AddToLayer(i); } // FIXME(afix) Should really assert that n.dis > old_dis // but current-arc heuristic isn't watertight at the moment... if (n.dis > old_dist) { for (auto arc = m_graph->ArcsBegin(i); arc != m_graph->ArcsEnd(i); ++arc) { if (m_graph->node(arc.Target()).parent == i) MakeOrphan(arc.Target()); } } } else { ASSERT(m_graph->NonzeroCap(n.parent_arc, false)); n.state = NodeState::S; } } while (!m_sink_orphans.empty()) { Node& n = m_sink_orphans.front(); NodeId i = n.id; m_sink_orphans.pop_front(); int old_dist = n.dis; while (n.parent_arc != m_graph->ArcsEnd(i) && (m_graph->node(n.parent).state == NodeState::S || m_graph->node(n.parent).state == NodeState::S_orphan || m_graph->node(n.parent).state == NodeState::N || m_graph->node(n.parent).dis != old_dist - 1 || !m_graph->NonzeroCap(n.parent_arc, true))) { ++n.parent_arc; if (n.parent_arc != m_graph->ArcsEnd(i)) n.parent = n.parent_arc.Target(); } if (n.parent_arc == m_graph->ArcsEnd(i)) { RemoveFromLayer(i); // We didn't find a new parent with the same label, so do a relabel n.dis = std::numeric_limits<int>::max()-1; for (auto newParentArc = m_graph->ArcsBegin(i); newParentArc != m_graph->ArcsEnd(i); ++newParentArc) { auto target = newParentArc.Target(); if (m_graph->node(target).dis < n.dis && (m_graph->node(target).state == NodeState::T || m_graph->node(target).state == NodeState::T_orphan) && m_graph->NonzeroCap(newParentArc, true)) { n.dis = m_graph->node(target).dis; n.parent_arc = newParentArc; ASSERT(m_graph->NonzeroCap(n.parent_arc, true)); n.parent = target; } } n.dis++; int cutoff_distance = m_sink_tree_d; if (!m_forward_search) cutoff_distance += 1; if (n.dis > cutoff_distance) { n.state = NodeState::N; } else { n.state = NodeState::T; AddToLayer(i); } // FIXME(afix) Should really assert that n.dis > old_dis // but current-arc heuristic isn't watertight at the moment... if (n.dis > old_dist) { for (auto arc = m_graph->ArcsBegin(i); arc != m_graph->ArcsEnd(i); ++arc) { if (m_graph->node(arc.Target()).parent == i) MakeOrphan(arc.Target()); } } } else { ASSERT(m_graph->NonzeroCap(n.parent_arc, true)); n.state = NodeState::T; } } m_adoptTime += Duration{ Clock::now() - start }.count(); }
TFLOW FifoGap<TFLOW,TCAP>::FindMaxFlow() { if (m_stage != 1) { throw System::InvalidOperationException(__FUNCTION__, __LINE__, "Call Init method before computing maximum flow."); } Size rl_count = 0, rl_threshold = (Size) (m_glob_rel_freq * m_nodes); Size next_layer_rank, min_rank; Node *node, *head; Arc *arc, *min_arc = NULL; Layer *lay; TCAP bottleneck; GlobalUpdate(); while (m_fifo_first != NULL) { // Pop node from the queue node = m_fifo_first; m_fifo_first = node->m_next_active; if (node->m_rank == m_nodes) { // The node was removed during gap relabeling continue; } RemoveFromLayer(&m_layer_list[node->m_rank], node); // DISCHARGE node while (node->m_rank < m_nodes) { lay = &m_layer_list[node->m_rank]; next_layer_rank = node->m_rank - 1; // PUSH excess for (arc = node->m_current; arc != NULL; arc = arc->m_next) { if (arc->m_res_cap > 0) { head = arc->m_head; if (head->m_rank == next_layer_rank) { bottleneck = Math::Min(node->m_excess, arc->m_res_cap); arc->m_res_cap -= bottleneck; arc->m_sister->m_res_cap += bottleneck; if (head->m_excess <= 0) { if (head->m_excess + bottleneck > 0) { // Add node to active queue if (m_fifo_first == NULL) { m_fifo_first = head; } else { m_fifo_last->m_next_active = head; } m_fifo_last = head; head->m_next_active = NULL; m_flow -= head->m_excess; } else { m_flow += bottleneck; } } head->m_excess += bottleneck; node->m_excess -= bottleneck; if (node->m_excess == 0) { break; } } } } if (arc != NULL) { // All excess pushed away, the node becomes inactive AddToLayer(lay, node); node->m_current = arc; break; } // RELABEL node node->m_rank = min_rank = m_nodes; if (lay->m_first == NULL) { // Gap relabeling GapRelabeling(lay, next_layer_rank); } else { // Node relabeling for (arc = node->m_first; arc != NULL; arc = arc->m_next) { if (arc->m_res_cap > 0 && arc->m_head->m_rank < min_rank) { min_rank = arc->m_head->m_rank; min_arc = arc; } } rl_count++; if (++min_rank < m_nodes) { node->m_rank = min_rank; node->m_current = min_arc; if (min_rank > m_max_rank) { m_max_rank = min_rank; } } } } // Check if global relabeling should be done if (rl_count > rl_threshold && m_fifo_first != NULL) { GlobalUpdate(); rl_count = 0; } } // Find nodes that are connected to the sink after the last step. // This is IMPORTANT, because it allows us to find which nodes are // connected to the source and which to the sink. GlobalUpdate(); m_stage = 2; return m_flow; }