void BidirectionalIBFS::IBFSInit() { auto start = Clock::now(); const int n = m_graph->NumNodes(); m_source_layers = std::vector<NodeQueue>(n+1); m_sink_layers = std::vector<NodeQueue>(n+1); m_source_orphans.clear(); m_sink_orphans.clear(); auto& nodes = m_graph->GetNodes(); auto& sNode = nodes[m_graph->GetS()]; sNode.state = NodeState::S; sNode.dis = 0; m_source_layers[0].push_back(sNode); auto& tNode = nodes[m_graph->GetT()]; tNode.state = NodeState::T; tNode.dis = 0; m_sink_layers[0].push_back(tNode); // saturate all s-i-t paths for (NodeId i = 0; i < n; ++i) { REAL min_cap = std::min(m_graph->m_c_si[i]-m_graph->m_phi_si[i], m_graph->m_c_it[i]-m_graph->m_phi_it[i]); m_graph->m_phi_si[i] += min_cap; m_graph->m_phi_it[i] += min_cap; if (m_graph->m_c_si[i] > m_graph->m_phi_si[i]) { auto& node = m_graph->node(i); node.state = NodeState::S; node.dis = 1; AddToLayer(i); node.parent_arc = m_graph->ArcsEnd(i); node.parent = m_graph->GetS(); } else if (m_graph->m_c_it[i] > m_graph->m_phi_it[i]) { auto& node = m_graph->node(i); node.state = NodeState::T; node.dis = 1; AddToLayer(i); node.parent_arc = m_graph->ArcsEnd(i); node.parent = m_graph->GetT(); } else { ASSERT(m_graph->m_c_si[i] == m_graph->m_phi_si[i] && m_graph->m_c_it[i] == m_graph->m_phi_it[i]); } } m_initTime += Duration{ Clock::now() - start }.count(); }
void BidirectionalIBFS::IBFS() { auto start = Clock::now(); m_forward_search = false; m_source_tree_d = 1; m_sink_tree_d = 0; IBFSInit(); // Set up initial current_q and search nodes to make it look like // we just finished scanning the sink node NodeQueue* current_q = &(m_sink_layers[0]); m_search_node_iter = current_q->end(); m_search_node_end = current_q->end(); while (!current_q->empty()) { if (m_search_node_iter == m_search_node_end) { // Swap queues and continue if (m_forward_search) { m_source_tree_d++; current_q = &(m_sink_layers[m_sink_tree_d]); } else { m_sink_tree_d++; current_q = &(m_source_layers[m_source_tree_d]); } m_search_node_iter = current_q->begin(); m_search_node_end = current_q->end(); m_forward_search = !m_forward_search; if (!current_q->empty()) { Node& n = *m_search_node_iter; NodeId nodeIdx = n.id; if (m_forward_search) { ASSERT(n.state == NodeState::S || n.state == NodeState::S_orphan); m_search_arc = m_graph->ArcsBegin(nodeIdx); m_search_arc_end = m_graph->ArcsEnd(nodeIdx); } else { ASSERT(n.state == NodeState::T || n.state == NodeState::T_orphan); m_search_arc = m_graph->ArcsBegin(nodeIdx); m_search_arc_end = m_graph->ArcsEnd(nodeIdx); } } continue; } Node& n = *m_search_node_iter; NodeId search_node = n.id; int distance; if (m_forward_search) { distance = m_source_tree_d; } else { distance = m_sink_tree_d; } ASSERT(n.dis == distance); // Advance m_search_arc until we find a residual arc while (m_search_arc != m_search_arc_end && !m_graph->NonzeroCap(m_search_arc, m_forward_search)) ++m_search_arc; if (m_search_arc != m_search_arc_end) { NodeId neighbor = m_search_arc.Target(); NodeState neighbor_state = m_graph->node(neighbor).state; if (neighbor_state == n.state) { ASSERT(m_graph->node(neighbor).dis <= n.dis + 1); if (m_graph->node(neighbor).dis == n.dis+1) { auto reverseArc = m_search_arc.Reverse(); if (reverseArc < m_graph->node(neighbor).parent_arc) { m_graph->node(neighbor).parent_arc = reverseArc; m_graph->node(neighbor).parent = search_node; } } ++m_search_arc; } else if (neighbor_state == NodeState::N) { // Then we found an unlabeled node, add it to the tree m_graph->node(neighbor).state = n.state; m_graph->node(neighbor).dis = n.dis + 1; AddToLayer(neighbor); auto reverseArc = m_search_arc.Reverse(); m_graph->node(neighbor).parent_arc = reverseArc; ASSERT(m_graph->NonzeroCap(m_graph->node(neighbor).parent_arc, !m_forward_search)); m_graph->node(neighbor).parent = search_node; ++m_search_arc; } else { // Then we found an arc to the other tree ASSERT(neighbor_state != NodeState::S_orphan && neighbor_state != NodeState::T_orphan); ASSERT(m_graph->NonzeroCap(m_search_arc, m_forward_search)); Augment(m_search_arc); Adopt(); } } else { // No more arcs to scan from this node, so remove from queue AdvanceSearchNode(); } } // End while m_totalTime += Duration{ Clock::now() - start }.count(); //std::cout << "Total time: " << m_totalTime << "\n"; //std::cout << "Init time: " << m_initTime << "\n"; //std::cout << "Augment time: " << m_augmentTime << "\n"; //std::cout << "Adopt time: " << m_adoptTime << "\n"; }
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(); }
void FifoGap<TFLOW,TCAP>::GlobalUpdate() { Node *node, *head; Layer *lay; Arc *arc; // Reset layers for (Size i = 0; i <= m_max_rank; i++) { m_layer_list[i].m_first = NULL; } m_max_rank = 0; m_fifo_first = NULL; m_fifo_last = NULL; // Initialize ranks, put nodes connected to the sink to the first layer lay = &m_layer_list[1]; for (node = m_node_list.Begin(); node != m_node_list.End(); ++node) { if (node->m_excess < 0) { node->m_rank = 1; node->m_current = node->m_first; AddToLayer(lay, node); } else { node->m_rank = m_nodes; } } // Breadth first search for ( ; lay->m_first != NULL; lay++) { m_max_rank++; // Check list of active nodes on this layer for (node = lay->m_first; node != NULL; node = node->m_lay_next) { for (arc = node->m_first; arc != NULL; arc = arc->m_next) { head = arc->m_head; if (head->m_rank == m_nodes && arc->m_sister->m_res_cap > 0) { head->m_rank = node->m_rank + 1; head->m_current = head->m_first; AddToLayer(lay + 1, head); if (head->m_excess > 0) { // Add to queue - be careful to initialize the queue // here so the highest ranks are processed first. // It is much faster then. head->m_next_active = m_fifo_first; if (m_fifo_first == NULL) { m_fifo_last = head; } m_fifo_first = head; } } } } } }
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; }