maxflow.cpp
Go to the documentation of this file.
00001 /* maxflow.cpp */
00002 
00003 
00004 #include <stdio.h>
00005 #include "graph.h"
00006 
00007 
00008 /*
00009         special constants for node->parent
00010 */
00011 #define TERMINAL ( (arc *) 1 )          /* to terminal */
00012 #define ORPHAN   ( (arc *) 2 )          /* orphan */
00013 
00014 
00015 #define INFINITE_D ((int)(((unsigned)-1)/2))            /* infinite distance to the terminal */
00016 
00017 /***********************************************************************/
00018 
00019 /*
00020         Functions for processing active list.
00021         i->next points to the next node in the list
00022         (or to i, if i is the last node in the list).
00023         If i->next is NULL iff i is not in the list.
00024 
00025         There are two queues. Active nodes are added
00026         to the end of the second queue and read from
00027         the front of the first queue. If the first queue
00028         is empty, it is replaced by the second queue
00029         (and the second queue becomes empty).
00030 */
00031 
00032 
00033 template <typename captype, typename tcaptype, typename flowtype> 
00034         inline void Graph<captype,tcaptype,flowtype>::set_active(node *i)
00035 {
00036         if (!i->next)
00037         {
00038                 /* it's not in the list yet */
00039                 if (queue_last[1]) queue_last[1] -> next = i;
00040                 else               queue_first[1]        = i;
00041                 queue_last[1] = i;
00042                 i -> next = i;
00043         }
00044 }
00045 
00046 /*
00047         Returns the next active node.
00048         If it is connected to the sink, it stays in the list,
00049         otherwise it is removed from the list
00050 */
00051 template <typename captype, typename tcaptype, typename flowtype> 
00052         inline typename Graph<captype,tcaptype,flowtype>::node* Graph<captype,tcaptype,flowtype>::next_active()
00053 {
00054         node *i;
00055 
00056         while ( 1 )
00057         {
00058                 if (!(i=queue_first[0]))
00059                 {
00060                         queue_first[0] = i = queue_first[1];
00061                         queue_last[0]  = queue_last[1];
00062                         queue_first[1] = NULL;
00063                         queue_last[1]  = NULL;
00064                         if (!i) return NULL;
00065                 }
00066 
00067                 /* remove it from the active list */
00068                 if (i->next == i) queue_first[0] = queue_last[0] = NULL;
00069                 else              queue_first[0] = i -> next;
00070                 i -> next = NULL;
00071 
00072                 /* a node in the list is active iff it has a parent */
00073                 if (i->parent) return i;
00074         }
00075 }
00076 
00077 /***********************************************************************/
00078 
00079 template <typename captype, typename tcaptype, typename flowtype> 
00080         inline void Graph<captype,tcaptype,flowtype>::set_orphan_front(node *i)
00081 {
00082         nodeptr *np;
00083         i -> parent = ORPHAN;
00084         np = nodeptr_block -> New();
00085         np -> ptr = i;
00086         np -> next = orphan_first;
00087         orphan_first = np;
00088 }
00089 
00090 template <typename captype, typename tcaptype, typename flowtype> 
00091         inline void Graph<captype,tcaptype,flowtype>::set_orphan_rear(node *i)
00092 {
00093         nodeptr *np;
00094         i -> parent = ORPHAN;
00095         np = nodeptr_block -> New();
00096         np -> ptr = i;
00097         if (orphan_last) orphan_last -> next = np;
00098         else             orphan_first        = np;
00099         orphan_last = np;
00100         np -> next = NULL;
00101 }
00102 
00103 /***********************************************************************/
00104 
00105 template <typename captype, typename tcaptype, typename flowtype> 
00106         inline void Graph<captype,tcaptype,flowtype>::add_to_changed_list(node *i)
00107 {
00108         if (changed_list && !i->is_in_changed_list)
00109         {
00110                 node_id* ptr = changed_list->New();
00111                 *ptr = (node_id)(i - nodes);
00112                 i->is_in_changed_list = true;
00113         }
00114 }
00115 
00116 /***********************************************************************/
00117 
00118 template <typename captype, typename tcaptype, typename flowtype> 
00119         void Graph<captype,tcaptype,flowtype>::maxflow_init()
00120 {
00121         node *i;
00122 
00123         queue_first[0] = queue_last[0] = NULL;
00124         queue_first[1] = queue_last[1] = NULL;
00125         orphan_first = NULL;
00126 
00127         TIME = 0;
00128 
00129         for (i=nodes; i<node_last; i++)
00130         {
00131                 i -> next = NULL;
00132                 i -> is_marked = 0;
00133                 i -> is_in_changed_list = 0;
00134                 i -> TS = TIME;
00135                 if (i->tr_cap > 0)
00136                 {
00137                         /* i is connected to the source */
00138                         i -> is_sink = 0;
00139                         i -> parent = TERMINAL;
00140                         set_active(i);
00141                         i -> DIST = 1;
00142                 }
00143                 else if (i->tr_cap < 0)
00144                 {
00145                         /* i is connected to the sink */
00146                         i -> is_sink = 1;
00147                         i -> parent = TERMINAL;
00148                         set_active(i);
00149                         i -> DIST = 1;
00150                 }
00151                 else
00152                 {
00153                         i -> parent = NULL;
00154                 }
00155         }
00156 }
00157 
00158 template <typename captype, typename tcaptype, typename flowtype> 
00159         void Graph<captype,tcaptype,flowtype>::maxflow_reuse_trees_init()
00160 {
00161         node* i;
00162         node* j;
00163         node* queue = queue_first[1];
00164         arc* a;
00165         nodeptr* np;
00166 
00167         queue_first[0] = queue_last[0] = NULL;
00168         queue_first[1] = queue_last[1] = NULL;
00169         orphan_first = orphan_last = NULL;
00170 
00171         TIME ++;
00172 
00173         while ((i=queue))
00174         {
00175                 queue = i->next;
00176                 if (queue == i) queue = NULL;
00177                 i->next = NULL;
00178                 i->is_marked = 0;
00179                 set_active(i);
00180 
00181                 if (i->tr_cap == 0)
00182                 {
00183                         if (i->parent) set_orphan_rear(i);
00184                         continue;
00185                 }
00186 
00187                 if (i->tr_cap > 0)
00188                 {
00189                         if (!i->parent || i->is_sink)
00190                         {
00191                                 i->is_sink = 0;
00192                                 for (a=i->first; a; a=a->next)
00193                                 {
00194                                         j = a->head;
00195                                         if (!j->is_marked)
00196                                         {
00197                                                 if (j->parent == a->sister) set_orphan_rear(j);
00198                                                 if (j->parent && j->is_sink && a->r_cap > 0) set_active(j);
00199                                         }
00200                                 }
00201                                 add_to_changed_list(i);
00202                         }
00203                 }
00204                 else
00205                 {
00206                         if (!i->parent || !i->is_sink)
00207                         {
00208                                 i->is_sink = 1;
00209                                 for (a=i->first; a; a=a->next)
00210                                 {
00211                                         j = a->head;
00212                                         if (!j->is_marked)
00213                                         {
00214                                                 if (j->parent == a->sister) set_orphan_rear(j);
00215                                                 if (j->parent && !j->is_sink && a->sister->r_cap > 0) set_active(j);
00216                                         }
00217                                 }
00218                                 add_to_changed_list(i);
00219                         }
00220                 }
00221                 i->parent = TERMINAL;
00222                 i -> TS = TIME;
00223                 i -> DIST = 1;
00224         }
00225 
00226         //test_consistency();
00227 
00228         /* adoption */
00229         while ((np=orphan_first))
00230         {
00231                 orphan_first = np -> next;
00232                 i = np -> ptr;
00233                 nodeptr_block -> Delete(np);
00234                 if (!orphan_first) orphan_last = NULL;
00235                 if (i->is_sink) process_sink_orphan(i);
00236                 else            process_source_orphan(i);
00237         }
00238         /* adoption end */
00239 
00240         //test_consistency();
00241 }
00242 
00243 template <typename captype, typename tcaptype, typename flowtype> 
00244         void Graph<captype,tcaptype,flowtype>::augment(arc *middle_arc)
00245 {
00246         node *i;
00247         arc *a;
00248         tcaptype bottleneck;
00249 
00250 
00251         /* 1. Finding bottleneck capacity */
00252         /* 1a - the source tree */
00253         bottleneck = middle_arc -> r_cap;
00254         for (i=middle_arc->sister->head; ; i=a->head)
00255         {
00256                 a = i -> parent;
00257                 if (a == TERMINAL) break;
00258                 if (bottleneck > a->sister->r_cap) bottleneck = a -> sister -> r_cap;
00259         }
00260         if (bottleneck > i->tr_cap) bottleneck = i -> tr_cap;
00261         /* 1b - the sink tree */
00262         for (i=middle_arc->head; ; i=a->head)
00263         {
00264                 a = i -> parent;
00265                 if (a == TERMINAL) break;
00266                 if (bottleneck > a->r_cap) bottleneck = a -> r_cap;
00267         }
00268         if (bottleneck > - i->tr_cap) bottleneck = - i -> tr_cap;
00269 
00270 
00271         /* 2. Augmenting */
00272         /* 2a - the source tree */
00273         middle_arc -> sister -> r_cap += bottleneck;
00274         middle_arc -> r_cap -= bottleneck;
00275         for (i=middle_arc->sister->head; ; i=a->head)
00276         {
00277                 a = i -> parent;
00278                 if (a == TERMINAL) break;
00279                 a -> r_cap += bottleneck;
00280                 a -> sister -> r_cap -= bottleneck;
00281                 if (!a->sister->r_cap)
00282                 {
00283                         set_orphan_front(i); // add i to the beginning of the adoption list
00284                 }
00285         }
00286         i -> tr_cap -= bottleneck;
00287         if (!i->tr_cap)
00288         {
00289                 set_orphan_front(i); // add i to the beginning of the adoption list
00290         }
00291         /* 2b - the sink tree */
00292         for (i=middle_arc->head; ; i=a->head)
00293         {
00294                 a = i -> parent;
00295                 if (a == TERMINAL) break;
00296                 a -> sister -> r_cap += bottleneck;
00297                 a -> r_cap -= bottleneck;
00298                 if (!a->r_cap)
00299                 {
00300                         set_orphan_front(i); // add i to the beginning of the adoption list
00301                 }
00302         }
00303         i -> tr_cap += bottleneck;
00304         if (!i->tr_cap)
00305         {
00306                 set_orphan_front(i); // add i to the beginning of the adoption list
00307         }
00308 
00309 
00310         flow += bottleneck;
00311 }
00312 
00313 /***********************************************************************/
00314 
00315 template <typename captype, typename tcaptype, typename flowtype> 
00316         void Graph<captype,tcaptype,flowtype>::process_source_orphan(node *i)
00317 {
00318         node *j;
00319         arc *a0, *a0_min = NULL, *a;
00320         int d, d_min = INFINITE_D;
00321 
00322         /* trying to find a new parent */
00323         for (a0=i->first; a0; a0=a0->next)
00324         if (a0->sister->r_cap)
00325         {
00326                 j = a0 -> head;
00327                 if (!j->is_sink && (a=j->parent))
00328                 {
00329                         /* checking the origin of j */
00330                         d = 0;
00331                         while ( 1 )
00332                         {
00333                                 if (j->TS == TIME)
00334                                 {
00335                                         d += j -> DIST;
00336                                         break;
00337                                 }
00338                                 a = j -> parent;
00339                                 d ++;
00340                                 if (a==TERMINAL)
00341                                 {
00342                                         j -> TS = TIME;
00343                                         j -> DIST = 1;
00344                                         break;
00345                                 }
00346                                 if (a==ORPHAN) { d = INFINITE_D; break; }
00347                                 j = a -> head;
00348                         }
00349                         if (d<INFINITE_D) /* j originates from the source - done */
00350                         {
00351                                 if (d<d_min)
00352                                 {
00353                                         a0_min = a0;
00354                                         d_min = d;
00355                                 }
00356                                 /* set marks along the path */
00357                                 for (j=a0->head; j->TS!=TIME; j=j->parent->head)
00358                                 {
00359                                         j -> TS = TIME;
00360                                         j -> DIST = d --;
00361                                 }
00362                         }
00363                 }
00364         }
00365 
00366         if (i->parent = a0_min)
00367         {
00368                 i -> TS = TIME;
00369                 i -> DIST = d_min + 1;
00370         }
00371         else
00372         {
00373                 /* no parent is found */
00374                 add_to_changed_list(i);
00375 
00376                 /* process neighbors */
00377                 for (a0=i->first; a0; a0=a0->next)
00378                 {
00379                         j = a0 -> head;
00380                         if (!j->is_sink && (a=j->parent))
00381                         {
00382                                 if (a0->sister->r_cap) set_active(j);
00383                                 if (a!=TERMINAL && a!=ORPHAN && a->head==i)
00384                                 {
00385                                         set_orphan_rear(j); // add j to the end of the adoption list
00386                                 }
00387                         }
00388                 }
00389         }
00390 }
00391 
00392 template <typename captype, typename tcaptype, typename flowtype> 
00393         void Graph<captype,tcaptype,flowtype>::process_sink_orphan(node *i)
00394 {
00395         node *j;
00396         arc *a0, *a0_min = NULL, *a;
00397         int d, d_min = INFINITE_D;
00398 
00399         /* trying to find a new parent */
00400         for (a0=i->first; a0; a0=a0->next)
00401         if (a0->r_cap)
00402         {
00403                 j = a0 -> head;
00404                 if (j->is_sink && (a=j->parent))
00405                 {
00406                         /* checking the origin of j */
00407                         d = 0;
00408                         while ( 1 )
00409                         {
00410                                 if (j->TS == TIME)
00411                                 {
00412                                         d += j -> DIST;
00413                                         break;
00414                                 }
00415                                 a = j -> parent;
00416                                 d ++;
00417                                 if (a==TERMINAL)
00418                                 {
00419                                         j -> TS = TIME;
00420                                         j -> DIST = 1;
00421                                         break;
00422                                 }
00423                                 if (a==ORPHAN) { d = INFINITE_D; break; }
00424                                 j = a -> head;
00425                         }
00426                         if (d<INFINITE_D) /* j originates from the sink - done */
00427                         {
00428                                 if (d<d_min)
00429                                 {
00430                                         a0_min = a0;
00431                                         d_min = d;
00432                                 }
00433                                 /* set marks along the path */
00434                                 for (j=a0->head; j->TS!=TIME; j=j->parent->head)
00435                                 {
00436                                         j -> TS = TIME;
00437                                         j -> DIST = d --;
00438                                 }
00439                         }
00440                 }
00441         }
00442 
00443         if (i->parent = a0_min)
00444         {
00445                 i -> TS = TIME;
00446                 i -> DIST = d_min + 1;
00447         }
00448         else
00449         {
00450                 /* no parent is found */
00451                 add_to_changed_list(i);
00452 
00453                 /* process neighbors */
00454                 for (a0=i->first; a0; a0=a0->next)
00455                 {
00456                         j = a0 -> head;
00457                         if (j->is_sink && (a=j->parent))
00458                         {
00459                                 if (a0->r_cap) set_active(j);
00460                                 if (a!=TERMINAL && a!=ORPHAN && a->head==i)
00461                                 {
00462                                         set_orphan_rear(j); // add j to the end of the adoption list
00463                                 }
00464                         }
00465                 }
00466         }
00467 }
00468 
00469 /***********************************************************************/
00470 
00471 template <typename captype, typename tcaptype, typename flowtype> 
00472         flowtype Graph<captype,tcaptype,flowtype>::maxflow(bool reuse_trees, Block<node_id>* _changed_list)
00473 {
00474         node *i, *j, *current_node = NULL;
00475         arc *a;
00476         nodeptr *np, *np_next;
00477 
00478         if (!nodeptr_block)
00479         {
00480                 nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
00481         }
00482 
00483         changed_list = _changed_list;
00484         if (maxflow_iteration == 0 && reuse_trees) { if (error_function) (*error_function)("reuse_trees cannot be used in the first call to maxflow()!"); exit(1); }
00485         if (changed_list && !reuse_trees) { if (error_function) (*error_function)("changed_list cannot be used without reuse_trees!"); exit(1); }
00486 
00487         if (reuse_trees) maxflow_reuse_trees_init();
00488         else             maxflow_init();
00489 
00490         // main loop
00491         while ( 1 )
00492         {
00493                 // test_consistency(current_node);
00494 
00495                 if ((i=current_node))
00496                 {
00497                         i -> next = NULL; /* remove active flag */
00498                         if (!i->parent) i = NULL;
00499                 }
00500                 if (!i)
00501                 {
00502                         if (!(i = next_active())) break;
00503                 }
00504 
00505                 /* growth */
00506                 if (!i->is_sink)
00507                 {
00508                         /* grow source tree */
00509                         for (a=i->first; a; a=a->next)
00510                         if (a->r_cap)
00511                         {
00512                                 j = a -> head;
00513                                 if (!j->parent)
00514                                 {
00515                                         j -> is_sink = 0;
00516                                         j -> parent = a -> sister;
00517                                         j -> TS = i -> TS;
00518                                         j -> DIST = i -> DIST + 1;
00519                                         set_active(j);
00520                                         add_to_changed_list(j);
00521                                 }
00522                                 else if (j->is_sink) break;
00523                                 else if (j->TS <= i->TS &&
00524                                          j->DIST > i->DIST)
00525                                 {
00526                                         /* heuristic - trying to make the distance from j to the source shorter */
00527                                         j -> parent = a -> sister;
00528                                         j -> TS = i -> TS;
00529                                         j -> DIST = i -> DIST + 1;
00530                                 }
00531                         }
00532                 }
00533                 else
00534                 {
00535                         /* grow sink tree */
00536                         for (a=i->first; a; a=a->next)
00537                         if (a->sister->r_cap)
00538                         {
00539                                 j = a -> head;
00540                                 if (!j->parent)
00541                                 {
00542                                         j -> is_sink = 1;
00543                                         j -> parent = a -> sister;
00544                                         j -> TS = i -> TS;
00545                                         j -> DIST = i -> DIST + 1;
00546                                         set_active(j);
00547                                         add_to_changed_list(j);
00548                                 }
00549                                 else if (!j->is_sink) { a = a -> sister; break; }
00550                                 else if (j->TS <= i->TS &&
00551                                          j->DIST > i->DIST)
00552                                 {
00553                                         /* heuristic - trying to make the distance from j to the sink shorter */
00554                                         j -> parent = a -> sister;
00555                                         j -> TS = i -> TS;
00556                                         j -> DIST = i -> DIST + 1;
00557                                 }
00558                         }
00559                 }
00560 
00561                 TIME ++;
00562 
00563                 if (a)
00564                 {
00565                         i -> next = i; /* set active flag */
00566                         current_node = i;
00567 
00568                         /* augmentation */
00569                         augment(a);
00570                         /* augmentation end */
00571 
00572                         /* adoption */
00573                         while ((np=orphan_first))
00574                         {
00575                                 np_next = np -> next;
00576                                 np -> next = NULL;
00577 
00578                                 while ((np=orphan_first))
00579                                 {
00580                                         orphan_first = np -> next;
00581                                         i = np -> ptr;
00582                                         nodeptr_block -> Delete(np);
00583                                         if (!orphan_first) orphan_last = NULL;
00584                                         if (i->is_sink) process_sink_orphan(i);
00585                                         else            process_source_orphan(i);
00586                                 }
00587 
00588                                 orphan_first = np_next;
00589                         }
00590                         /* adoption end */
00591                 }
00592                 else current_node = NULL;
00593         }
00594         // test_consistency();
00595 
00596         if (!reuse_trees || (maxflow_iteration % 64) == 0)
00597         {
00598                 delete nodeptr_block; 
00599                 nodeptr_block = NULL; 
00600         }
00601 
00602         maxflow_iteration ++;
00603         return flow;
00604 }
00605 
00606 /***********************************************************************/
00607 
00608 
00609 template <typename captype, typename tcaptype, typename flowtype> 
00610         void Graph<captype,tcaptype,flowtype>::test_consistency(node* current_node)
00611 {
00612         node *i;
00613         arc *a;
00614         int r;
00615         int num1 = 0, num2 = 0;
00616 
00617         // test whether all nodes i with i->next!=NULL are indeed in the queue
00618         for (i=nodes; i<node_last; i++)
00619         {
00620                 if (i->next || i==current_node) num1 ++;
00621         }
00622         for (r=0; r<3; r++)
00623         {
00624                 i = (r == 2) ? current_node : queue_first[r];
00625                 if (i)
00626                 for ( ; ; i=i->next)
00627                 {
00628                         num2 ++;
00629                         if (i->next == i)
00630                         {
00631                                 if (r<2) assert(i == queue_last[r]);
00632                                 else     assert(i == current_node);
00633                                 break;
00634                         }
00635                 }
00636         }
00637         assert(num1 == num2);
00638 
00639         for (i=nodes; i<node_last; i++)
00640         {
00641                 // test whether all edges in seach trees are non-saturated
00642                 if (i->parent == NULL) {}
00643                 else if (i->parent == ORPHAN) {}
00644                 else if (i->parent == TERMINAL)
00645                 {
00646                         if (!i->is_sink) assert(i->tr_cap > 0);
00647                         else             assert(i->tr_cap < 0);
00648                 }
00649                 else
00650                 {
00651                         if (!i->is_sink) assert (i->parent->sister->r_cap > 0);
00652                         else             assert (i->parent->r_cap > 0);
00653                 }
00654                 // test whether passive nodes in search trees have neighbors in
00655                 // a different tree through non-saturated edges
00656                 if (i->parent && !i->next)
00657                 {
00658                         if (!i->is_sink)
00659                         {
00660                                 assert(i->tr_cap >= 0);
00661                                 for (a=i->first; a; a=a->next)
00662                                 {
00663                                         if (a->r_cap > 0) assert(a->head->parent && !a->head->is_sink);
00664                                 }
00665                         }
00666                         else
00667                         {
00668                                 assert(i->tr_cap <= 0);
00669                                 for (a=i->first; a; a=a->next)
00670                                 {
00671                                         if (a->sister->r_cap > 0) assert(a->head->parent && a->head->is_sink);
00672                                 }
00673                         }
00674                 }
00675                 // test marking invariants
00676                 if (i->parent && i->parent!=ORPHAN && i->parent!=TERMINAL)
00677                 {
00678                         assert(i->TS <= i->parent->head->TS);
00679                         if (i->TS == i->parent->head->TS) assert(i->DIST > i->parent->head->DIST);
00680                 }
00681         }
00682 }
00683 
00684 template <typename captype, typename tcaptype, typename flowtype> 
00685         void Graph<captype,tcaptype,flowtype>::Copy(Graph<captype, tcaptype, flowtype>* g0)
00686 {
00687         node* i;
00688         arc* a;
00689 
00690         reset();
00691 
00692         if (node_max < nodes + g0->node_num)
00693         {
00694                 free(nodes);
00695                 nodes = node_last = (node*) malloc(g0->node_num*sizeof(node));
00696                 node_max = nodes + g0->node_num;
00697         }
00698         if (arc_max < arcs + (g0->arc_last - g0->arcs))
00699         {
00700                 free(arcs);
00701                 arcs = arc_last = (arc*) malloc((g0->arc_last - g0->arcs)*sizeof(arc));
00702                 arc_max = arcs + (g0->arc_last - g0->arcs);
00703         }
00704 
00705         node_num = g0->node_num;
00706         node_last = nodes + node_num;
00707         memcpy(nodes, g0->nodes, node_num*sizeof(node));
00708         for (i=nodes; i<node_last; i++)
00709         {
00710                 if (i->first) i->first  = (arc*)((char*)arcs + (((char*)i->first)  - ((char*)g0->arcs)));
00711                 if (i->parent && i->parent!=TERMINAL && i->parent!=ORPHAN) i->parent = (arc*)((char*)arcs + (((char*)i->parent) - ((char*)g0->arcs)));
00712                 if (i->next) i->next   = (node*)((char*)nodes + (((char*)i->next) - ((char*)g0->nodes)));
00713         }
00714 
00715         arc_last = arcs + (g0->arc_last - g0->arcs);
00716         memcpy(arcs, g0->arcs, (g0->arc_last - g0->arcs)*sizeof(arc));
00717         for (a=arcs; a<arc_last; a++)
00718         {
00719                 a->head    = (node*)((char*)nodes + (((char*)a->head)  - ((char*)g0->nodes)));
00720                 if (a->next) a->next = (arc*)((char*)arcs + (((char*)a->next)    - ((char*)g0->arcs)));
00721                 a->sister  = (arc*)((char*)arcs + (((char*)a->sister)  - ((char*)g0->arcs)));
00722         }
00723 
00724         error_function = g0->error_function;
00725         flow = g0->flow;
00726         maxflow_iteration = g0->maxflow_iteration;
00727 
00728         queue_first[0] = (g0->queue_first[0]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_first[0]) - ((char*)g0->nodes)));
00729         queue_first[1] = (g0->queue_first[1]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_first[1]) - ((char*)g0->nodes)));
00730         queue_last[0] = (g0->queue_last[0]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_last[0]) - ((char*)g0->nodes)));
00731         queue_last[1] = (g0->queue_last[1]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_last[1]) - ((char*)g0->nodes)));
00732         TIME = g0->TIME;
00733 }


tabletop_pushing
Author(s): Tucker Hermans
autogenerated on Wed Nov 27 2013 11:59:44