Esempio n. 1
0
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
Esempio n. 2
0
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);
}