void* scan_nodes(void* threadid) { int i, j, k; long tid; unsigned int min_nbr_height; Edge nbr_edge, min_height_edge; long d; long local_e; long local_c; int max_flow; int isInQ; int height_before_lift; int node_push_times = 0, node_lift_times = 0; int op_times = 0; tid = (long)threadid; Node* cur_node; ThreadEnv* thisThread; thisThread = threadEnv + tid; #if 0 if (tid == 0) global_relabel(tid); #endif pthread_barrier_wait(&start_barrier); while (!flow_done()) { cur_node = thisThread->Q[0]; while (cur_node != NoNode) { #ifdef GR if (op_times > gr_threshold) { op_times = 0; if (pthread_mutex_trylock(&gr_mutex) == 0) { global_relabel(tid); pthread_mutex_unlock(&gr_mutex); } } #endif while (cur_node->excess > 0) { #ifdef DEBUG fprintf(stderr, "%d h=%d, e=%ld\n", cur_node - g_node, cur_node->height, cur_node->excess); fflush(stderr); #endif min_nbr_height = UINT_MAX; for (nbr_edge = cur_node->adj_list; nbr_edge < (cur_node + 1)->adj_list; nbr_edge++) { if (nbr_edge->capacity > 0 && (nbr_edge->endpoint)->height < min_nbr_height) { min_nbr_height = (nbr_edge->endpoint)->height; min_height_edge = nbr_edge; } } #ifdef DEBUG fprintf(stderr, "work on %d\n", cur_node - g_node); fflush(stderr); #endif if (cur_node->height > min_nbr_height) { local_e = cur_node->excess; local_c = min_height_edge->capacity; d = MIN(local_e, local_c); if (min_height_edge->endpoint->wave == cur_node->wave && cur_node->height > min_height_edge->endpoint->height) { node_push_times++; op_times++; atomic_add(d, &(min_height_edge->mateedge->capacity)); atomic_sub(d, &(min_height_edge->capacity)); atomic_add(d, &((min_height_edge->endpoint)->excess)); atomic_sub(d, &(cur_node->excess)); #if defined(PUSH) || defined(DEBUG) fprintf(stderr, "[%ld] %ld(%ld) -> %ld -> %ld(%ld) \n", tid, cur_node - g_node, cur_node->excess, d, min_height_edge->endpoint - g_node, (min_height_edge->endpoint)->excess); fflush(stderr); #endif // add min_nbr to local queue isInQ = cmpxchg(&(min_height_edge->endpoint->inQ), 0, tid + 1); if (isInQ == 0) enQ(thisThread, min_height_edge->endpoint); } } else { // if we cannot push to any nodes, then we must be able to lift node_lift_times++; op_times++; pthread_mutex_lock(&(node_mutex[cur_node - g_node])); if (cur_node->height < min_nbr_height + 1) cur_node->height = min_nbr_height + 1; pthread_mutex_unlock(&(node_mutex[cur_node - g_node])); #if defined(LIFT) || defined(DEBUG) fprintf(stderr, "%ld ^ %d, ref %ld(%d)\n", cur_node - g_node, cur_node->height, min_height_edge->endpoint - g_node, min_height_edge->endpoint->height); fflush(stderr); #endif } } // while( g_node[i].excess > 0 ) set0(&(cur_node->inQ)); if (cur_node->excess > 0) { isInQ = cmpxchg(&(cur_node->inQ), 0, tid + 1); if (isInQ == 0) { reenQ(thisThread, cur_node); } else { deQ(thisThread); } } else { deQ(thisThread); } #ifdef HELP if (thisThread->request < MAX_THRD) send_work(tid); #endif cur_node = thisThread->Q[thisThread->head]; } // while (i != -1) #ifdef HELP // Q is empty, find something to do; request_work(tid); #else break; #endif } // while(!flow_done()) atomic_add(node_push_times, &(totalPushes)); atomic_add(node_lift_times, &(totalLifts)); } // scan_node
double maxflow (GRAPH *gr, GRAPHNODE *s_ptr, GRAPHNODE *t_ptr) { /* Determines maximum flow and minimum cut between nodes s (= *s_ptr) and t (= *t_ptr) in an undirected graph References: ---------- A. Goldberg/ E. Tarjan: "A New Approach to the Maximum Flow Problem", in Proc. 18th ACM Symp. on Theory of Computing, 1986. */ GRAPHNODE *aptr, *nptr, *q_front, *q_rear; GRAPHEDGE *eptr; long n, m, m0, level, i, n_discharge; double incre; long dmin; double cap; /* node ids range from 1 to n, node array indices range from 0 to n-1 */ n = gr->nnodes; for ( nptr = &(gr->nodes[n-1L]); nptr >= gr->nodes; nptr-- ) { nptr->scan_ptr = nptr->first_edge; while( nptr->scan_ptr != NULL && nptr->scan_ptr->cap <= EPS ) nptr->scan_ptr = nptr->scan_ptr->next; if ( nptr->scan_ptr == NULL ) { fprintf (stderr, "isolated node in input graph\n"); return (FALSE); } nptr->excess = 0.0L; nptr->stack_link = NULL; nptr->alive = TRUE; nptr->unmarked = TRUE; } m = gr->nedgesnonzero; m0 = gr->nedges; for ( eptr = &(gr->edges[m-1L]); eptr >= gr->edges; eptr-- ) eptr->rcap = eptr->cap; for ( eptr = &(gr->edges[m0+m-1L]); eptr >= &(gr->edges[m0]); eptr-- ) eptr->rcap = eptr->cap; for ( i = n; i >= 0L; i-- ) { number[i] = 0L; active[i] = NULL; } t_ptr->dist = 0L; /* breadth first search to get exact distances from sink and for test of graph connectivity */ t_ptr->unmarked = FALSE; q_front = t_ptr; q_rear = q_front; bfs_next: level = q_rear->dist + 1L; eptr = q_rear->first_edge; while ( eptr != NULL ) { assert(eptr->back->cap == eptr->back->rcap); if ( eptr->adjac->unmarked && eptr->back->rcap > EPS ) { nptr = eptr->adjac; nptr->unmarked = FALSE; nptr->dist = level; ++number[level]; q_front->bfs_link = nptr; q_front = nptr; } eptr = eptr->next; } if ( q_rear == q_front ) goto bfs_ready; q_rear = q_rear->bfs_link; goto bfs_next; bfs_ready: if ( co_check ) { co_check = FALSE; for ( nptr = &(gr->nodes[n-1]); nptr >= gr->nodes; --nptr ) { if ( nptr->unmarked ) return (-1.0L); } } s_ptr->dist = n; /* number[0] and number[n] not required */ t_ptr->dist = 0L; t_ptr->excess = 1.0L; /* to be subtracted again */ /* initial preflow push from source node */ max_dist = 0L; /* = max_dist of active nodes */ eptr = s_ptr->first_edge; while ( eptr != NULL ) { if( eptr->cap > EPS ) { nptr = eptr->adjac; cap = eptr->rcap; nptr->excess += cap; s_ptr->excess -= cap; eptr->back->rcap += cap; eptr->rcap = 0.0L; if ( nptr != t_ptr && nptr->excess <= cap + EPS ) { /* push node nptr onto stack for nptr->dist, but only once in case of double edges */ nptr->stack_link = active[nptr->dist]; active[nptr->dist] = nptr; if ( nptr->dist > max_dist ) max_dist = nptr->dist; } } eptr = eptr->next; } s_ptr->alive = FALSE; bound = n; n_discharge = 0L; /* main loop */ do { /* get maximum distance active node */ aptr = active[max_dist]; while ( aptr != NULL ) { active[max_dist] = aptr->stack_link; eptr = aptr->scan_ptr; assert(eptr != NULL); assert(eptr->back != NULL); assert(eptr->cap > EPS); edge_scan: /* for current active node */ assert(eptr != NULL); assert(eptr->back != NULL); assert(eptr->cap > EPS); nptr = eptr->adjac; assert(nptr != NULL); if ( nptr->dist == aptr->dist - 1L && eptr->rcap > EPS ) { incre = aptr->excess; if ( incre <= eptr->rcap ) { /* perform a non saturating push */ eptr->rcap -= incre; eptr->back->rcap += incre; aptr->excess = 0.0L; nptr->excess += incre; if ( nptr->excess <= incre + EPS ) { /* push nptr onto active stack */ nptr->stack_link = active[nptr->dist]; active[nptr->dist] = nptr; } assert(eptr->cap > EPS); aptr->scan_ptr = eptr; goto node_ready; } else { /* perform a saturating push */ incre = eptr->rcap; eptr->back->rcap += incre; aptr->excess -= incre; nptr->excess += incre; eptr->rcap = 0.0L; if ( nptr->excess <= incre + EPS ) { /* push nptr onto active stack */ nptr->stack_link = active[nptr->dist]; active[nptr->dist] = nptr; } if ( aptr->excess <= EPS ) { assert(eptr->cap > EPS); aptr->scan_ptr = eptr; goto node_ready; } } } /* go to the next non-zero edge */ do { eptr = eptr->next; } while( eptr != NULL && eptr->cap <= EPS ); if ( eptr == NULL ) { /* all incident arcs scanned, but node still has positive excess, check if for all nptr nptr->dist != aptr->dist */ if ( number[aptr->dist] == 1L ) { /* put all nodes v with dist[v] >= dist[a] into the set of "dead" nodes since they are disconnected from the sink */ for ( nptr = &(gr->nodes[n-1L]); nptr >= gr->nodes; nptr-- ) { if ( nptr->alive && nptr->dist > aptr->dist ) { --number[nptr->dist]; active[nptr->dist] = NULL; nptr->alive = FALSE; nptr->dist = n; --bound; } } --number[aptr->dist]; active[aptr->dist] = NULL; aptr->alive = FALSE; aptr->dist = n; --bound; goto node_ready; } else { /* determine new label value */ dmin = n; aptr->scan_ptr = NULL; eptr = aptr->first_edge; while ( eptr != NULL ) { assert(eptr->rcap <= EPS || eptr->cap > EPS); if ( eptr->adjac->dist < dmin && eptr->rcap > EPS ) { assert(eptr->cap > EPS); dmin = eptr->adjac->dist; if ( aptr->scan_ptr == NULL ) aptr->scan_ptr = eptr; } eptr = eptr->next; } if ( ++dmin < bound ) { /* ordinary relabel operation */ --number[aptr->dist]; aptr->dist = dmin; ++number[dmin]; max_dist = dmin; eptr = aptr->scan_ptr; assert(eptr != NULL); assert(eptr->cap > EPS); goto edge_scan; } else { aptr->alive = FALSE; --number[aptr->dist]; aptr->dist = n; --bound; goto node_ready; } } } else goto edge_scan; node_ready: ++n_discharge; if ( n_discharge == n ) { n_discharge = 0L; global_relabel (gr, t_ptr); } aptr = active[max_dist]; } /* aptr != NULL */ --max_dist; } while ( max_dist > 0L ); return (t_ptr->excess - 1.0L); }