Graphviz  2.29.20120523.0446
lib/dotgen/aspect.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #include "dot.h"
00015 
00016 /*
00017  * Author: Mohammad T. Irfan
00018  *   Summer, 2008
00019  */
00020 
00021 /* TODO:
00022  *   - Support clusters
00023  *   - Support disconnected graphs
00024  *   - Provide algorithms for aspect ratios < 1
00025  */
00026 
00027 #define DPI 72
00028 
00029 /*
00030  *       NODE GROUPS FOR SAME RANKING
00031  *       Node group data structure groups nodes together for
00032  *       MIN, MAX, SOURCE, SINK constraints.
00033  *       The grouping is based on the union-find data structure and
00034  *       provides sequential access to the nodes in the same group.
00035  */
00036 
00037 /* data structure for node groups */
00038 typedef struct nodeGroup_t {
00039     node_t **nodes;
00040     int nNodes;
00041     double width, height;
00042 } nodeGroup_t;
00043 
00044 static nodeGroup_t *nodeGroups;
00045 static int nNodeGroups = 0;
00046 
00047 /* computeNodeGroups:
00048  * computeNodeGroups function does the groupings of nodes.   
00049  * The grouping is based on the union-find data structure.
00050  */
00051 static void computeNodeGroups(graph_t * g)
00052 {
00053     node_t *n;
00054 
00055     nodeGroups = N_GNEW(agnnodes(g), nodeGroup_t);
00056 
00057     nNodeGroups = 0;
00058 
00059     /* initialize node ids. Id of a node is used as an index to the group. */
00060     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00061         ND_id(n) = -1;
00062     }
00063 
00064     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00065         if (ND_UF_size(n) == 0) {       /* no same ranking constraint */
00066             nodeGroups[nNodeGroups].nodes = NEW(node_t *);
00067             nodeGroups[nNodeGroups].nodes[0] = n;
00068             nodeGroups[nNodeGroups].nNodes = 1;
00069             nodeGroups[nNodeGroups].width = ND_width(n);
00070             nodeGroups[nNodeGroups].height = ND_height(n);
00071 
00072             ND_id(n) = nNodeGroups;
00073             nNodeGroups++;
00074         } else                  /* group same ranked nodes */
00075         {
00076             node_t *l = UF_find(n);
00077             if (ND_id(l) > -1)  /* leader is already grouped */
00078             {
00079                 int index = ND_id(l);
00080                 nodeGroups[index].nodes[nodeGroups[index].nNodes++] = n;
00081                 nodeGroups[index].width += ND_width(n);
00082                 nodeGroups[index].height =
00083                     (nodeGroups[index].height <
00084                      ND_height(n)) ? ND_height(n) : nodeGroups[index].
00085                     height;
00086 
00087                 ND_id(n) = index;
00088             } else              /* create a new group */
00089             {
00090                 nodeGroups[nNodeGroups].nodes =
00091                     N_NEW(ND_UF_size(l), node_t *);
00092 
00093                 if (l == n)     /* node n is the leader */
00094                 {
00095                     nodeGroups[nNodeGroups].nodes[0] = l;
00096                     nodeGroups[nNodeGroups].nNodes = 1;
00097                     nodeGroups[nNodeGroups].width = ND_width(l);
00098                     nodeGroups[nNodeGroups].height = ND_height(l);
00099                 } else {
00100                     nodeGroups[nNodeGroups].nodes[0] = l;
00101                     nodeGroups[nNodeGroups].nodes[1] = n;
00102                     nodeGroups[nNodeGroups].nNodes = 2;
00103                     nodeGroups[nNodeGroups].width =
00104                         ND_width(l) + ND_width(n);
00105                     nodeGroups[nNodeGroups].height =
00106                         (ND_height(l) <
00107                          ND_height(n)) ? ND_height(n) : ND_height(l);
00108                 }
00109 
00110                 ND_id(l) = nNodeGroups;
00111                 ND_id(n) = nNodeGroups;
00112                 nNodeGroups++;
00113             }
00114         }
00115     }
00116 
00117 }
00118 
00119 /*
00120  *       END OF CODES FOR NODE GROUPS 
00121  */
00122 
00123 /* countDummyNodes:
00124  *  Count the number of dummy nodes
00125  */
00126 int countDummyNodes(graph_t * g)
00127 {
00128     int count = 0;
00129     node_t *n;
00130     edge_t *e;
00131 
00132     /* Count dummy nodes */
00133     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00134         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00135 #ifdef UNUSED
00136             /* this loop can be avoided */
00137             for (k = ND_rank(agtail(e))+1; k < ND_rank(aghead(e)); k++) {
00138                count++;
00139             }
00140 #endif
00141                 /* flat edges do not have dummy nodes */
00142             if (ND_rank(aghead(e)) != ND_rank(agtail(e)))       
00143                 count += abs(ND_rank(aghead(e)) - ND_rank(agtail(e))) - 1;
00144         }
00145     }
00146     return count;
00147 }
00148 
00149 /*
00150  *       FFDH PACKING ALGORITHM TO ACHIEVE TARGET ASPECT RATIO
00151  */
00152 
00153 /*
00154  *  layerWidthInfo_t: data structure for keeping layer width information
00155  *  Each layer consists of a number of node groups.
00156  */
00157 typedef struct layerWidthInfo_t {
00158     int layerNumber;
00159     nodeGroup_t **nodeGroupsInLayer;
00160     int *removed;               /* is the node group removed? */
00161     int nNodeGroupsInLayer;
00162     int nDummyNodes;
00163     double width;
00164     double height;
00165 } layerWidthInfo_t;
00166 
00167 static layerWidthInfo_t *layerWidthInfo = NULL;
00168 static int *sortedLayerIndex;
00169 static int nLayers = 0;
00170 
00171 /* computeLayerWidths:
00172  */
00173 static void computeLayerWidths(graph_t * g)
00174 {
00175     int i;
00176     node_t *v;
00177     node_t *n;
00178     edge_t *e;
00179 
00180     nLayers = 0;
00181 
00182     /* free previously allocated memory */
00183     if (layerWidthInfo) {
00184         for (i = 0; i < nNodeGroups; i++) {
00185             if (layerWidthInfo[i].nodeGroupsInLayer) {
00186                 int j;
00187                 for (j = 0; j < layerWidthInfo[i].nNodeGroupsInLayer; j++) {
00188                     //if (layerWidthInfo[i].nodeGroupsInLayer[j])
00189                     //free(layerWidthInfo[i].nodeGroupsInLayer[j]);
00190                 }
00191                 free(layerWidthInfo[i].nodeGroupsInLayer);
00192             }
00193             if (layerWidthInfo[i].removed)
00194                 free(layerWidthInfo[i].removed);
00195         }
00196 
00197         free(layerWidthInfo);
00198     }
00199     /* allocate memory
00200      * the number of layers can go up to the number of node groups
00201      */
00202     layerWidthInfo = N_NEW(nNodeGroups, layerWidthInfo_t);
00203 
00204     for (i = 0; i < nNodeGroups; i++) {
00205         layerWidthInfo[i].nodeGroupsInLayer =
00206             N_NEW(nNodeGroups, nodeGroup_t *);
00207 
00208         layerWidthInfo[i].removed = N_NEW(nNodeGroups, int);
00209 
00210         layerWidthInfo[i].layerNumber = i;
00211         layerWidthInfo[i].nNodeGroupsInLayer = 0;
00212         layerWidthInfo[i].nDummyNodes = 0;
00213         layerWidthInfo[i].width = 0.0;
00214         layerWidthInfo[i].height = 0.0;
00215     }
00216 
00217 
00218 
00219     /* Count dummy nodes in the layer */
00220     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00221         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00222             int k;
00223 
00224             /* FIX: This loop maybe unnecessary, but removing it and using 
00225              * the commented codes next, gives a segmentation fault. I 
00226              * forgot the reason why.
00227              */
00228             for (k = ND_rank(agtail(e)) + 1; k < ND_rank(aghead(e)); k++) {
00229                 layerWidthInfo[k].nDummyNodes++;
00230             }
00231 
00232 #ifdef UNUSED
00233             if (ND_rank(aghead(e)) != ND_rank(agtail(e)))
00234                 /* flat edges do not have dummy nodes  */
00235                 layerWidthInfo[k].nDummyNodes = abs(ND_rank(aghead(e)) - ND_rank(agtail(e))) - 1;
00236 #endif
00237         }
00238 
00239 #ifdef UNUSED
00240   /*****************************************************************
00241    * This code is removed. It considers dummy nodes in layer width,
00242    * which does not give good results in experiments.
00243    *****************************************************************/
00244 
00245     for (i = 0; i < nNodeGroups; i++) {
00246        v = nodeGroups[i].nodes[0];
00247        layerWidthInfo[ND_rank(v)].width = (layerWidthInfo[ND_rank(v)].nDummyNodes - 1) * GD_nodesep(g); 
00248        }
00249 #endif
00250 
00251     /* gather the layer information */
00252     for (i = 0; i < nNodeGroups; i++) {
00253         v = nodeGroups[i].nodes[0];
00254         if (ND_rank(v) + 1 > nLayers)   /* update the number of layers */
00255             nLayers = ND_rank(v) + 1;
00256 
00257         layerWidthInfo[ND_rank(v)].width +=
00258             nodeGroups[i].width * DPI + (layerWidthInfo[ND_rank(v)].width >
00259                                          0) * GD_nodesep(g);
00260         if (layerWidthInfo[ND_rank(v)].height < nodeGroups[i].height * DPI)
00261             layerWidthInfo[ND_rank(v)].height = nodeGroups[i].height * DPI;
00262         layerWidthInfo[ND_rank(v)].
00263             nodeGroupsInLayer[layerWidthInfo[ND_rank(v)].
00264                               nNodeGroupsInLayer] = &nodeGroups[i];
00265         layerWidthInfo[ND_rank(v)].nNodeGroupsInLayer++;
00266     }
00267 
00268 }
00269 
00270 /* compFunction:
00271  * Comparison function to be used in qsort.
00272  * For sorting the layers by nonincreasing width
00273  */
00274 static int compFunction(const void *a, const void *b)
00275 {
00276     int *ind1 = (int *) a;
00277     int *ind2 = (int *) b;
00278 
00279     return (layerWidthInfo[*ind2].width >
00280             layerWidthInfo[*ind1].width) - (layerWidthInfo[*ind2].width <
00281                                             layerWidthInfo[*ind1].width);
00282 }
00283 
00284 /* sortLayers:
00285  * Sort the layers by width (nonincreasing order)
00286  * qsort should be replaced by insertion sort for better performance.
00287  * (layers are "almost" sorted during iterations)
00288  */
00289 static void sortLayers(graph_t * g)
00290 {
00291     qsort(sortedLayerIndex, agnnodes(g), sizeof(int), compFunction);
00292 }
00293 
00294 #ifdef UNUSED
00295 /* getMaxDummyNodes:
00296  * get the max # of dummy nodes on the incoming edges to a nodeGroup
00297  */
00298 static int getMaxDummyNodes(nodeGroup_t * ng)
00299 {
00300     int i, max = 0, cnt = 0;
00301     for (i = 0; i < ng->nNodes; i++) {
00302         node_t *n = ng->nodes[i];
00303         edge_t *e;
00304         graph_t *g = agraphof(n);
00305         for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
00306             cnt += ND_rank(aghead(e)) - ND_rank(agtail(e));     // it's 1 more than the original count
00307             if (ND_rank(aghead(e)) - ND_rank(agtail(e)) > max)
00308                 max = ND_rank(aghead(e)) - ND_rank(agtail(e));
00309         }
00310     }
00311 
00312     return max;
00313 }
00314 #endif
00315 
00316 /* getOutDegree:
00317  * Return the sum of out degrees of the nodes in a node group.
00318  */
00319 static int getOutDegree(nodeGroup_t * ng)
00320 {
00321     int i, cnt = 0;
00322     for (i = 0; i < ng->nNodes; i++) {
00323         node_t *n = ng->nodes[i];
00324         edge_t *e;
00325         graph_t *g = agraphof(n);
00326 
00327         /* count outdegree. This loop might be unnecessary. */
00328         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00329             cnt++;
00330         }
00331     }
00332 
00333     return cnt;
00334 }
00335 
00336 /* compFunction2:
00337  * Comparison function to be used in qsort.
00338  * For sorting the node groups by their out degrees (nondecreasing)
00339  */
00340 static int compFunction2(const void *a, const void *b)
00341 {
00342     nodeGroup_t **ind1 = (nodeGroup_t **) a, **ind2 = (nodeGroup_t **) b;
00343 
00344     int cnt1 = getOutDegree(*ind1);
00345     int cnt2 = getOutDegree(*ind2);
00346 
00347     return (cnt2 < cnt1) - (cnt2 > cnt1);
00348 }
00349 
00350 #ifdef UNUSED
00351 /* compFunction3:
00352  * Comparison function to be used in qsort.
00353  * For sorting the node groups by their height & width
00354  */
00355 static int compFunction3(const void *a, const void *b)
00356 {
00357     nodeGroup_t **ind1 = (nodeGroup_t **) a, **ind2 = (nodeGroup_t **) b;
00358     if ((*ind2)->height == (*ind1)->height)
00359         return ((*ind2)->width < (*ind1)->width) - ((*ind2)->width >
00360                                                     (*ind1)->width);
00361 
00362     return ((*ind2)->height < (*ind1)->height) - ((*ind2)->height >
00363                                                   (*ind1)->height);
00364 }
00365 
00366 /*****************************************************************
00367  * The following commented codes are no longer used
00368  * Originally used in the cocktail tool.
00369  *****************************************************************/
00370 /* checkLayerConstraints:
00371  * check if there is any node group in the layer 
00372  * that is not constrained by MIN/MAX/SOURCE/SINK-RANK constraints.
00373  */
00374 static int checkLayerConstraints(layerWidthInfo_t lwi)
00375 {
00376     int i;
00377     for (i = 0; i < lwi.nNodeGroupsInLayer; i++) {
00378         if (lwi.nodeGroupsInLayer[i]->nNodes > 0) {
00379             int rtype = ND_ranktype(lwi.nodeGroupsInLayer[i]->nodes[0]);
00380             if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK
00381                 && rtype != SINKRANK)
00382                 return 1;
00383         }
00384     }
00385 
00386     return 0;
00387 }
00388 
00389 /* checkLayerConstraints:
00390  * check if all the node groups in the layer are 
00391  * constrained by MIN/MAX/SOURCE/SINK-RANK constraints
00392  */
00393 static int checkLayerConstraints(layerWidthInfo_t lwi)
00394 {
00395     int i;
00396     for (i = 0; i < lwi.nNodeGroupsInLayer; i++) {
00397         if (lwi.nodeGroupsInLayer[i]->nNodes > 0) {
00398             int rtype = ND_ranktype(lwi.nodeGroupsInLayer[i]->nodes[0]);
00399             if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK
00400                 && rtype != SINKRANK)
00401                 return 0;
00402         }
00403     }
00404 
00405     return 1;
00406 }
00407 
00408 /* checkNodeGroupConstraints:
00409  * check if the node group is not constrained by 
00410  * MIN/MAX/SOURCE/SINK-RANK constraints
00411  * Only used in the cocktail tool.
00412  */
00413 static int checkNodeGroupConstraints(nodeGroup_t * ndg)
00414 {
00415     int i;
00416     int rtype = ND_ranktype(ndg->nodes[0]);
00417 
00418     if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK
00419         && rtype != SINKRANK)
00420         return 1;
00421 
00422     return 0;
00423 }
00424 
00425 /* checkHorizontalEdge:
00426  * check if there is an edge from ng to a node in 
00427  * layerWidthInfo[nextLayerIndex].
00428  * Only used in the cocktail tool.
00429  */
00430 static int
00431 checkHorizontalEdge(graph_t * g, nodeGroup_t * ng, int nextLayerIndex)
00432 {
00433     int i;
00434     edge_t *e;
00435 
00436     for (i = 0; i < ng->nNodes; i++) {
00437         for (e = agfstout(g, ng->nodes[i]); e; e = agnxtout(g, e)) {
00438             if (layerWidthInfo[nextLayerIndex].layerNumber ==
00439                 ND_rank(aghead(e))) {
00440                 return 1;
00441             }
00442         }
00443     }
00444 
00445 
00446     return 0;
00447 }
00448 
00449 /* hasMaxOrSinkNodes:
00450  * check if the the layer lwi has MAX or SINK nodes
00451  * Only used in the cocktail tool.
00452  */
00453 static int hasMaxOrSinkNodes(layerWidthInfo_t * lwi)
00454 {
00455     int i, j;
00456 
00457     for (i = 0; i < lwi->nNodeGroupsInLayer; i++) {
00458         if (lwi->removed[i])
00459             continue;
00460         for (j = 0; j < lwi->nodeGroupsInLayer[i]->nNodes; j++) {
00461             if (ND_ranktype(lwi->nodeGroupsInLayer[i]->nodes[j]) == MAXRANK
00462                 || ND_ranktype(lwi->nodeGroupsInLayer[i]->nodes[j]) ==
00463                 SINKRANK)
00464                 return 1;
00465         }
00466     }
00467 
00468     return 0;
00469 }
00470 
00471 /* reduceMaxWidth:
00472  * The following function is no longer used.
00473  * Originally used for FFDH packing heuristic
00474  * FFDH procedure
00475  */
00476 static void reduceMaxWidth(graph_t * g)
00477 {
00478     int i;
00479     int maxLayerIndex;          // = sortedLayerIndex[0];
00480     double nextMaxWidth;        // = (nLayers > 1) ? layerWidthInfo[sortedLayerIndex[1]].width : 0;
00481     double w = 0;
00482     Agnode_t *v;
00483 
00484     for (i = 0; i < nLayers; i++) {
00485         if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1)        // || !checkLayerConstraints(layerWidthInfo[sortedLayerIndex[i]]))
00486             continue;
00487         else {
00488             maxLayerIndex = sortedLayerIndex[i];
00489             nextMaxWidth =
00490                 (nLayers >
00491                  i + 1) ? layerWidthInfo[sortedLayerIndex[i +
00492                                                           1]].width : 0;
00493             break;
00494         }
00495     }
00496 
00497     if (i == nLayers)
00498         return;                 //reduction of layerwidth is not possible.
00499 
00500 
00501     //sort the node groups in maxLayerIndex layer by height and then width, nonincreasing
00502     qsort(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer,
00503           layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer,
00504           sizeof(nodeGroup_t *), compFunction2);
00505     //printf("ht0 = %lf, ht1 = %lf\n", ND_height(layerWidthInfo[maxLayerIndex].nodes[0]), ND_height(layerWidthInfo[maxLayerIndex].nodes[1]));
00506 
00507 
00508     if (nextMaxWidth <= layerWidthInfo[maxLayerIndex].width / 2
00509         || nextMaxWidth == layerWidthInfo[maxLayerIndex].width)
00510         nextMaxWidth = layerWidthInfo[maxLayerIndex].width / 2;
00511 
00512     double targetWidth = nextMaxWidth;  //layerWidthInfo[maxLayerIndex].width/2;
00513 
00514     //printf("max = %lf, target = %lf\n", layerWidthInfo[maxLayerIndex].width, targetWidth);//,  w + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width );
00515     //getchar();
00516 
00517 
00518     //packing by node demotion
00519     int nextLayerIndex = -1;
00520     for (i = 0; i < nLayers; i++) {
00521         if (layerWidthInfo[i].layerNumber ==
00522             layerWidthInfo[maxLayerIndex].layerNumber + 1)
00523             nextLayerIndex = i;
00524     }
00525 
00526     if (nextLayerIndex > -1) {
00527         //if (layerWidthInfo[nextLayerIndex].width <= 0.5*layerWidthInfo[maxLayerIndex].width)
00528         //{
00529         int changed = 0;
00530         //demote nodes to the next layer
00531         for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer;
00532              i++) {
00533             if (layerWidthInfo[maxLayerIndex].removed[i])
00534                 continue;
00535 
00536             if (!checkHorizontalEdge
00537                 (g, layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i],
00538                  nextLayerIndex)
00539                 && w + layerWidthInfo[nextLayerIndex].width +
00540                 (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->
00541                 width <= targetWidth) {
00542                 w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->
00543                     width;
00544                 changed++;
00545 
00546                 int j;
00547                 nodeGroup_t *ng =
00548                     layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i];
00549 
00550                 layerWidthInfo[maxLayerIndex].removed[i] = 1;
00551                 layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--;
00552                 layerWidthInfo[maxLayerIndex].width -= ng->width;
00553                 for (j = 0; j < ng->nNodes; j++)
00554                     ND_rank(ng->nodes[j])++;
00555 
00556 
00557                 layerWidthInfo[nextLayerIndex].
00558                     nodeGroupsInLayer[layerWidthInfo[nextLayerIndex].
00559                                       nNodeGroupsInLayer] = ng;
00560                 layerWidthInfo[nextLayerIndex].
00561                     removed[layerWidthInfo[nextLayerIndex].
00562                             nNodeGroupsInLayer] = 0;
00563                 layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer++;
00564                 layerWidthInfo[nextLayerIndex].width += ng->width;
00565 
00566                 //int jj;
00567                 //for (jj = 0; jj < layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer; jj++) {
00568                     //Agnode_t *node = layerWidthInfo[nextLayerIndex].nodeGroupsInLayer[jj]->nodes[0];
00569                     //printf("%s\n", agnameof(node));
00570                 //}
00571             }
00572 
00573         }
00574 
00575         if (changed) {
00576             //printf("Demoted %d nodes\n", changed);
00577             return;
00578         }
00579         //}
00580     }
00581     //packing by creating new layers. Must be commented out if packing by demotion is used
00582 
00583     //going to create a new layer. increase the rank of all higher ranked nodes. (to be modified...)
00584     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00585         if (ND_rank(v) > layerWidthInfo[maxLayerIndex].layerNumber)     
00586             ND_rank(v)++;
00587     }
00588 
00589     for (i = 0; i < nLayers; i++) {
00590         if (layerWidthInfo[i].layerNumber >
00591             layerWidthInfo[maxLayerIndex].layerNumber)
00592             layerWidthInfo[i].layerNumber++;
00593     }
00594 
00595     //now partition the current layer into two layers (to be modified to support general case of > 2 layers)
00596     int flag = 0;               //is a new layer created?
00597     int alt = 0;
00598     for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; i++) {
00599         if (layerWidthInfo[maxLayerIndex].removed[i])
00600             continue;
00601 
00602         //nodesep-> only if there are > 1 nodes*******************************
00603         if ((w +
00604              (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width *
00605              DPI + (w > 0) * GD_nodesep(g) <= targetWidth && alt == 0
00606              && ND_ranktype(layerWidthInfo[maxLayerIndex].
00607                             nodeGroupsInLayer[i]->nodes[0]) != SINKRANK
00608              && ND_ranktype(layerWidthInfo[maxLayerIndex].
00609                             nodeGroupsInLayer[i]->nodes[0]) != MAXRANK)
00610             ||
00611             (ND_ranktype
00612              (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->
00613               nodes[0]) != SINKRANK
00614              && ND_ranktype(layerWidthInfo[maxLayerIndex].
00615                             nodeGroupsInLayer[i]->nodes[0]) != MAXRANK
00616              && hasMaxOrSinkNodes(&layerWidthInfo[maxLayerIndex]))
00617             )
00618             //&& ND_pinned(layerWidthInfo[maxLayerIndex].nodes[i]) == 0 ) 
00619         {
00620             w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->
00621                 width * DPI + (w > 0) * GD_nodesep(g);
00622             alt = 1;
00623         } else {
00624             int j;
00625             nodeGroup_t *ng =
00626                 layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i];
00627 
00628             flag = 1;
00629 
00630             layerWidthInfo[maxLayerIndex].removed[i] = 1;
00631             layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--;
00632             layerWidthInfo[maxLayerIndex].nDummyNodes++;        
00633             layerWidthInfo[maxLayerIndex].width -=
00634                 (ng->width * DPI + GD_nodesep(g));
00635             for (j = 0; j < ng->nNodes; j++)
00636                 ND_rank(ng->nodes[j])++;
00637 
00638             //create new layer
00639             layerWidthInfo[nLayers].
00640                 nodeGroupsInLayer[layerWidthInfo[nLayers].
00641                                   nNodeGroupsInLayer] = ng;
00642             layerWidthInfo[nLayers].nNodeGroupsInLayer++;
00643             layerWidthInfo[nLayers].layerNumber = ND_rank(ng->nodes[0]);
00644 
00645             layerWidthInfo[nLayers].width += (ng->width * DPI + (layerWidthInfo[nLayers].nNodeGroupsInLayer > 1) * GD_nodesep(g));      // just add the node widths now. 
00646 
00647             alt = 0;
00648         }
00649     }
00650 
00651     if (flag) {
00652         //calculate number of dummy nodes
00653         node_t *n;
00654         edge_t *e;
00655         int nDummy = 0;
00656 
00657         for (n = agfstnode(g); n; n = agnxtnode(g, n))
00658             for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00659                 if ((ND_rank(aghead(e)) > layerWidthInfo[nLayers].layerNumber
00660                      && ND_rank(agtail(e)) <
00661                      layerWidthInfo[nLayers].layerNumber)
00662                     || (ND_rank(aghead(e)) <
00663                         layerWidthInfo[nLayers].layerNumber
00664                         && ND_rank(agtail(e)) >
00665                         layerWidthInfo[nLayers].layerNumber)
00666                     )
00667                     nDummy++;
00668             }
00669 
00670         layerWidthInfo[nLayers].nDummyNodes = nDummy;
00671         layerWidthInfo[nLayers].width +=
00672             (layerWidthInfo[nLayers].nDummyNodes - 1) * GD_nodesep(g);
00673         nLayers++;
00674     }
00675 
00676     else {
00677         //undo increment of ranks and layerNumbers.*****************
00678         for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00679             if (ND_rank(v) > layerWidthInfo[maxLayerIndex].layerNumber + 1)
00680                 ND_rank(v)--;
00681         }
00682 
00683         for (i = 0; i < nLayers; i++) {
00684             if (layerWidthInfo[i].layerNumber >
00685                 layerWidthInfo[maxLayerIndex].layerNumber + 1)
00686                 layerWidthInfo[i].layerNumber--;
00687         }
00688     }
00689 }
00690 #endif
00691 
00692 /* reduceMaxWidth2:
00693  * This is the main heuristic for partitioning the widest layer.
00694  * Partitioning is based on outdegrees of nodes.
00695  * Replace compFunction2 by compFunction3 if you want to partition
00696  * by node widths and heights.
00697  * FFDH procedure
00698  */
00699 static void reduceMaxWidth2(graph_t * g)
00700 {
00701     int i;
00702     int maxLayerIndex;
00703     double nextMaxWidth;
00704     double w = 0;
00705     double targetWidth;
00706     int fst;
00707     nodeGroup_t *fstNdGrp;
00708     int ndem;
00709     int p, q;
00710     int limit;
00711     int rem;
00712     int rem2;
00713 
00714 
00715     /* Find the widest layer. it must have at least 2 nodes. */
00716     for (i = 0; i < nLayers; i++) {
00717         if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1)
00718             continue;
00719         else {
00720             maxLayerIndex = sortedLayerIndex[i];
00721             /* get the width of the next widest layer */
00722             nextMaxWidth =
00723                 (nLayers >
00724                  i + 1) ? layerWidthInfo[sortedLayerIndex[i +
00725                                                           1]].width : 0;
00726             break;
00727         }
00728     }
00729 
00730     if (i == nLayers)
00731         return;                 /* reduction of layerwidth is not possible. */
00732 
00733     /* sort the node groups in maxLayerIndex layer by height and 
00734      * then width, nonincreasing 
00735      */
00736     qsort(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer,
00737           layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer,
00738           sizeof(nodeGroup_t *), compFunction2);
00739 
00740 #if 0
00741     printf("\nSorted nodes in mx layer:\n---------------------------\n");
00742     for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; i++) {
00743         Agnode_t *node = layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->nodes[0];
00744         printf("%s. width=%lf, height=%lf\n",
00745                agnameof(node), node->width, node->height);
00746     }
00747 #endif
00748 
00749     if (nextMaxWidth <= layerWidthInfo[maxLayerIndex].width / 4
00750         || nextMaxWidth >= layerWidthInfo[maxLayerIndex].width * 3 / 4)
00751         nextMaxWidth = layerWidthInfo[maxLayerIndex].width / 2;
00752 
00753     targetWidth = nextMaxWidth; /* layerWidthInfo[maxLayerIndex].width/2; */
00754 
00755     /* now partition the current layer into two or more 
00756      * layers (determined by the ranking algorithm)
00757      */
00758     fst = 0;
00759     ndem = 0;
00760     limit = layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer;
00761     rem = 0;
00762     rem2 = 0;
00763 
00764     /* initialize w, the width of the widest layer after partitioning */
00765     w = 0;
00766 
00767     for (i = 0; i < limit + rem; i++) {
00768         if (layerWidthInfo[maxLayerIndex].removed[i]) {
00769             rem++;
00770             continue;
00771         }
00772 
00773         if ((w +
00774              layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->width *
00775              DPI + (w > 0) * GD_nodesep(g) <= targetWidth)
00776             || !fst) {
00777             w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->
00778                 width * DPI + (w > 0) * GD_nodesep(g);
00779             if (!fst) {
00780                 fstNdGrp =
00781                     layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i];
00782                 fst = 1;
00783             }
00784         } else {
00785             nodeGroup_t *ng =
00786                 layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i];
00787 
00788 
00789 #ifdef UNUSED
00790             /* The following code corrects w by adding dummy node spacing. 
00791              * It's no longer used
00792              */
00793             int l;
00794             for (l = 0; l < ng->nNodes; l++) {
00795                 w += (ND_in(ng->nodes[l]).size - 1) * GD_nodesep(g);
00796             }
00797 #endif
00798 
00799             for (p = 0; p < fstNdGrp->nNodes; p++)
00800                 for (q = 0; q < ng->nNodes; q++) {
00801                     //printf("Trying to add virtual edge: %s -> %s\n",
00802                     //    agnameof(fstNdGrp->nodes[p]), agnameof(ng->nodes[q]));
00803 
00804                     /* The following code is for deletion of long virtual edges.
00805                      * It's no longer used.
00806                      */
00807 #ifdef UNUSED
00808                     for (s = ND_in(ng->nodes[q]).size - 1; s >= 0; s--) {
00809                         ev = ND_in(ng->nodes[q]).list[s];
00810 
00811                         edge_t *et;
00812                         int fail = 0;
00813                         cnt = 0;
00814 
00815                         for (et = agfstin(g, aghead(ev)); et;
00816                              et = agnxtin(g, et)) {
00817                             if (aghead(et) == aghead(ev)
00818                                 && agtail(et) == agtail(ev)) {
00819                                 fail = 1;
00820                                 break;
00821                             }
00822                         }
00823 
00824                         if (fail) {
00825                             //printf("FAIL DETECTED\n");
00826                             continue;
00827                         }
00828 
00829 
00830                         if (ED_edge_type(ev) == VIRTUAL
00831                             && ND_rank(aghead(ev)) > ND_rank(agtail(ev)) + 1) {
00832                             //printf("%d. inNode= %s.deleted: %s->%s\n",
00833                             //   test++, agnameof(ng->nodes[q]),
00834                             //   agnameof(agtail(ev)), agnameof(aghead(ev)));
00835 
00836                             delete_fast_edge(ev);
00837                             free(ev);
00838                         }
00839                     }
00840 #endif
00841 
00842                     /* add a new virtual edge */
00843                     edge_t *newVEdge =
00844                         virtual_edge(fstNdGrp->nodes[p], ng->nodes[q],
00845                                      NULL);
00846                     ED_edge_type(newVEdge) = VIRTUAL;
00847                     ndem++;     /* increase number of node demotions */
00848                 }
00849 
00850             /* the following code updates the layer width information. The 
00851              * update is not useful in the current version of the heuristic.
00852              */
00853             layerWidthInfo[maxLayerIndex].removed[i] = 1;
00854             rem2++;
00855             layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--;
00856             /* SHOULD BE INCREASED BY THE SUM OF INDEG OF ALL NODES IN GROUP */
00857             layerWidthInfo[maxLayerIndex].nDummyNodes++;
00858             layerWidthInfo[maxLayerIndex].width -=
00859                 (ng->width * DPI + GD_nodesep(g));
00860         }
00861     }
00862 }
00863 
00864 #ifdef UNUSED
00865 /* balanceLayers:
00866  * The following is the layer balancing heuristic.
00867  * Balance the widths of the layers as much as possible.
00868  * It's no longer used.
00869  */
00870 static void balanceLayers(graph_t * g)
00871 {
00872     int maxLayerIndex, nextLayerIndex, i;
00873     double maxWidth, w;
00874 
00875     //get the max width layer number
00876 
00877     for (i = 0; i < nLayers; i++) {
00878         if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1
00879             ||
00880             layerWidthInfo[sortedLayerIndex[i]].layerNumber + 1 == nLayers)
00881             continue;
00882         else {
00883             maxLayerIndex = sortedLayerIndex[i];
00884             maxWidth = layerWidthInfo[maxLayerIndex].width;
00885             printf("Balancing: maxLayerIndex = %d\n", maxLayerIndex);
00886             break;
00887         }
00888     }
00889 
00890     if (i == nLayers)
00891         return;                 //reduction of layerwidth is not possible.
00892 
00893     //balancing ~~ packing by node demotion
00894     nextLayerIndex = -1;
00895     for (i = 0; i < nLayers; i++) {
00896         if (layerWidthInfo[i].layerNumber ==
00897             layerWidthInfo[maxLayerIndex].layerNumber + 1) {
00898             nextLayerIndex = i;
00899         }
00900     }
00901 
00902     if (nextLayerIndex > -1) {
00903         //if (layerWidthInfo[nextLayerIndex].width <= 0.5*layerWidthInfo[maxLayerIndex].width)
00904         //{
00905         int changed = 0;
00906         w = 0;
00907 
00908         //demote nodes to the next layer
00909         for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer;
00910              i++) {
00911             if (layerWidthInfo[maxLayerIndex].removed[i])
00912                 continue;
00913 
00914             if (!checkHorizontalEdge
00915                 (g, layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i],
00916                  nextLayerIndex)
00917                 && layerWidthInfo[nextLayerIndex].width
00918                 /*+ (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width */
00919                 <= layerWidthInfo[maxLayerIndex].width
00920                 /*- (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width*/
00921                 ) {
00922                 w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->
00923                     width;
00924                 changed++;
00925 
00926                 int j;
00927                 nodeGroup_t *ng =
00928                     layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i];
00929 
00930                 layerWidthInfo[maxLayerIndex].removed[i] = 1;
00931                 layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--;
00932                 layerWidthInfo[maxLayerIndex].width -= (ng->width);
00933                 layerWidthInfo[maxLayerIndex].nDummyNodes++;
00934                 for (j = 0; j < ng->nNodes; j++)
00935                     ND_rank(ng->nodes[j])++;
00936 
00937 
00938                 layerWidthInfo[nextLayerIndex].
00939                     nodeGroupsInLayer[layerWidthInfo[nextLayerIndex].
00940                                       nNodeGroupsInLayer] = ng;
00941                 layerWidthInfo[nextLayerIndex].
00942                     removed[layerWidthInfo[nextLayerIndex].
00943                             nNodeGroupsInLayer] = 0;
00944                 layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer++;
00945                 layerWidthInfo[nextLayerIndex].width +=
00946                     (ng->width + GD_nodesep(g));
00947             }
00948 
00949         }
00950 
00951         if (changed) {
00952             //printf("Demoted %d nodes\n", changed);
00953             return;
00954         }
00955         //}
00956     }
00957 }
00958 
00959 /* applyPacking:
00960  * The following is the initial packing heuristic
00961  * It's no longer used.
00962  */
00963 static void applyPacking(graph_t * g, double targetAR)
00964 {
00965     int i;
00966 
00967     sortedLayerIndex = N_NEW(agnnodes(g), int);
00968 
00969     for (i = 0; i < agnnodes(g); i++) {
00970         sortedLayerIndex[i] = i;
00971     }
00972 
00973 
00974     node_t *v;
00975 
00976     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00977         //printf("%s, rank = %d, ranktype = %d\n", agnameof(v), ND_rank(v), ND_ranktype(v));
00978     }
00979 
00980     //GD_nodesep(g) = 0.25;
00981     //GD_ranksep(g) = 0.25;
00983     //printf("Nodesep = %d, Ranksep = %d\n",GD_nodesep(g), GD_ranksep(g));
00984 
00985 
00986     for (i = 0; i < 1; i++) {
00987         //printf("iteration = %d\n----------------------\n", i);
00988         for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00989             //printf("%s rank = %d\n", agnameof(v), ND_rank(v));
00990         }
00991 
00992         computeLayerWidths(g);
00993         sortLayers(g);
00994         reduceMaxWidth(g);
00995 
00996         //printf("====================\n");
00997     }
00998 
00999 
01000     int k;
01001 
01002     for (k = 0; k < nLayers - 1; k++) {
01003         int cnt = 0, tg;
01004         if (layerWidthInfo[k].nNodeGroupsInLayer > 7) {
01005 
01006             cnt = 0;
01007             tg = layerWidthInfo[k].nNodeGroupsInLayer - 7;
01008 
01009             for (i = layerWidthInfo[k].nNodeGroupsInLayer - 1; i >= 0; i--) {
01010 
01011                 if (layerWidthInfo[k].removed[i])
01012                     continue;
01013 
01014                 int j;
01015                 nodeGroup_t *ng = layerWidthInfo[k].nodeGroupsInLayer[i];
01016 
01017 
01018                 layerWidthInfo[k].removed[i] = 1;
01019                 layerWidthInfo[k].nNodeGroupsInLayer--;
01020                 layerWidthInfo[k].nDummyNodes++;
01021                 layerWidthInfo[k].width -=
01022                     (ng->width * DPI + GD_nodesep(g));
01023                 for (j = 0; j < ng->nNodes; j++)
01024                     ND_rank(ng->nodes[j])++;
01025 
01026                 //create new layer
01027                 layerWidthInfo[k +
01028                                1].nodeGroupsInLayer[layerWidthInfo[k +
01029                                                                    1].
01030                                                     nNodeGroupsInLayer] =
01031                     ng;
01032                 layerWidthInfo[k + 1].nNodeGroupsInLayer++;
01033                 //layerWidthInfo[k+1].layerNumber = ND_rank(ng->nodes[0]);
01034 
01035                 //layerWidthInfo[k+1].width += ( ng->width*DPI + (layerWidthInfo[nLayers].nNodeGroupsInLayer > 1) * GD_nodesep(g) ); // just add the node widths now. 
01036 
01037                 cnt++;
01038 
01039                 if (cnt == tg)
01040                     break;
01041 
01042             }
01043         }
01044     }
01045 
01046     //calcualte the max width
01047     int maxW = 0;
01048     int nNodeG = 0, l, nDummy = 0;
01049     int index;
01050 
01051     for (k = 0; k < nLayers; k++) {
01052         //printf("Layer#=%d, #dumNd=%d, width=%0.1lf, node=%s\n", layerWidthInfo[k].layerNumber, layerWidthInfo[k].nDummyNodes, layerWidthInfo[k].width,
01053         // agnameof(layerWidthInfo[k].nodeGroupsInLayer[0]->nodes[0]));
01054         if (layerWidthInfo[k].width > maxW)     // && layerWidthInfo[k].nNodeGroupsInLayer > 0)
01055         {
01056             maxW = layerWidthInfo[k].width;
01057             nNodeG = layerWidthInfo[k].nNodeGroupsInLayer;
01058             l = layerWidthInfo[k].layerNumber;
01059             nDummy = layerWidthInfo[k].nDummyNodes;
01060             index = k;
01061         }
01062     }
01063     //printf("Ht=%d, MxW=%d, #ndGr=%d, #dumNd=%d, lyr#=%d, 1stNd=%s\n", (nLayers-1)*DPI, maxW, nNodeG, nDummy, l, agnameof(layerWidthInfo[index].nodeGroupsInLayer[0]->nodes[0]));
01064 
01065     // printf("Finally...\n------------------\n");
01066     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01067         //printf("%s, rank = %d, ranktype = %d\n", agnameof(v, ND_rank(v), ND_ranktype(v));
01068     }
01069 
01070 }
01071 #endif
01072 
01073 /* applyPacking2:
01074  * The following is the packing heuristic for wide layout.
01075  */
01076 static void applyPacking2(graph_t * g)
01077 {
01078     int i;
01079 
01080     sortedLayerIndex = N_NEW(agnnodes(g), int);
01081 
01082     for (i = 0; i < agnnodes(g); i++) {
01083         sortedLayerIndex[i] = i;
01084     }
01085 
01086     computeLayerWidths(g);
01087     sortLayers(g);
01088     reduceMaxWidth2(g);
01089 
01090 }
01091 
01092 #ifdef UNUSED
01093 /* applyPacking4:
01094  * The following is the packing heuristic for wide layout.
01095  * It's used with Nikolov-Healy healy heuristic.
01096  */
01097 void applyPacking4(graph_t * g)
01098 {
01099     int i;
01100 
01101     sortedLayerIndex = N_NEW(agnnodes(g), int);
01102 
01103     for (i = 0; i < agnnodes(g); i++) {
01104         sortedLayerIndex[i] = i;
01105     }
01106 
01107 
01108     for (i = 0; i < 1; i++) {
01109         /*    printf("iteration = %d\n----------------------\n", i);
01110            for (v = agfstnode(g); v; v = agnxtnode(g,v))
01111            {
01112            printf("%s rank = %d\n", agnameof(v), ND_rank(v));
01113            }
01114          */
01115 
01116 
01117         computeLayerWidths(g);
01118         sortLayers(g);
01119         reduceMaxWidth2(g);
01120         //printf("====================\n");
01121     }
01122 }
01123 
01124 /*
01125  *       NOCOLOV & HEALY'S NODE PROMOTION HEURISTIC
01126  */
01127 
01128 /****************************************************************
01129  * This data structure is needed for backing up node information
01130  * during node promotion
01131  ****************************************************************/
01132 typedef struct myNodeInfo_t {
01133     int indegree;
01134     int outdegree;
01135     int rank;
01136     Agnode_t *node;
01137 } myNodeInfo_t;
01138 
01139 myNodeInfo_t *myNodeInfo;
01140 
01141 
01142 /* getMaxLevelNumber:
01143  * return the maximum level number assigned
01144  */
01145 int getMaxLevelNumber(graph_t * g)
01146 {
01147     int max;
01148     Agnode_t *n;
01149 
01150     max = ND_rank(agfstnode(g));
01151 
01152     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01153         if (ND_rank(n) > max)
01154             max = ND_rank(n);
01155     }
01156 
01157     return max;
01158 }
01159 
01160 /* countDummyDiff:
01161  * return the difference in the count of dummy nodes before 
01162  * and after promoting the node v
01163  */
01164 static int countDummyDiff(graph_t * g, Agnode_t * v, int max)
01165 {
01166     int dummydiff = 0;
01167     Agedge_t *e;
01168     Agnode_t *u;
01169     int maxR = 0;
01170     int j;
01171 
01172     for (j = 0; j < ND_in(v).size; j++) {
01173         e = ND_in(v).list[j];
01174         u = agtail(e);
01175 
01176         if (myNodeInfo[ND_id(u)].rank == myNodeInfo[ND_id(v)].rank + 1) {
01177             dummydiff += countDummyDiff(g, u, max);
01178         }
01179     }
01180 
01181     if (myNodeInfo[ND_id(v)].rank + 1 < max
01182         || (ND_in(v).size == 0 && myNodeInfo[ND_id(v)].rank + 1 <= max))
01183         myNodeInfo[ND_id(v)].rank += 1;
01184 
01185     dummydiff = dummydiff - ND_in(v).size + ND_out(v).size;
01186 
01187 
01188     return dummydiff;
01189 }
01190 
01191 /* applyPromotionHeuristic:
01192  * Node Promotion Heuristic
01193  * by Nikolov and Healy
01194  */
01195 static void applyPromotionHeuristic(graph_t * g)
01196 {
01197     graph_t graphBkup = *g;
01198     Agnode_t *v;
01199     int promotions;
01200 
01201     int max = getMaxLevelNumber(g);
01202     int count = 0;
01203     int nNodes = agnnodes(g);
01204     int i, j;
01205 
01206     myNodeInfo = N_NEW(nNodes, myNodeInfo_t);
01207     myNodeInfo_t *myNodeInfoBak = N_NEW(nNodes, myNodeInfo_t);
01208 
01209     for (v = agfstnode(g), i = 0; v; v = agnxtnode(g, v), i++) {
01210         myNodeInfo[i].indegree = ND_in(v).size;
01211         myNodeInfo[i].outdegree = ND_out(v).size;
01212         myNodeInfo[i].rank = ND_rank(v);
01213         myNodeInfo[i].node = v;
01214         ND_id(v) = i;
01215 
01216         myNodeInfoBak[i] = myNodeInfo[i];
01217     }
01218 
01219     do {
01220         promotions = 0;
01221 
01222         for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01223             if (ND_in(v).size > 0) {
01224                 if (countDummyDiff(g, v, max) <= 0) {
01225                     promotions++;
01226 
01227                     for (j = 0; j < nNodes; j++) {
01228                         myNodeInfoBak[j] = myNodeInfo[j];
01229                     }
01230 
01231                 } else {
01232                     for (j = 0; j < nNodes; j++) {
01233                         myNodeInfo[j] = myNodeInfoBak[j];
01234                     }
01235                 }
01236             }
01237         }
01238         count++;
01239     } while (count < max);
01240 
01241     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01242         ND_rank(v) = myNodeInfo[ND_id(v)].rank;
01243     }
01244 }
01245 
01246 /*
01247  *       LONGEST PATH ALGORITHM
01248  */
01249 
01250 /* allNeighborsAreBelow:
01251  * Return 1 if all the neighbors of n already ranked, else 0
01252  */
01253 static int allNeighborsAreBelow(Agnode_t * n)
01254 {
01255     Agedge_t *e;
01256     graph_t *g = agraphof(n);
01257     int i;
01258 
01259     //for (e = agfstout(g,n); e; e = agnxtout(g,e))
01260     for (i = 0; i < ND_out(n).size; i++) {
01261         e = ND_out(n).list[i];
01262         if (ED_edge_type(e) == VIRTUAL) {
01263             if (ED_to_orig(e) != NULL)
01264                 e = ED_to_orig(e);
01265             else if (ND_node_type(aghead(e)) == VIRTUAL)
01266                 continue;
01267         }
01268 
01269         if (ND_pinned(aghead(e)) != 2)  //neighbor of n is not below
01270         {
01271             return 0;
01272         }
01273     }
01274 
01275     return 1;
01276 }
01277 
01278 /* reverseLevelNumbers:
01279  * In Nikolov and Healy ranking, bottom layer ranking is  0 and
01280  * top layer ranking is the maximum. 
01281  * Graphviz does the opposite.
01282  * This function does the reversing from Nikolov to Graphviz.
01283  */
01284 static void reverseLevelNumbers(graph_t * g)
01285 {
01286     Agnode_t *n;
01287     int max;
01288 
01289     max = getMaxLevelNumber(g);
01290 
01291     //printf("max = %d\n", max);
01292 
01293     //return;
01294     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01295         ND_rank(n) = max - ND_rank(n);
01296     }
01297 }
01298 
01299 /* doSameRank:
01300  * Maintain the same ranking constraint.
01301  * Can only be used with the Nikolov and Healy algorithm
01302  */
01303 static void doSameRank(graph_t * g)
01304 {
01305     int i;
01306     for (i = 0; i < nNodeGroups; i++) {
01307         int j;
01308 
01309         for (j = 0; j < nodeGroups[i].nNodes; j++) {
01310             if (ND_ranktype(nodeGroups[i].nodes[j]) == SAMERANK)        //once we find a SAMERANK node in a group- make all the members of the group SAMERANK
01311             {
01312                 int k;
01313                 int r = ND_rank(UF_find(nodeGroups[i].nodes[j]));
01314                 for (k = 0; k < nodeGroups[i].nNodes; k++) {
01315                     ND_rank(nodeGroups[i].
01316                             nodes[(j + k) % nodeGroups[i].nNodes]) = r;
01317                 }
01318 
01319                 break;
01320             }
01321         }
01322     }
01323 }
01324 
01325 /* doMinRank:
01326  * Maintain the MIN ranking constraint.
01327  * Can only be used with the Nikolov and Healy algorithm
01328  */
01329 void doMinRank(graph_t * g)
01330 {
01331     int i;
01332     for (i = 0; i < nNodeGroups; i++) {
01333         int j;
01334 
01335         for (j = 0; j < nodeGroups[i].nNodes; j++) {
01336             if (ND_ranktype(nodeGroups[i].nodes[j]) == MINRANK) //once we find a MINRANK node in a group- make the rank of all the members of the group 0
01337             {
01338                 int k;
01339                 for (k = 0; k < nodeGroups[i].nNodes; k++) {
01340                     ND_rank(nodeGroups[i].
01341                             nodes[(j + k) % nodeGroups[i].nNodes]) = 0;
01342                     if (ND_ranktype
01343                         (nodeGroups[i].
01344                          nodes[(j + k) % nodeGroups[i].nNodes]) !=
01345                         SOURCERANK)
01346                         ND_ranktype(nodeGroups[i].
01347                                     nodes[(j +
01348                                            k) % nodeGroups[i].nNodes]) =
01349                             MINRANK;
01350                 }
01351 
01352                 break;
01353             }
01354         }
01355     }
01356 }
01357 
01358 /* getMaxRank:
01359  * Return the maximum rank among all nodes.
01360  */
01361 static int getMaxRank(graph_t * g)
01362 {
01363     int i;
01364     node_t *v;
01365     int maxR = ND_rank(agfstnode(g));
01366     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01367         if (ND_rank(v) > maxR)
01368             maxR = ND_rank(v);
01369     }
01370 
01371     return maxR;
01372 }
01373 
01374 /* doMaxRank:
01375  * Maintain the MAX ranking constraint.
01376  * Can only be used with the Nikolov and Healy algorithm
01377  */
01378 static void doMaxRank(graph_t * g)
01379 {
01380     int i;
01381     for (i = 0; i < nNodeGroups; i++) {
01382         int j;
01383         int maxR = getMaxRank(g);
01384 
01385         for (j = 0; j < nodeGroups[i].nNodes; j++) {
01386             if (ND_ranktype(nodeGroups[i].nodes[j]) == MAXRANK) //once we find a MAXRANK node in a group- make the rank of all the members of the group MAX
01387             {
01388                 int k;
01389                 for (k = 0; k < nodeGroups[i].nNodes; k++) {
01390                     ND_rank(nodeGroups[i].
01391                             nodes[(j + k) % nodeGroups[i].nNodes]) = maxR;
01392                     if (ND_ranktype
01393                         (nodeGroups[i].
01394                          nodes[(j + k) % nodeGroups[i].nNodes]) !=
01395                         SINKRANK)
01396                         ND_ranktype(nodeGroups[i].
01397                                     nodes[(j +
01398                                            k) % nodeGroups[i].nNodes]) =
01399                             MAXRANK;
01400                 }
01401 
01402                 break;
01403             }
01404         }
01405     }
01406 }
01407 
01408 /* doSourceRank:
01409  * Maintain the SOURCE ranking constraint.
01410  * Can only be used with the Nikolov and Healy algorithm
01411  */
01412 static void doSourceRank(graph_t * g)
01413 {
01414     int i;
01415     int flag = 0;
01416 
01417     for (i = 0; i < nNodeGroups; i++) {
01418         int j;
01419 
01420         for (j = 0; j < nodeGroups[i].nNodes; j++) {
01421             //once we find a SOURCERANK node in a group- make the rank of all the members of the group 0
01422             if (ND_ranktype(nodeGroups[i].nodes[j]) == SOURCERANK) {
01423                 int k;
01424                 for (k = 0; k < nodeGroups[i].nNodes; k++) {
01425                     ND_rank(nodeGroups[i].
01426                             nodes[(j + k) % nodeGroups[i].nNodes]) = 0;
01427                     ND_ranktype(nodeGroups[i].
01428                                 nodes[(j + k) % nodeGroups[i].nNodes]) =
01429                         SOURCERANK;
01430                 }
01431 
01432                 flag = 1;
01433                 break;
01434             }
01435         }
01436     }
01437 
01438     if (!flag)
01439         return;
01440 
01441     flag = 0;
01442 
01443     //The SourceRank group might be the only group having rank 0. Check if increment of ranking of other nodes is necessary at all.
01444     for (i = 0; i < nNodeGroups; i++) {
01445         if (nodeGroups[i].nNodes > 0
01446             && ND_ranktype(nodeGroups[i].nodes[0]) != SOURCERANK
01447             && ND_rank(nodeGroups[i].nodes[0]) == 0) {
01448             flag = 1;
01449             break;
01450         }
01451     }
01452 
01453 
01454     if (!flag)
01455         return;
01456 
01457     //Now make all NON-SourceRank nodes' ranking nonzero (increment)
01458     for (i = 0; i < nNodeGroups; i++) {
01459         if (nodeGroups[i].nNodes > 0
01460             && ND_ranktype(nodeGroups[i].nodes[0]) != SOURCERANK) {
01461             int j;
01462 
01463             for (j = 0; j < nodeGroups[i].nNodes; j++) {
01464                 ND_rank(nodeGroups[i].nodes[j])++;
01465             }
01466         }
01467     }
01468 }
01469 
01470 /* doSinkRank:
01471  * Maintain the SINK ranking constraint.
01472  * Can only be used with the Nikolov and Healy algorithm
01473  */
01474 static void doSinkRank(graph_t * g)
01475 {
01476     int i, max;
01477     int flag = 0;
01478 
01479     max = getMaxRank(g);
01480 
01481 
01482     //Check if any non-sink node has rank = max
01483     for (i = 0; i < nNodeGroups; i++) {
01484         if (nodeGroups[i].nNodes > 0
01485             && ND_ranktype(nodeGroups[i].nodes[0]) != SINKRANK
01486             && ND_rank(nodeGroups[i].nodes[0]) == max) {
01487             flag = 1;
01488             break;
01489         }
01490     }
01491 
01492     if (!flag)
01493         return;
01494 
01495     for (i = 0; i < nNodeGroups; i++) {
01496         int j;
01497 
01498         for (j = 0; j < nodeGroups[i].nNodes; j++) {
01499             if (ND_ranktype(nodeGroups[i].nodes[j]) == SINKRANK)        //once we find a SINKRANK node in a group- make the rank of all the members of the group: max+1
01500             {
01501                 int k;
01502                 for (k = 0; k < nodeGroups[i].nNodes; k++) {
01503                     ND_rank(nodeGroups[i].
01504                             nodes[(j + k) % nodeGroups[i].nNodes]) =
01505                         max + 1;
01506                     ND_ranktype(nodeGroups[i].
01507                                 nodes[(j + k) % nodeGroups[i].nNodes]) =
01508                         SINKRANK;
01509                 }
01510 
01511                 break;
01512             }
01513         }
01514     }
01515 }
01516 
01517 /* rank2: 
01518  * Initial codes for ranking (Nikolov-Healy).
01519  * It's no longer used.
01520  */
01521 void rank2(graph_t * g)
01522 {
01523     int currentLayer = 1;
01524     int nNodes = agnnodes(g);
01525     int nEdges = agnedges(g);
01526     int nPinnedNodes = 0, nSelected = 0;
01527     Agnode_t *n, **UArray;
01528     int USize = 0;
01529     int i, prevSize = 0;
01530 
01531     UArray = N_NEW(nEdges * 2, Agnode_t *);
01532 
01533     /* make all pinning values 0 */
01534     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01535         ND_pinned(n) = 0;
01536     }
01537 
01538     while (nPinnedNodes != nNodes) {
01539         for (nSelected = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) {
01540             if (ND_pinned(n) == 0) {
01541                 if (allNeighborsAreBelow(n)) {
01542                     ND_pinned(n) = 1;
01543 
01544                     UArray[USize] = n;
01545                     USize++;
01546 
01547                     ND_rank(n) = currentLayer;
01548                     nPinnedNodes++;
01549                     nSelected++;
01550                 }
01551             }
01552         }
01553 
01554         if (nSelected == 0)     //no node has been selected
01555         {
01556             currentLayer++;
01557             for (i = prevSize; i < USize; i++) {
01558                 ND_pinned(UArray[i]) = 2;       //pinning value of 2 indicates this node is below the current node under consideration
01559             }
01560 
01561             prevSize = USize;
01562         }
01563     }
01564 
01565     //Apply Nikolov's node promotion heuristic
01566     applyPromotionHeuristic(g);
01567 
01568     //this is for the sake of graphViz layer numbering scheme
01569     reverseLevelNumbers(g);
01570 
01571     computeNodeGroups(g);       //groups of UF DS nodes
01572 
01573     //modify the ranking to respect the same ranking constraint
01574     doSameRank(g);
01575 
01576     //satisfy min ranking constraints
01577     doMinRank(g);
01578     doMaxRank(g);
01579 
01580     //satisfy source ranking constraints
01581     doSourceRank(g);
01582     doSinkRank(g);
01583 
01584     //Apply the FFDH algorithm to achieve better aspect ratio;
01585     applyPacking(g, 1);         //achieve an aspect ratio of 1
01586 }
01587 #endif
01588 
01589 /****************************************************************
01590  * Initialize all the edge types to NORMAL 
01591  ****************************************************************/
01592 void initEdgeTypes(graph_t * g)
01593 {
01594     edge_t *e;
01595     node_t *n;
01596     int lc;
01597 
01598     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01599         for (lc = 0; lc < ND_in(n).size; lc++) {
01600             e = ND_in(n).list[lc];
01601             ED_edge_type(e) = NORMAL;
01602         }
01603     }
01604 }
01605 
01606 /* computeCombiAR:
01607  * Compute and return combinatorial aspect ratio 
01608  * =
01609  * Width of the widest layer / Height 
01610  * (in ranking phase)
01611  */
01612 static double computeCombiAR(graph_t * g)
01613 {
01614     int i, maxLayerIndex;
01615     double maxW = 0;
01616     double maxH;
01617     double ratio;
01618 
01619     computeLayerWidths(g);
01620     maxH = (nLayers - 1) * GD_ranksep(g);
01621 
01622     for (i = 0; i < nLayers; i++) {
01623         if (maxW <
01624             layerWidthInfo[i].width +
01625             layerWidthInfo[i].nDummyNodes * GD_nodesep(g)) {
01626             maxW =
01627                 layerWidthInfo[i].width +
01628                 layerWidthInfo[i].nDummyNodes * GD_nodesep(g);
01629             maxLayerIndex = i;
01630         }
01631         maxH += layerWidthInfo[i].height;
01632     }
01633 
01634     ratio = maxW / maxH;
01635 
01636     return ratio;
01637 }
01638 
01639 #ifdef UNUSED
01640 /* applyExpansion:
01641  * Heuristic for expanding very narrow graphs by edge reversal.
01642  * Needs improvement.
01643  */
01644 void applyExpansion(graph_t * g)
01645 {
01646     node_t *sink = NULL;
01647     int i, k;
01648     edge_t *e;
01649 
01650     computeLayerWidths(g);
01651 
01652     for (i = 0; i < nLayers; i++) {
01653         if (layerWidthInfo[i].layerNumber == nLayers / 2) {
01654             k = i;
01655             break;
01656         }
01657     }
01658 
01659     //now reverse the edges, from the k-th layer nodes to their parents
01660     for (i = 0; i < layerWidthInfo[k].nNodeGroupsInLayer; i++) {
01661         int p;
01662         nodeGroup_t *ng = layerWidthInfo[k].nodeGroupsInLayer[i];
01663         for (p = 0; p < ng->nNodes; p++) {
01664             node_t *nd = ng->nodes[p];
01665 
01666             while (e = ND_in(nd).list[0]) {
01667                 printf("Reversing edge: %s->%s\n", agnemeof(agtail(e)),
01668                        agnameof(aghead(e)));
01669                 reverse_edge(e);
01670             }
01671 
01672             int j, l;
01673             node_t *v3;
01674             edge_t *e3;
01675             for (v3 = agfstnode(g); v3; v3 = agnxtnode(g, v3)) {
01676                 for (e3 = agfstout(g, v3); e3; e3 = agnxtout(g, e3)) {
01677                     if (ND_rank(aghead(e3)) > k && ND_rank(agtail(e3)) < k) {
01678                         printf("Reversing long edge: %s->%s\n",
01679                                agnameof(agtail(e3)), agnameof(aghead(e3)));
01680                         reverse_edge(e3);
01681                     }
01682 
01683                 }
01684             }
01685 
01686             /*for (l = 0; l < nLayers; l++) {
01687                 if (layerWidthInfo[l].layerNumber <= k)
01688                     continue;
01689 
01690                 for (j = 0; j < layerWidthInfo[l].nNodeGroupsInLayer; j++) {
01691                     int q;
01692                     nodeGroup_t *ng2 = layerWidthInfo[l].nodeGroupsInLayer[j];
01693                     for (q = 0; q < ng2->nNodes; q++) {
01694                         node_t *nd2 = ng2->nodes[q];
01695                         edge_t *e2;
01696                         int s = 0;
01697                         while (e2 = ND_in(nd2).list[s]) {
01698                             if (ND_rank(agtail(e2)) < k) {
01699                                 printf("Reversing edge: %s->%s\n",
01700                                     agnameof(agtail(e2)), agnameof(aghead(e2)));
01701                                 getchar();
01702                                 //reverse_edge(e2);
01703                             }
01704                             else s++;
01705                         }
01706                     }
01707                 }
01708             } */
01709 
01710             if (sink == NULL) {
01711                 int brFlag = 1;
01712                 for (l = 0; l < nLayers && brFlag; l++) {
01713                     for (j = 0;
01714                          j < layerWidthInfo[l].nNodeGroupsInLayer
01715                          && brFlag; j++) {
01716                         int q;
01717                         nodeGroup_t *ng2 =
01718                             layerWidthInfo[l].nodeGroupsInLayer[j];
01719                         for (q = 0; q < ng2->nNodes && brFlag; q++) {
01720                             node_t *nd2 = ng2->nodes[q];
01721                             if (ND_in(nd2).size == 0) {
01722                                 sink = nd2;
01723                                 brFlag = 0;
01724                             }
01725                         }
01726                     }
01727                 }
01728 
01729             }
01730 
01731             virtual_edge(nd,    /*sink */
01732                          layerWidthInfo[0].nodeGroupsInLayer[0]->nodes[0],
01733                          NULL);
01734         }
01735     }
01736 
01737     //collapse_sets(g);
01738 }
01739 #endif
01740 
01741 /* zapLayers:
01742  * After applying the expansion heuristic, some layers are
01743  * found to be empty.
01744  * This function removes the empty layers.
01745  */
01746 static void zapLayers(graph_t * g)
01747 {
01748     int i, j;
01749     int start = 0;
01750     int count = 0;
01751 
01752     /* the layers are sorted by the layer number.  now zap the empty layers */
01753 
01754     for (i = 0; i < nLayers; i++) {
01755         if (layerWidthInfo[i].nNodeGroupsInLayer == 0) {
01756             if (count == 0)
01757                 start = layerWidthInfo[i].layerNumber;
01758             count++;
01759         } else if (count && layerWidthInfo[i].layerNumber > start) {
01760             for (j = 0; j < layerWidthInfo[i].nNodeGroupsInLayer; j++) {
01761                 int q;
01762                 nodeGroup_t *ng = layerWidthInfo[i].nodeGroupsInLayer[j];
01763                 for (q = 0; q < ng->nNodes; q++) {
01764                     node_t *nd = ng->nodes[q];
01765                     ND_rank(nd) -= count;
01766                 }
01767             }
01768         }
01769     }
01770 }
01771 
01772 /* rank3: 
01773  * ranking function for dealing with wide/narrow graphs,
01774  * or graphs with varying node widths and heights.
01775  * This function iteratively calls dot's rank1() function and 
01776  * applies packing (by calling the applyPacking2 function. 
01777  * applyPacking2 function calls the reduceMaxWidth2 function
01778  * for partitioning the widest layer).
01779  * Initially the iterations argument is -1, for which rank3
01780  * callse applyPacking2 function until the combinatorial aspect
01781  * ratio is <= the desired aspect ratio.
01782  */
01783 void rank3(graph_t * g, aspect_t * asp)
01784 {
01785     Agnode_t *n;
01786     int i;
01787     int iterations = asp->nextIter;
01788 
01789     computeNodeGroups(g);       /* groups of UF DS nodes */
01790 
01791     for (i = 0; i < iterations || iterations == -1; i++) {
01792         /* initialize all ranks to be 0 */
01793         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01794             ND_rank(n) = 0;
01795         }
01796 
01797         /* need to compute ranking first--- by Network flow */
01798 
01799         rank1(g);
01800 
01801         asp->combiAR = computeCombiAR(g);
01802         if (Verbose)
01803             fprintf(stderr, "combiAR = %lf\n", asp->combiAR);
01804 
01805 
01806         /* Uncomment the following codes, for working with narrow graphs */
01807 #ifdef UNUSED
01808         if (combiAR < 0.8 * targetAR) {
01809             char str[20];
01810             printf("Apply expansion? (y/n):");
01811             scanf("%s", str);
01812             if (strcmp(str, "y") == 0)
01813                 applyExpansion(g);
01814             break;
01815         } else
01816 #endif
01817         if (iterations == -1 && asp->combiAR <= asp->targetAR) {
01818             asp->prevIterations = asp->curIterations;
01819             asp->curIterations = i;
01820 
01821             break;
01822         }
01823         /* Apply the FFDH algorithm to reduce the aspect ratio; */
01824         applyPacking2(g);
01825     }
01826 
01827     /* do network flow once again... incorporating the added edges */
01828     rank1(g);
01829 
01830     computeLayerWidths(g);
01831     zapLayers(g);
01832     asp->combiAR = computeCombiAR(g);
01833 }
01834 
01835 #ifdef UNUSED
01836 /* NikolovHealy:
01837  * Nikolov-Healy approach to ranking.
01838  * First, use longest path algorithm.
01839  * Then use node promotion heuristic.
01840  * This function is called by rank4 function.
01841  */
01842 static void NikolovHealy(graph_t * g)
01843 {
01844     int currentLayer = 1;
01845     int nNodes = agnnodes(g);
01846     int nEdges = agnedges(g);
01847     int nPinnedNodes = 0, nSelected = 0;
01848     Agnode_t *n, **UArray;
01849     int USize = 0;
01850     int i, prevSize = 0;
01851 
01852     /************************************************************************
01853      * longest path algorithm
01854      ************************************************************************/
01855     UArray = N_NEW(nEdges * 2, Agnode_t *);
01856 
01857     /* make all pinning values 0 */
01858     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01859         ND_pinned(n) = 0;
01860     }
01861 
01862     while (nPinnedNodes != nNodes) {
01863         for (nSelected = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) {
01864             if (ND_pinned(n) == 0) {
01865                 if (allNeighborsAreBelow(n)) {
01866                     ND_pinned(n) = 1;
01867 
01868                     UArray[USize] = n;
01869                     USize++;
01870 
01871                     ND_rank(n) = currentLayer;
01872                     nPinnedNodes++;
01873                     nSelected++;
01874                 }
01875             }
01876         }
01877 
01878         if (nSelected == 0)     //no node has been selected
01879         {
01880             currentLayer++;
01881             for (i = prevSize; i < USize; i++) {
01882                 ND_pinned(UArray[i]) = 2;       //pinning value of 2 indicates this node is below the current node under consideration
01883             }
01884 
01885             prevSize = USize;
01886         }
01887 
01888     }
01889 
01890     /************************************************************************
01891      * end of longest path algorithm
01892      ************************************************************************/
01893 
01894     //Apply node promotion heuristic
01895     applyPromotionHeuristic(g);
01896 
01897     //this is for the sake of graphViz layer numbering scheme
01898     reverseLevelNumbers(g);
01899 
01900 }
01901 
01902 
01903 /* rank4:
01904  * This function is calls the NikolovHealy function
01905  * for ranking in the Nikolov-Healy approach.
01906  */
01907 void rank4(graph_t * g, int iterations)
01908 {
01909     int currentLayer = 1;
01910     int nNodes = agnnodes(g);
01911     int nEdges = agnedges(g);
01912     int nPinnedNodes = 0, nSelected = 0;
01913     Agnode_t *n, **UArray;
01914     int USize = 0;
01915     int i, prevSize = 0;
01916 
01917     int it;
01918     printf("# of interations of packing: ");
01919     scanf("%d", &it);
01920     printf("it=%d\n", it);
01921 
01922     computeNodeGroups(g);       //groups of UF DS nodes
01923 
01924     for (i = 0; i < it; i++) {
01925         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01926             ND_rank(n) = 0;
01927         }
01928 
01929         NikolovHealy(g);
01930 
01931         edge_t *e;
01932         int cnt = 0;
01933         int lc;
01934 
01935 
01936         combiAR = computeCombiAR(g);
01937         printf("%d. combiAR = %lf\n", i, combiAR);
01938 
01939         /*
01940            //modify the ranking to respect the same ranking constraint
01941            doSameRank(g);
01942 
01943            //satisfy min ranking constraints
01944            doMinRank(g);
01945            doMaxRank(g);
01946 
01947            //satisfy source ranking constraints
01948            doSourceRank(g);
01949            doSinkRank(g);
01950          */
01951 
01952         //Apply the FFDH algorithm to achieve better aspect ratio;
01953         applyPacking4(g);
01954 
01955     }
01956 
01957 }
01958 #endif
01959 
01960 /* init_UF_size:
01961  * Initialize the Union Find data structure
01962  */
01963 void init_UF_size(graph_t * g)
01964 {
01965     node_t *n;
01966 
01967     for (n = agfstnode(g); n; n = agnxtnode(g, n))
01968         ND_UF_size(n) = 0;
01969 }