From: erg Date: Fri, 17 Oct 2008 20:31:01 +0000 (+0000) Subject: Really integrate and turn on aspect ratio code in dot. X-Git-Tag: LAST_LIBGRAPH~32^2~3084 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b37176fbc5859daf68dacc4fd1706e273c665e68;p=graphviz Really integrate and turn on aspect ratio code in dot. --- diff --git a/lib/dotgen/Makefile.am b/lib/dotgen/Makefile.am index 3c9c2df1d..20971a9d1 100644 --- a/lib/dotgen/Makefile.am +++ b/lib/dotgen/Makefile.am @@ -5,10 +5,13 @@ AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_srcdir)/lib/common \ -I$(top_srcdir)/lib/gvc \ + -I$(top_srcdir)/lib/ortho \ -I$(top_srcdir)/lib/graph \ -I$(top_srcdir)/lib/cdt \ -I$(top_srcdir)/lib/pathplan +AM_CFLAGS = -DORTHO + if WITH_CGRAPH else noinst_HEADERS = dot.h dotprocs.h diff --git a/lib/dotgen/aspect.c b/lib/dotgen/aspect.c index f80526657..ed3e2a3ac 100644 --- a/lib/dotgen/aspect.c +++ b/lib/dotgen/aspect.c @@ -16,1646 +16,1554 @@ #include "dot.h" -/******************************************************************************************** -* CODES BY MOHAMMAD T. IRFAN -*********************************************************************************************/ - -#define DPI 72 - -/**************************** GLOBAL VARIABLES ***********************/ -double targetAR = 0; -double currentAR = 0; -double combiAR = 0; -int prevIterations = 0; -int curIterations = 0; -/**************************** END OF GLOBAL VARIABLES ****************/ +/* + * Author: Mohammad T. Irfan + * Summer, 2008 + */ +/* TODO: + * - Support clusters + * - Support disconnected graphs + * - Provide algorithms for aspect rations < 1 + */ +#define DPI 72 -/******************************************************************************************** +/* * NODE GROUPS FOR SAME RANKING * Node group data structure groups nodes together for * MIN, MAX, SOURCE, SINK constraints. * The grouping is based on the union-find data structure and * provides sequential access to the nodes in the same group. - *********************************************************************************************/ + */ -//data structure for node groups -typedef struct nodeGroup_t -{ - node_t **nodes; - int nNodes; - double width, height; +/* data structure for node groups */ +typedef struct nodeGroup_t { + node_t **nodes; + int nNodes; + double width, height; } nodeGroup_t; -nodeGroup_t *nodeGroups; -int nNodeGroups = 0; +static nodeGroup_t *nodeGroups; +static int nNodeGroups = 0; -/*************************************************************************** +/* computeNodeGroups: * computeNodeGroups function does the groupings of nodes. * The grouping is based on the union-find data structure. - ***************************************************************************/ -static void -computeNodeGroups(graph_t *g) + */ +static void computeNodeGroups(graph_t * g) { - int i; - node_t *n; - - nodeGroups = (nodeGroup_t *) malloc(sizeof(nodeGroup_t)*agnnodes(g)); - - if (nodeGroups == NULL) - { - agerr(AGERR, "Memory allocation error in computeNodeGroups function.\n"); - printf("Memory allocation error for nodeGroups\n"); - } - - nNodeGroups = 0; - - //initialize node ids. Id of a node is used as an index to the group. - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - { - ND_id(n) = -1; - } - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - { - if (ND_UF_size(n) == 0) //no same ranking constraint - { - nodeGroups[nNodeGroups].nodes = (node_t **) malloc(sizeof(node_t *) * 1); - if (nodeGroups[nNodeGroups].nodes == NULL) - { - agerr(AGERR, "Memory allocation error in computeNodeGroups function.\n"); - printf("Memory allocation error for nodeGroups[nNodeGroups].nodes\n"); - } - nodeGroups[nNodeGroups].nodes[0] = n; - nodeGroups[nNodeGroups].nNodes = 1; - nodeGroups[nNodeGroups].width = ND_width(n); - nodeGroups[nNodeGroups].height = ND_height(n); - - ND_id(n) = nNodeGroups; - nNodeGroups++; + node_t *n; + + nodeGroups = N_GNEW(agnnodes(g), nodeGroup_t); + + nNodeGroups = 0; + + /* initialize node ids. Id of a node is used as an index to the group. */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + ND_id(n) = -1; } - else //group same ranked nodes - { - node_t *l = UF_find(n); - if (ND_id(l) > -1) //leader is already grouped - { - int index = ND_id(l); - nodeGroups[index].nodes[nodeGroups[index].nNodes++] = n; - nodeGroups[index].width += ND_width(n); - nodeGroups[index].height = (nodeGroups[index].height < ND_height(n)) ? ND_height(n) : nodeGroups[index].height; - - ND_id(n) = index; - } - else //create a new group - { - nodeGroups[nNodeGroups].nodes = (node_t **) malloc(sizeof(node_t *) * ND_UF_size(l)); - if (nodeGroups[nNodeGroups].nodes == NULL) - { - agerr(AGERR, "Memory allocation error in computeNodeGroups function.\n"); - printf("Memory allocation error for nodeGroups[nNodeGroups].nodes\n"); - } - - if (l == n) //node n is the leader - { - nodeGroups[nNodeGroups].nodes[0] = l; - nodeGroups[nNodeGroups].nNodes = 1; - nodeGroups[nNodeGroups].width = ND_width(l); - nodeGroups[nNodeGroups].height = ND_height(l); - } - else + + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + if (ND_UF_size(n) == 0) { /* no same ranking constraint */ + nodeGroups[nNodeGroups].nodes = NEW(node_t *); + nodeGroups[nNodeGroups].nodes[0] = n; + nodeGroups[nNodeGroups].nNodes = 1; + nodeGroups[nNodeGroups].width = ND_width(n); + nodeGroups[nNodeGroups].height = ND_height(n); + + ND_id(n) = nNodeGroups; + nNodeGroups++; + } else /* group same ranked nodes */ { - nodeGroups[nNodeGroups].nodes[0] = l; - nodeGroups[nNodeGroups].nodes[1] = n; - nodeGroups[nNodeGroups].nNodes = 2; - nodeGroups[nNodeGroups].width = ND_width(l) + ND_width(n); - nodeGroups[nNodeGroups].height = (ND_height(l) < ND_height(n)) ? ND_height(n) : ND_height(l); - } + node_t *l = UF_find(n); + if (ND_id(l) > -1) /* leader is already grouped */ + { + int index = ND_id(l); + nodeGroups[index].nodes[nodeGroups[index].nNodes++] = n; + nodeGroups[index].width += ND_width(n); + nodeGroups[index].height = + (nodeGroups[index].height < + ND_height(n)) ? ND_height(n) : nodeGroups[index]. + height; + + ND_id(n) = index; + } else /* create a new group */ + { + nodeGroups[nNodeGroups].nodes = + N_NEW(ND_UF_size(l), node_t *); + + if (l == n) /* node n is the leader */ + { + nodeGroups[nNodeGroups].nodes[0] = l; + nodeGroups[nNodeGroups].nNodes = 1; + nodeGroups[nNodeGroups].width = ND_width(l); + nodeGroups[nNodeGroups].height = ND_height(l); + } else { + nodeGroups[nNodeGroups].nodes[0] = l; + nodeGroups[nNodeGroups].nodes[1] = n; + nodeGroups[nNodeGroups].nNodes = 2; + nodeGroups[nNodeGroups].width = + ND_width(l) + ND_width(n); + nodeGroups[nNodeGroups].height = + (ND_height(l) < + ND_height(n)) ? ND_height(n) : ND_height(l); + } - ND_id(l) = nNodeGroups; - ND_id(n) = nNodeGroups; - nNodeGroups++; - } + ND_id(l) = nNodeGroups; + ND_id(n) = nNodeGroups; + nNodeGroups++; + } + } } - } } -/******************************************************************************************** -* END OF CODES FOR NODE GROUPS -*********************************************************************************************/ - - -/******************************************************************************************** -* Count the number of dummy nodes -*********************************************************************************************/ +/* + * END OF CODES FOR NODE GROUPS + */ -int -countDummyNodes(graph_t *g) +/* countDummyNodes: + * Count the number of dummy nodes + */ +int countDummyNodes(graph_t * g) { - int count = 0; - node_t *n; - edge_t *e; - - //Count dummy nodes - for (n = agfstnode(g); n; n = agnxtnode(g, n)) - for (e = agfstout(g, n); e; e = agnxtout(g, e)) - { - int k; - //this loop can be avoided - /*for (k = ND_rank(e->tail)+1; k < ND_rank(e->head); k++) - { - count++; - }*/ + int count = 0; + node_t *n; + edge_t *e; - if (ND_rank(e->head) != ND_rank(e->tail)) //flat edges do not have dummy nodes - count += abs(ND_rank(e->head) - ND_rank(e->tail)) - 1; + /* Count dummy nodes */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + for (e = agfstout(g, n); e; e = agnxtout(g, e)) { +#ifdef UNUSED + /* this loop can be avoided */ + for (k = ND_rank(e->tail)+1; k < ND_rank(e->head); k++) { + count++; + } +#endif + /* flat edges do not have dummy nodes */ + if (ND_rank(e->head) != ND_rank(e->tail)) + count += abs(ND_rank(e->head) - ND_rank(e->tail)) - 1; + } } - - return count; + return count; } -/******************************************************************************************** -* FFDH PACKING ALGORITHM TO ACHIEVE TARGET ASPECT RATIO -*********************************************************************************************/ - - -/******************************************************************************************** -* layerWidthInfo_t: data structure for keeping layer width information -* Each layer consists of a number of node groups. -*********************************************************************************************/ +/* + * FFDH PACKING ALGORITHM TO ACHIEVE TARGET ASPECT RATIO + */ -typedef struct layerWidthInfo_t -{ - int layerNumber; - nodeGroup_t **nodeGroupsInLayer; - int *removed; // is the node group removed? - int nNodeGroupsInLayer; - int nDummyNodes; - double width; - double height; +/* + * layerWidthInfo_t: data structure for keeping layer width information + * Each layer consists of a number of node groups. + */ +typedef struct layerWidthInfo_t { + int layerNumber; + nodeGroup_t **nodeGroupsInLayer; + int *removed; /* is the node group removed? */ + int nNodeGroupsInLayer; + int nDummyNodes; + double width; + double height; } layerWidthInfo_t; -layerWidthInfo_t *layerWidthInfo = NULL; -int *sortedLayerIndex; -int nLayers = 0; +static layerWidthInfo_t *layerWidthInfo = NULL; +static int *sortedLayerIndex; +static int nLayers = 0; -void computeLayerWidths(graph_t *g) +/* computeLayerWidths: + */ +static void computeLayerWidths(graph_t * g) { - int i; - node_t *v; - - nLayers = 0; - - - //free previously allocated memory - - if (layerWidthInfo) - { - for (i=0; itail)+1; k < ND_rank(e->head); k++) - { - layerWidthInfo[k].nDummyNodes++; - } - - /*if (ND_rank(e->head) != ND_rank(e->tail)) //flat edges do not have dummy nodes - layerWidthInfo[k].nDummyNodes = abs(ND_rank(e->head) - ND_rank(e->tail)) - 1;*/ - } + node_t *n; + edge_t *e; + + /* Count dummy nodes in the layer */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) + for (e = agfstout(g, n); e; e = agnxtout(g, e)) { + int k; + + /* FIX: This loop maybe unnecessary, but removing it and using + * the commented codes next, gives a segmentation fault. I + * forgot the reason why. + */ + for (k = ND_rank(e->tail) + 1; k < ND_rank(e->head); k++) { + layerWidthInfo[k].nDummyNodes++; + } + +#ifdef UNUSED + if (ND_rank(e->head) != ND_rank(e->tail)) + /* flat edges do not have dummy nodes */ + layerWidthInfo[k].nDummyNodes = abs(ND_rank(e->head) - ND_rank(e->tail)) - 1; +#endif + } +#ifdef UNUSED /***************************************************************** * This code is removed. It considers dummy nodes in layer width, * which does not give good results in experiments. *****************************************************************/ - - /*for (i = 0; i < nNodeGroups; i++) - { - v = nodeGroups[i].nodes[0]; - layerWidthInfo[ND_rank(v)].width = (layerWidthInfo[ND_rank(v)].nDummyNodes - 1) * GD_nodesep(g); - }*/ - - //gather the layer information - for (i = 0; i < nNodeGroups; i++) - { - v = nodeGroups[i].nodes[0]; - if (ND_rank(v)+1 > nLayers) //update the number of layers - nLayers = ND_rank(v)+1; - - layerWidthInfo[ND_rank(v)].width += nodeGroups[i].width*DPI + (layerWidthInfo[ND_rank(v)].width > 0) * GD_nodesep(g); - if (layerWidthInfo[ND_rank(v)].height < nodeGroups[i].height * DPI) - layerWidthInfo[ND_rank(v)].height = nodeGroups[i].height * DPI; - layerWidthInfo[ND_rank(v)].nodeGroupsInLayer[layerWidthInfo[ND_rank(v)].nNodeGroupsInLayer] = &nodeGroups[i]; - layerWidthInfo[ND_rank(v)].nNodeGroupsInLayer++; - } -} + for (i = 0; i < nNodeGroups; i++) { + v = nodeGroups[i].nodes[0]; + layerWidthInfo[ND_rank(v)].width = (layerWidthInfo[ND_rank(v)].nDummyNodes - 1) * GD_nodesep(g); + } +#endif + + /* gather the layer information */ + for (i = 0; i < nNodeGroups; i++) { + v = nodeGroups[i].nodes[0]; + if (ND_rank(v) + 1 > nLayers) /* update the number of layers */ + nLayers = ND_rank(v) + 1; + + layerWidthInfo[ND_rank(v)].width += + nodeGroups[i].width * DPI + (layerWidthInfo[ND_rank(v)].width > + 0) * GD_nodesep(g); + if (layerWidthInfo[ND_rank(v)].height < nodeGroups[i].height * DPI) + layerWidthInfo[ND_rank(v)].height = nodeGroups[i].height * DPI; + layerWidthInfo[ND_rank(v)]. + nodeGroupsInLayer[layerWidthInfo[ND_rank(v)]. + nNodeGroupsInLayer] = &nodeGroups[i]; + layerWidthInfo[ND_rank(v)].nNodeGroupsInLayer++; + } +} -/***************************************************************** +/* compFunction: * Comparison function to be used in qsort. * For sorting the layers by nonincreasing width - *****************************************************************/ - -static int -compFunction(const void *a, const void *b) + */ +static int compFunction(const void *a, const void *b) { - int *ind1 = (int *)a; - int *ind2 = (int *)b; + int *ind1 = (int *) a; + int *ind2 = (int *) b; - return (layerWidthInfo[*ind2].width > layerWidthInfo[*ind1].width) - (layerWidthInfo[*ind2].width < layerWidthInfo[*ind1].width); + return (layerWidthInfo[*ind2].width > + layerWidthInfo[*ind1].width) - (layerWidthInfo[*ind2].width < + layerWidthInfo[*ind1].width); } - -/******************************************************************** +/* sortLayers: * Sort the layers by width (nonincreasing order) * qsort should be replaced by insertion sort for better performance. * (layers are "almost" sorted during iterations) - ********************************************************************/ - -void sortLayers(graph_t *g) + */ +static void sortLayers(graph_t * g) { - qsort(sortedLayerIndex, agnnodes(g), sizeof(int), compFunction); + qsort(sortedLayerIndex, agnnodes(g), sizeof(int), compFunction); } -//get the max # of dummy nodes on the incoming edges to a nodeGroup -static int -getMaxDummyNodes (nodeGroup_t *ng) +#ifdef UNUSED +/* getMaxDummyNodes: + * get the max # of dummy nodes on the incoming edges to a nodeGroup + */ +static int getMaxDummyNodes(nodeGroup_t * ng) { - int i, max = 0, cnt = 0; - for (i = 0; i < ng->nNodes; i++) - { - node_t *n = ng->nodes[i]; - edge_t *e; - graph_t *g = n->graph; - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - { - cnt += ND_rank(e->head) - ND_rank(e->tail); // it's 1 more than the original count - if (ND_rank(e->head) - ND_rank(e->tail) > max) - max = ND_rank(e->head) - ND_rank(e->tail); + int i, max = 0, cnt = 0; + for (i = 0; i < ng->nNodes; i++) { + node_t *n = ng->nodes[i]; + edge_t *e; + graph_t *g = n->graph; + for (e = agfstin(g, n); e; e = agnxtin(g, e)) { + cnt += ND_rank(e->head) - ND_rank(e->tail); // it's 1 more than the original count + if (ND_rank(e->head) - ND_rank(e->tail) > max) + max = ND_rank(e->head) - ND_rank(e->tail); + } } - } - return max; + return max; } +#endif -//Return the sum of out degrees of the nodes in a node group. -static int getOutDegree(nodeGroup_t *ng) +/* getOutDegree: + * Return the sum of out degrees of the nodes in a node group. + */ +static int getOutDegree(nodeGroup_t * ng) { - int i, cnt = 0; - for (i = 0; i < ng->nNodes; i++) - { - node_t *n = ng->nodes[i]; - edge_t *e; - graph_t *g = n->graph; + int i, cnt = 0; + for (i = 0; i < ng->nNodes; i++) { + node_t *n = ng->nodes[i]; + edge_t *e; + graph_t *g = n->graph; - //count outdegree. This loop might be unnecessary. - for (e = agfstout(g,n); e; e=agnxtout(g,e)) - { - cnt++; + /* count outdegree. This loop might be unnecessary. */ + for (e = agfstout(g, n); e; e = agnxtout(g, e)) { + cnt++; + } } - } - - return cnt; + return cnt; } - -/****************************************************************** +/* compFunction2: * Comparison function to be used in qsort. * For sorting the node groups by their out degrees (nondecreasing) - ******************************************************************/ -static int -compFunction2(const void *a, const void *b) + */ +static int compFunction2(const void *a, const void *b) { - nodeGroup_t **ind1 = (nodeGroup_t **)a, **ind2 = (nodeGroup_t **)b; + nodeGroup_t **ind1 = (nodeGroup_t **) a, **ind2 = (nodeGroup_t **) b; - int cnt1 = getOutDegree(*ind1); - int cnt2 = getOutDegree(*ind2); + int cnt1 = getOutDegree(*ind1); + int cnt2 = getOutDegree(*ind2); - return (cnt2 < cnt1) - (cnt2 > cnt1); + return (cnt2 < cnt1) - (cnt2 > cnt1); } - -/***************************************************************** +#ifdef UNUSED +/* compFunction3: * Comparison function to be used in qsort. * For sorting the node groups by their height & width - *****************************************************************/ -static int -compFunction3(const void *a, const void *b) + */ +static int compFunction3(const void *a, const void *b) { - nodeGroup_t **ind1 = (nodeGroup_t **)a, **ind2 = (nodeGroup_t **)b; - if ((*ind2)->height == (*ind1)->height) - return ((*ind2)->width < (*ind1)->width) - ((*ind2)->width > (*ind1)->width); + nodeGroup_t **ind1 = (nodeGroup_t **) a, **ind2 = (nodeGroup_t **) b; + if ((*ind2)->height == (*ind1)->height) + return ((*ind2)->width < (*ind1)->width) - ((*ind2)->width > + (*ind1)->width); - return ((*ind2)->height < (*ind1)->height) - ((*ind2)->height > (*ind1)->height); + return ((*ind2)->height < (*ind1)->height) - ((*ind2)->height > + (*ind1)->height); } - /***************************************************************** * The following commented codes are no longer used * Originally used in the cocktail tool. *****************************************************************/ -/* -//check if there is any node group in the layer that is not constrained by MIN/MAX/SOURCE/SINK-RANK constraints. - -static int -checkLayerConstraints(layerWidthInfo_t lwi) +/* checkLayerConstraints: + * check if there is any node group in the layer + * that is not constrained by MIN/MAX/SOURCE/SINK-RANK constraints. + */ +static int checkLayerConstraints(layerWidthInfo_t lwi) { - int i; - for (i = 0; i < lwi.nNodeGroupsInLayer; i++) - { - if (lwi.nodeGroupsInLayer[i]->nNodes > 0) - { - int rtype = ND_ranktype(lwi.nodeGroupsInLayer[i]->nodes[0]); - if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK && rtype != SINKRANK) - return 1; + int i; + for (i = 0; i < lwi.nNodeGroupsInLayer; i++) { + if (lwi.nodeGroupsInLayer[i]->nNodes > 0) { + int rtype = ND_ranktype(lwi.nodeGroupsInLayer[i]->nodes[0]); + if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK + && rtype != SINKRANK) + return 1; + } } - } - return 0; + return 0; } -//check if all the node groups in the layer are constrained by MIN/MAX/SOURCE/SINK-RANK constraints -static int -checkLayerConstraints(layerWidthInfo_t lwi) +/* checkLayerConstraints: + * check if all the node groups in the layer are + * constrained by MIN/MAX/SOURCE/SINK-RANK constraints + */ +static int checkLayerConstraints(layerWidthInfo_t lwi) { - int i; - for (i = 0; i < lwi.nNodeGroupsInLayer; i++) - { - if (lwi.nodeGroupsInLayer[i]->nNodes > 0) - { - int rtype = ND_ranktype(lwi.nodeGroupsInLayer[i]->nodes[0]); - if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK && rtype != SINKRANK) - return 0; + int i; + for (i = 0; i < lwi.nNodeGroupsInLayer; i++) { + if (lwi.nodeGroupsInLayer[i]->nNodes > 0) { + int rtype = ND_ranktype(lwi.nodeGroupsInLayer[i]->nodes[0]); + if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK + && rtype != SINKRANK) + return 0; + } } - } - return 1; + return 1; } -*/ - - -/***************************************************************** +/* checkNodeGroupConstraints: * check if the node group is not constrained by * MIN/MAX/SOURCE/SINK-RANK constraints * Only used in the cocktail tool. - *****************************************************************/ - -static int -checkNodeGroupConstraints(nodeGroup_t *ndg) + */ +static int checkNodeGroupConstraints(nodeGroup_t * ndg) { - int i; - int rtype = ND_ranktype(ndg->nodes[0]); + int i; + int rtype = ND_ranktype(ndg->nodes[0]); - if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK && rtype != SINKRANK) - return 1; + if (rtype != MINRANK && rtype != MAXRANK && rtype != SOURCERANK + && rtype != SINKRANK) + return 1; - return 0; + return 0; } - -/***************************************************************** +/* checkHorizontalEdge: * check if there is an edge from ng to a node in * layerWidthInfo[nextLayerIndex]. * Only used in the cocktail tool. - *****************************************************************/ - + */ static int -checkHorizontalEdge(graph_t *g, nodeGroup_t *ng, int nextLayerIndex) +checkHorizontalEdge(graph_t * g, nodeGroup_t * ng, int nextLayerIndex) { - int i; - edge_t *e; - - for (i = 0; i < ng->nNodes; i++) - { - for (e = agfstout(g, ng->nodes[i]); e; e = agnxtout(g, e)) - { - if (layerWidthInfo[nextLayerIndex].layerNumber == ND_rank(e->head)) - { - return 1; + int i; + edge_t *e; + + for (i = 0; i < ng->nNodes; i++) { + for (e = agfstout(g, ng->nodes[i]); e; e = agnxtout(g, e)) { + if (layerWidthInfo[nextLayerIndex].layerNumber == + ND_rank(e->head)) { + return 1; + } } } - } - return 0; + return 0; } - -/***************************************************************** +/* hasMaxOrSinkNodes: * check if the the layer lwi has MAX or SINK nodes * Only used in the cocktail tool. - *****************************************************************/ - -static int -hasMaxOrSinkNodes(layerWidthInfo_t *lwi) + */ +static int hasMaxOrSinkNodes(layerWidthInfo_t * lwi) { - int i, j; - - for (i = 0; i < lwi->nNodeGroupsInLayer; i++) - { - if (lwi->removed[i]) - continue; - for (j = 0; j < lwi->nodeGroupsInLayer[i]->nNodes; j++) - { - if (ND_ranktype(lwi->nodeGroupsInLayer[i]->nodes[j]) == MAXRANK || ND_ranktype(lwi->nodeGroupsInLayer[i]->nodes[j]) == SINKRANK) - return 1; + int i, j; + + for (i = 0; i < lwi->nNodeGroupsInLayer; i++) { + if (lwi->removed[i]) + continue; + for (j = 0; j < lwi->nodeGroupsInLayer[i]->nNodes; j++) { + if (ND_ranktype(lwi->nodeGroupsInLayer[i]->nodes[j]) == MAXRANK + || ND_ranktype(lwi->nodeGroupsInLayer[i]->nodes[j]) == + SINKRANK) + return 1; + } } - } - - return 0; + + return 0; } -/***************************************************************** +/* reduceMaxWidth: * The following function is no longer used. * Originally used for FFDH packing heuristic - *****************************************************************/ - -//FFDH procedure -void reduceMaxWidth(graph_t *g) + * FFDH procedure + */ +static void reduceMaxWidth(graph_t * g) { - int i; - int maxLayerIndex; // = sortedLayerIndex[0]; - double nextMaxWidth; // = (nLayers > 1) ? layerWidthInfo[sortedLayerIndex[1]].width : 0; - double w = 0; - Agnode_t *v; - - for (i=0; i < nLayers; i++) - { - if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1)// || !checkLayerConstraints(layerWidthInfo[sortedLayerIndex[i]])) - continue; - else - { - maxLayerIndex = sortedLayerIndex[i]; - nextMaxWidth = (nLayers > i+1) ? layerWidthInfo[sortedLayerIndex[i+1]].width : 0; - break; + int i; + int maxLayerIndex; // = sortedLayerIndex[0]; + double nextMaxWidth; // = (nLayers > 1) ? layerWidthInfo[sortedLayerIndex[1]].width : 0; + double w = 0; + Agnode_t *v; + + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1) // || !checkLayerConstraints(layerWidthInfo[sortedLayerIndex[i]])) + continue; + else { + maxLayerIndex = sortedLayerIndex[i]; + nextMaxWidth = + (nLayers > + i + 1) ? layerWidthInfo[sortedLayerIndex[i + + 1]].width : 0; + break; + } } - } - - if (i == nLayers) - return; //reduction of layerwidth is not possible. - - - //sort the node groups in maxLayerIndex layer by height and then width, nonincreasing - qsort(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer, layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer, sizeof(nodeGroup_t *), compFunction2); - //printf("ht0 = %lf, ht1 = %lf\n", ND_height(layerWidthInfo[maxLayerIndex].nodes[0]), ND_height(layerWidthInfo[maxLayerIndex].nodes[1])); - - - if (nextMaxWidth <= layerWidthInfo[maxLayerIndex].width/2 || nextMaxWidth == layerWidthInfo[maxLayerIndex].width) - nextMaxWidth = layerWidthInfo[maxLayerIndex].width/2; - - double targetWidth = nextMaxWidth;//layerWidthInfo[maxLayerIndex].width/2; - - //printf("max = %lf, target = %lf\n", layerWidthInfo[maxLayerIndex].width, targetWidth);//, w + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width ); - //getchar(); - - - //packing by node demotion - int nextLayerIndex = -1; - for (i = 0; i < nLayers; i++) - { - if (layerWidthInfo[i].layerNumber == layerWidthInfo[maxLayerIndex].layerNumber + 1) - nextLayerIndex = i; - } - - if (nextLayerIndex > -1) - { - //if (layerWidthInfo[nextLayerIndex].width <= 0.5*layerWidthInfo[maxLayerIndex].width) - //{ - int changed = 0; - //demote nodes to the next layer - for (i=0; iwidth <= targetWidth ) - { - w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width; - changed++; - - int j; - nodeGroup_t *ng = layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; - - layerWidthInfo[maxLayerIndex].removed[i] = 1; - layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; - layerWidthInfo[maxLayerIndex].width -= ng->width; - for (j = 0; j < ng->nNodes; j++) - ND_rank(ng->nodes[j])++; - - - layerWidthInfo[nextLayerIndex].nodeGroupsInLayer[layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer] = ng; - layerWidthInfo[nextLayerIndex].removed[layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer] = 0; - layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer++; - layerWidthInfo[nextLayerIndex].width += ng->width; - - int jj; - for (jj=0; jjnodes[0]->name); - } + if (i == nLayers) + return; //reduction of layerwidth is not possible. + + + //sort the node groups in maxLayerIndex layer by height and then width, nonincreasing + qsort(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer, + layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer, + sizeof(nodeGroup_t *), compFunction2); + //printf("ht0 = %lf, ht1 = %lf\n", ND_height(layerWidthInfo[maxLayerIndex].nodes[0]), ND_height(layerWidthInfo[maxLayerIndex].nodes[1])); + + + if (nextMaxWidth <= layerWidthInfo[maxLayerIndex].width / 2 + || nextMaxWidth == layerWidthInfo[maxLayerIndex].width) + nextMaxWidth = layerWidthInfo[maxLayerIndex].width / 2; + + double targetWidth = nextMaxWidth; //layerWidthInfo[maxLayerIndex].width/2; + + //printf("max = %lf, target = %lf\n", layerWidthInfo[maxLayerIndex].width, targetWidth);//, w + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width ); + //getchar(); + + + //packing by node demotion + int nextLayerIndex = -1; + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[i].layerNumber == + layerWidthInfo[maxLayerIndex].layerNumber + 1) + nextLayerIndex = i; + } + + if (nextLayerIndex > -1) { + //if (layerWidthInfo[nextLayerIndex].width <= 0.5*layerWidthInfo[maxLayerIndex].width) + //{ + int changed = 0; + //demote nodes to the next layer + for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; + i++) { + if (layerWidthInfo[maxLayerIndex].removed[i]) + continue; + + if (!checkHorizontalEdge + (g, layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i], + nextLayerIndex) + && w + layerWidthInfo[nextLayerIndex].width + + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])-> + width <= targetWidth) { + w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])-> + width; + changed++; + + int j; + nodeGroup_t *ng = + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; + + layerWidthInfo[maxLayerIndex].removed[i] = 1; + layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; + layerWidthInfo[maxLayerIndex].width -= ng->width; + for (j = 0; j < ng->nNodes; j++) + ND_rank(ng->nodes[j])++; + + + layerWidthInfo[nextLayerIndex]. + nodeGroupsInLayer[layerWidthInfo[nextLayerIndex]. + nNodeGroupsInLayer] = ng; + layerWidthInfo[nextLayerIndex]. + removed[layerWidthInfo[nextLayerIndex]. + nNodeGroupsInLayer] = 0; + layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer++; + layerWidthInfo[nextLayerIndex].width += ng->width; + + int jj; + for (jj = 0; + jj < + layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer; + jj++) { + //printf("%s\n", layerWidthInfo[nextLayerIndex].nodeGroupsInLayer[jj]->nodes[0]->name); + } + } + } - } + if (changed) { + //printf("Demoted %d nodes\n", changed); + return; + } + //} + } + //packing by creating new layers. Must be commented out if packing by demotion is used + + //going to create a new layer. increase the rank of all higher ranked nodes. (to be modified...) + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + if (ND_rank(v) > layerWidthInfo[maxLayerIndex].layerNumber) ///////////******** +1 + ND_rank(v)++; + } + + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[i].layerNumber > + layerWidthInfo[maxLayerIndex].layerNumber) + layerWidthInfo[i].layerNumber++; + } + + //now partition the current layer into two layers (to be modified to support general case of > 2 layers) + int flag = 0; //is a new layer created? + int alt = 0; + for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; i++) { + if (layerWidthInfo[maxLayerIndex].removed[i]) + continue; - if (changed) + //nodesep-> only if there are > 1 nodes******************************* + if ((w + + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width * + DPI + (w > 0) * GD_nodesep(g) <= targetWidth && alt == 0 + && ND_ranktype(layerWidthInfo[maxLayerIndex]. + nodeGroupsInLayer[i]->nodes[0]) != SINKRANK + && ND_ranktype(layerWidthInfo[maxLayerIndex]. + nodeGroupsInLayer[i]->nodes[0]) != MAXRANK) + || + (ND_ranktype + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]-> + nodes[0]) != SINKRANK + && ND_ranktype(layerWidthInfo[maxLayerIndex]. + nodeGroupsInLayer[i]->nodes[0]) != MAXRANK + && hasMaxOrSinkNodes(&layerWidthInfo[maxLayerIndex])) + ) + //&& ND_pinned(layerWidthInfo[maxLayerIndex].nodes[i]) == 0 ) { - //printf("Demoted %d nodes\n", changed); - return; + w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])-> + width * DPI + (w > 0) * GD_nodesep(g); + alt = 1; + } else { + int j; + nodeGroup_t *ng = + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; + + flag = 1; + + layerWidthInfo[maxLayerIndex].removed[i] = 1; + layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; + layerWidthInfo[maxLayerIndex].nDummyNodes++; /////************** SHOULD BE INCREASED BY THE SUM OF INDEG OF ALL NODES IN GROUP + layerWidthInfo[maxLayerIndex].width -= + (ng->width * DPI + GD_nodesep(g)); + for (j = 0; j < ng->nNodes; j++) + ND_rank(ng->nodes[j])++; + + //create new layer + layerWidthInfo[nLayers]. + nodeGroupsInLayer[layerWidthInfo[nLayers]. + nNodeGroupsInLayer] = ng; + layerWidthInfo[nLayers].nNodeGroupsInLayer++; + layerWidthInfo[nLayers].layerNumber = ND_rank(ng->nodes[0]); + + layerWidthInfo[nLayers].width += (ng->width * DPI + (layerWidthInfo[nLayers].nNodeGroupsInLayer > 1) * GD_nodesep(g)); // just add the node widths now. + + alt = 0; } - //} - } - - //packing by creating new layers. Must be commented out if packing by demotion is used - - //going to create a new layer. increase the rank of all higher ranked nodes. (to be modified...) - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - if (ND_rank(v) > layerWidthInfo[maxLayerIndex].layerNumber) ///////////******** +1 - ND_rank(v)++; - } - - for (i = 0; i < nLayers; i++) - { - if (layerWidthInfo[i].layerNumber > layerWidthInfo[maxLayerIndex].layerNumber) - layerWidthInfo[i].layerNumber++; - } - - //now partition the current layer into two layers (to be modified to support general case of > 2 layers) - int flag = 0; //is a new layer created? - int alt = 0; - for (i=0; i only if there are > 1 nodes******************************* - if ( (w + (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width*DPI + (w>0)*GD_nodesep(g) <= targetWidth && alt == 0 && ND_ranktype(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->nodes[0]) != SINKRANK && ND_ranktype(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->nodes[0]) != MAXRANK) - || - (ND_ranktype(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->nodes[0]) != SINKRANK && ND_ranktype(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->nodes[0]) != MAXRANK && hasMaxOrSinkNodes(&layerWidthInfo[maxLayerIndex]) ) - ) - //&& ND_pinned(layerWidthInfo[maxLayerIndex].nodes[i]) == 0 ) - { - w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width*DPI + (w > 0) * GD_nodesep(g); - alt = 1; - } - else - { - int j; - nodeGroup_t *ng = layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; - - flag = 1; - - layerWidthInfo[maxLayerIndex].removed[i] = 1; - layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; - layerWidthInfo[maxLayerIndex].nDummyNodes++; /////************** SHOULD BE INCREASED BY THE SUM OF INDEG OF ALL NODES IN GROUP - layerWidthInfo[maxLayerIndex].width -= (ng->width*DPI + GD_nodesep(g)); - for (j = 0; j < ng->nNodes; j++) - ND_rank(ng->nodes[j])++; - - //create new layer - layerWidthInfo[nLayers].nodeGroupsInLayer[layerWidthInfo[nLayers].nNodeGroupsInLayer] = ng; - layerWidthInfo[nLayers].nNodeGroupsInLayer++; - layerWidthInfo[nLayers].layerNumber = ND_rank(ng->nodes[0]); - - layerWidthInfo[nLayers].width += ( ng->width*DPI + (layerWidthInfo[nLayers].nNodeGroupsInLayer > 1) * GD_nodesep(g) ); // just add the node widths now. - - alt = 0; } - } - if (flag) - { - //calculate number of dummy nodes - node_t *n; - edge_t *e; - int nDummy = 0; - - for (n = agfstnode(g); n; n = agnxtnode(g, n)) - for (e = agfstout(g, n); e; e = agnxtout(g, e)) - { - if ( (ND_rank(e->head) > layerWidthInfo[nLayers].layerNumber && ND_rank(e->tail) < layerWidthInfo[nLayers].layerNumber) - || - (ND_rank(e->head) < layerWidthInfo[nLayers].layerNumber && ND_rank(e->tail) > layerWidthInfo[nLayers].layerNumber) - ) - nDummy++; - } - - layerWidthInfo[nLayers].nDummyNodes = nDummy; - layerWidthInfo[nLayers].width += (layerWidthInfo[nLayers].nDummyNodes - 1) * GD_nodesep(g); - nLayers++; - } - - else - { - //undo increment of ranks and layerNumbers.***************** - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - if (ND_rank(v) > layerWidthInfo[maxLayerIndex].layerNumber+1) - ND_rank(v)--; - } - - for (i = 0; i < nLayers; i++) - { - if (layerWidthInfo[i].layerNumber > layerWidthInfo[maxLayerIndex].layerNumber+1) - layerWidthInfo[i].layerNumber--; + if (flag) { + //calculate number of dummy nodes + node_t *n; + edge_t *e; + int nDummy = 0; + + for (n = agfstnode(g); n; n = agnxtnode(g, n)) + for (e = agfstout(g, n); e; e = agnxtout(g, e)) { + if ((ND_rank(e->head) > layerWidthInfo[nLayers].layerNumber + && ND_rank(e->tail) < + layerWidthInfo[nLayers].layerNumber) + || (ND_rank(e->head) < + layerWidthInfo[nLayers].layerNumber + && ND_rank(e->tail) > + layerWidthInfo[nLayers].layerNumber) + ) + nDummy++; + } + + layerWidthInfo[nLayers].nDummyNodes = nDummy; + layerWidthInfo[nLayers].width += + (layerWidthInfo[nLayers].nDummyNodes - 1) * GD_nodesep(g); + nLayers++; } - } -} + else { + //undo increment of ranks and layerNumbers.***************** + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + if (ND_rank(v) > layerWidthInfo[maxLayerIndex].layerNumber + 1) + ND_rank(v)--; + } + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[i].layerNumber > + layerWidthInfo[maxLayerIndex].layerNumber + 1) + layerWidthInfo[i].layerNumber--; + } + } +} +#endif -/***************************************************************** +/* reduceMaxWidth2: * This is the main heuristic for partitioning the widest layer. * Partitioning is based on outdegrees of nodes. * Replace compFunction2 by compFunction3 if you want to partition * by node widths and heights. - *****************************************************************/ - -//FFDH procedure -void reduceMaxWidth2(graph_t *g) + * FFDH procedure + */ +static void reduceMaxWidth2(graph_t * g) { - int i; - int maxLayerIndex; - double nextMaxWidth; - double w = 0; - Agnode_t *v, *n; - - //Find the widest layer. it must have at least 2 nodes. - for (i=0; i < nLayers; i++) - { - if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1) - continue; - else - { - maxLayerIndex = sortedLayerIndex[i]; - //get the width of the next widest layer - nextMaxWidth = (nLayers > i+1) ? layerWidthInfo[sortedLayerIndex[i+1]].width : 0; - break; + int i; + int maxLayerIndex; + double nextMaxWidth; + double w = 0; + double targetWidth; + int fst; + nodeGroup_t *fstNdGrp; + int ndem; + int p, q; + int limit; + int rem; + int rem2; + + + /* Find the widest layer. it must have at least 2 nodes. */ + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1) + continue; + else { + maxLayerIndex = sortedLayerIndex[i]; + /* get the width of the next widest layer */ + nextMaxWidth = + (nLayers > + i + 1) ? layerWidthInfo[sortedLayerIndex[i + + 1]].width : 0; + break; + } } - } - - if (i == nLayers) - return; //reduction of layerwidth is not possible. - - //sort the node groups in maxLayerIndex layer by height and then width, nonincreasing - qsort(layerWidthInfo[maxLayerIndex].nodeGroupsInLayer, layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer, sizeof(nodeGroup_t *), compFunction2); - - //printf("ht0 = %lf, ht1 = %lf\n", ND_height(layerWidthInfo[maxLayerIndex].nodes[0]), ND_height(layerWidthInfo[maxLayerIndex].nodes[1])); - /* - printf("\nSorted nodes in mx layer:\n---------------------------\n"); - for (i=0; inodes[0]->name, layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->width, layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->height); - }*/ - - - if (nextMaxWidth <= layerWidthInfo[maxLayerIndex].width/4 || nextMaxWidth >= layerWidthInfo[maxLayerIndex].width*3/4) - nextMaxWidth = layerWidthInfo[maxLayerIndex].width/2; - - double targetWidth = nextMaxWidth;//layerWidthInfo[maxLayerIndex].width/2; - - //now partition the current layer into two or more layers (determined by the ranking algorithm) - int flag = 0; //is a new layer created? - int alt = 0; - int fst = 0; - nodeGroup_t *fstNdGrp; - int ndem = 0; - - //initialize w, the width of the widest layer after partitioning - w = 0; - - int limit = layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; - int rem = 0; - int rem2 = 0; - - for (i=0; i + nodes[0]->name, + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->width, + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->height); } +#endif - if ( (w + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->width*DPI + (w>0)*GD_nodesep(g) <= targetWidth) - || - !fst - ) - { - w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width*DPI + (w > 0) * GD_nodesep(g); - if (!fst) - { - fstNdGrp = layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; - fst = 1; + if (nextMaxWidth <= layerWidthInfo[maxLayerIndex].width / 4 + || nextMaxWidth >= layerWidthInfo[maxLayerIndex].width * 3 / 4) + nextMaxWidth = layerWidthInfo[maxLayerIndex].width / 2; + + targetWidth = nextMaxWidth; /* layerWidthInfo[maxLayerIndex].width/2; */ + + /* now partition the current layer into two or more + * layers (determined by the ranking algorithm) + */ + fst = 0; + ndem = 0; + limit = layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; + rem = 0; + rem2 = 0; + + /* initialize w, the width of the widest layer after partitioning */ + w = 0; + + for (i = 0; i < limit + rem; i++) { + if (layerWidthInfo[maxLayerIndex].removed[i]) { + rem++; + continue; } - } - else - { - int j; - nodeGroup_t *ng = layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; - - - //The following code corrects w by adding dummy node spacing. It's no longer used - /*int l; - for (l = 0; l < ng->nNodes; l++) - { - w += (ND_in(ng->nodes[l]).size - 1) * GD_nodesep(g); - }*/ - - int p, q; - for (p = 0; p < fstNdGrp->nNodes; p++) - for (q = 0; q < ng->nNodes; q++) - { - //printf("Trying to add virtual edge: %s -> %s\n", fstNdGrp->nodes[p]->name, ng->nodes[q]->name); - edge_t *ev; - int s, cnt = 0; - - //The following code is for deletion of long virtual edges. - //It's no longer used. - - /*for (s = ND_in(ng->nodes[q]).size - 1; s >= 0; s--) - { - ev = ND_in(ng->nodes[q]).list[s]; - - edge_t *et; - int fail = 0; - cnt =0; - - for (et = agfstin(g,ev->head); et; et = agnxtin(g,et)) - { - if (et->head == ev->head && et->tail == ev->tail) - { - fail = 1; - break; - } - } - if (fail) - { - //printf("FAIL DETECTED\n"); - continue; + if ((w + + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]->width * + DPI + (w > 0) * GD_nodesep(g) <= targetWidth) + || !fst) { + w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])-> + width * DPI + (w > 0) * GD_nodesep(g); + if (!fst) { + fstNdGrp = + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; + fst = 1; + } + } else { + nodeGroup_t *ng = + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; + + +#ifdef UNUSED + /* The following code corrects w by adding dummy node spacing. + * It's no longer used + */ + int l; + for (l = 0; l < ng->nNodes; l++) { + w += (ND_in(ng->nodes[l]).size - 1) * GD_nodesep(g); + } +#endif + + for (p = 0; p < fstNdGrp->nNodes; p++) + for (q = 0; q < ng->nNodes; q++) { + //printf("Trying to add virtual edge: %s -> %s\n", fstNdGrp->nodes[p]->name, ng->nodes[q]->name); + + /* The following code is for deletion of long virtual edges. + * It's no longer used. + */ +#ifdef UNUSED + for (s = ND_in(ng->nodes[q]).size - 1; s >= 0; s--) { + ev = ND_in(ng->nodes[q]).list[s]; + + edge_t *et; + int fail = 0; + cnt = 0; + + for (et = agfstin(g, ev->head); et; + et = agnxtin(g, et)) { + if (et->head == ev->head + && et->tail == ev->tail) { + fail = 1; + break; + } + } + + if (fail) { + //printf("FAIL DETECTED\n"); + continue; + } + + + if (ED_edge_type(ev) == VIRTUAL + && ND_rank(ev->head) > ND_rank(ev->tail) + 1) { + //printf("%d. inNode= %s.deleted: %s->%s\n", test++, ng->nodes[q]->name, ev->tail->name, ev->head->name); + + delete_fast_edge(ev); + free(ev); + } + } +#endif + + /* add a new virtual edge */ + edge_t *newVEdge = + virtual_edge(fstNdGrp->nodes[p], ng->nodes[q], + NULL); + ED_edge_type(newVEdge) = VIRTUAL; + ndem++; /* increase number of node demotions */ } - - - if (ED_edge_type(ev) == VIRTUAL && ND_rank(ev->head) > ND_rank(ev->tail)+1) - { - //printf("%d. inNode= %s.deleted: %s->%s\n", test++, ng->nodes[q]->name, ev->tail->name, ev->head->name); - - delete_fast_edge(ev); - free(ev); - } - }*/ - - //add a new virtual edge - edge_t *newVEdge = virtual_edge(fstNdGrp->nodes[p], ng->nodes[q], NULL); - ED_edge_type(newVEdge) = VIRTUAL; - ndem++; //increase number of node demotions - } - - //the following code updates the layer width information. The update is not useful in the current version of the heuristic. - - layerWidthInfo[maxLayerIndex].removed[i] = 1; - rem2++; - layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; - layerWidthInfo[maxLayerIndex].nDummyNodes++; /////************** SHOULD BE INCREASED BY THE SUM OF INDEG OF ALL NODES IN GROUP - layerWidthInfo[maxLayerIndex].width -= (ng->width*DPI + GD_nodesep(g)); + + /* the following code updates the layer width information. The + * update is not useful in the current version of the heuristic. + */ + layerWidthInfo[maxLayerIndex].removed[i] = 1; + rem2++; + layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; + /* SHOULD BE INCREASED BY THE SUM OF INDEG OF ALL NODES IN GROUP */ + layerWidthInfo[maxLayerIndex].nDummyNodes++; + layerWidthInfo[maxLayerIndex].width -= + (ng->width * DPI + GD_nodesep(g)); + } } - } } - -/***************************************************************** +#ifdef UNUSED +/* balanceLayers: * The following is the layer balancing heuristic. * Balance the widths of the layers as much as possible. * It's no longer used. - *****************************************************************/ - -void balanceLayers(graph_t *g) + */ +static void balanceLayers(graph_t * g) { - int maxLayerIndex, nextLayerIndex, i; - double maxWidth, w; - - //get the max width layer number - - for (i=0; i < nLayers; i++) - { - if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1 - || - layerWidthInfo[sortedLayerIndex[i]].layerNumber+1 == nLayers) - continue; - else - { - maxLayerIndex = sortedLayerIndex[i]; - maxWidth = layerWidthInfo[maxLayerIndex].width; - printf("Balancing: maxLayerIndex = %d\n", maxLayerIndex); - break; - } - } - - if (i == nLayers) - return; //reduction of layerwidth is not possible. - - //balancing ~~ packing by node demotion - nextLayerIndex = -1; - for (i = 0; i < nLayers; i++) - { - if (layerWidthInfo[i].layerNumber == layerWidthInfo[maxLayerIndex].layerNumber + 1) - { - nextLayerIndex = i; + int maxLayerIndex, nextLayerIndex, i; + double maxWidth, w; + + //get the max width layer number + + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[sortedLayerIndex[i]].nNodeGroupsInLayer <= 1 + || + layerWidthInfo[sortedLayerIndex[i]].layerNumber + 1 == nLayers) + continue; + else { + maxLayerIndex = sortedLayerIndex[i]; + maxWidth = layerWidthInfo[maxLayerIndex].width; + printf("Balancing: maxLayerIndex = %d\n", maxLayerIndex); + break; + } } - } - - if (nextLayerIndex > -1) - { - //if (layerWidthInfo[nextLayerIndex].width <= 0.5*layerWidthInfo[maxLayerIndex].width) - //{ - int changed = 0; - w = 0; - - //demote nodes to the next layer - for (i=0; iwidth*/ <= layerWidthInfo[maxLayerIndex].width /*- (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width*/) - { - w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width; - changed++; - - int j; - nodeGroup_t *ng = layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; - - layerWidthInfo[maxLayerIndex].removed[i] = 1; - layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; - layerWidthInfo[maxLayerIndex].width -= (ng->width); - layerWidthInfo[maxLayerIndex].nDummyNodes++; - for (j = 0; j < ng->nNodes; j++) - ND_rank(ng->nodes[j])++; - - - layerWidthInfo[nextLayerIndex].nodeGroupsInLayer[layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer] = ng; - layerWidthInfo[nextLayerIndex].removed[layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer] = 0; - layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer++; - layerWidthInfo[nextLayerIndex].width += (ng->width + GD_nodesep(g)); + if (i == nLayers) + return; //reduction of layerwidth is not possible. + + //balancing ~~ packing by node demotion + nextLayerIndex = -1; + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[i].layerNumber == + layerWidthInfo[maxLayerIndex].layerNumber + 1) { + nextLayerIndex = i; } + } - } + if (nextLayerIndex > -1) { + //if (layerWidthInfo[nextLayerIndex].width <= 0.5*layerWidthInfo[maxLayerIndex].width) + //{ + int changed = 0; + w = 0; + + //demote nodes to the next layer + for (i = 0; i < layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer; + i++) { + if (layerWidthInfo[maxLayerIndex].removed[i]) + continue; + + if (!checkHorizontalEdge + (g, layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i], + nextLayerIndex) + && layerWidthInfo[nextLayerIndex].width + /*+ (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width */ + <= layerWidthInfo[maxLayerIndex].width + /*- (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])->width*/ + ) { + w += (layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i])-> + width; + changed++; + + int j; + nodeGroup_t *ng = + layerWidthInfo[maxLayerIndex].nodeGroupsInLayer[i]; + + layerWidthInfo[maxLayerIndex].removed[i] = 1; + layerWidthInfo[maxLayerIndex].nNodeGroupsInLayer--; + layerWidthInfo[maxLayerIndex].width -= (ng->width); + layerWidthInfo[maxLayerIndex].nDummyNodes++; + for (j = 0; j < ng->nNodes; j++) + ND_rank(ng->nodes[j])++; + + + layerWidthInfo[nextLayerIndex]. + nodeGroupsInLayer[layerWidthInfo[nextLayerIndex]. + nNodeGroupsInLayer] = ng; + layerWidthInfo[nextLayerIndex]. + removed[layerWidthInfo[nextLayerIndex]. + nNodeGroupsInLayer] = 0; + layerWidthInfo[nextLayerIndex].nNodeGroupsInLayer++; + layerWidthInfo[nextLayerIndex].width += + (ng->width + GD_nodesep(g)); + } - if (changed) - { - //printf("Demoted %d nodes\n", changed); - return; } - //} - } -} + if (changed) { + //printf("Demoted %d nodes\n", changed); + return; + } + //} + } +} -/***************************************************************** +/* applyPacking: * The following is the initial packing heuristic * It's no longer used. - *****************************************************************/ - -void applyPacking(graph_t *g, double targetAR) + */ +static void applyPacking(graph_t * g, double targetAR) { - int i; + int i; - sortedLayerIndex = (int *)malloc(sizeof(int)*agnnodes(g)); - if (sortedLayerIndex == NULL) - agerr(AGERR, "Memory allocation error in applyPacking function.\n"); + sortedLayerIndex = N_NEW(agnnodes(g), int); - for (i=0; iname, ND_rank(v), ND_ranktype(v)); - } + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + //printf("%s, rank = %d, ranktype = %d\n", v->name, ND_rank(v), ND_ranktype(v)); + } //GD_nodesep(g) = 0.25; //GD_ranksep(g) = 0.25; //////////////////// //printf("Nodesep = %d, Ranksep = %d\n",GD_nodesep(g), GD_ranksep(g)); - - - for (i=0; i<1; i++) - { - //printf("iteration = %d\n----------------------\n", i); - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - //printf("%s rank = %d\n", v->name, ND_rank(v)); - } - computeLayerWidths(g); - sortLayers(g); - reduceMaxWidth(g); - //printf("====================\n"); + for (i = 0; i < 1; i++) { + //printf("iteration = %d\n----------------------\n", i); + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + //printf("%s rank = %d\n", v->name, ND_rank(v)); + } + + computeLayerWidths(g); + sortLayers(g); + reduceMaxWidth(g); + + //printf("====================\n"); } - - - int k; - - for (k = 0; k < nLayers-1; k++) - { - int cnt = 0, tg; - if (layerWidthInfo[k].nNodeGroupsInLayer > 7) - { - - cnt = 0; - tg = layerWidthInfo[k].nNodeGroupsInLayer - 7; - - for (i = layerWidthInfo[k].nNodeGroupsInLayer-1; i >=0; i--) - { - if (layerWidthInfo[k].removed[i]) - continue; - int j; - nodeGroup_t *ng = layerWidthInfo[k].nodeGroupsInLayer[i]; + int k; + + for (k = 0; k < nLayers - 1; k++) { + int cnt = 0, tg; + if (layerWidthInfo[k].nNodeGroupsInLayer > 7) { + + cnt = 0; + tg = layerWidthInfo[k].nNodeGroupsInLayer - 7; + + for (i = layerWidthInfo[k].nNodeGroupsInLayer - 1; i >= 0; i--) { + + if (layerWidthInfo[k].removed[i]) + continue; + + int j; + nodeGroup_t *ng = layerWidthInfo[k].nodeGroupsInLayer[i]; - layerWidthInfo[k].removed[i] = 1; - layerWidthInfo[k].nNodeGroupsInLayer--; - layerWidthInfo[k].nDummyNodes++; - layerWidthInfo[k].width -= (ng->width*DPI + GD_nodesep(g)); - for (j = 0; j < ng->nNodes; j++) - ND_rank(ng->nodes[j])++; + layerWidthInfo[k].removed[i] = 1; + layerWidthInfo[k].nNodeGroupsInLayer--; + layerWidthInfo[k].nDummyNodes++; + layerWidthInfo[k].width -= + (ng->width * DPI + GD_nodesep(g)); + for (j = 0; j < ng->nNodes; j++) + ND_rank(ng->nodes[j])++; - //create new layer - layerWidthInfo[k+1].nodeGroupsInLayer[layerWidthInfo[k+1].nNodeGroupsInLayer] = ng; - layerWidthInfo[k+1].nNodeGroupsInLayer++; - //layerWidthInfo[k+1].layerNumber = ND_rank(ng->nodes[0]); - - //layerWidthInfo[k+1].width += ( ng->width*DPI + (layerWidthInfo[nLayers].nNodeGroupsInLayer > 1) * GD_nodesep(g) ); // just add the node widths now. + //create new layer + layerWidthInfo[k + + 1].nodeGroupsInLayer[layerWidthInfo[k + + 1]. + nNodeGroupsInLayer] = + ng; + layerWidthInfo[k + 1].nNodeGroupsInLayer++; + //layerWidthInfo[k+1].layerNumber = ND_rank(ng->nodes[0]); - cnt++; - - if (cnt == tg) - break; + //layerWidthInfo[k+1].width += ( ng->width*DPI + (layerWidthInfo[nLayers].nNodeGroupsInLayer > 1) * GD_nodesep(g) ); // just add the node widths now. + cnt++; + + if (cnt == tg) + break; + + } } } - } - + //calcualte the max width int maxW = 0; int nNodeG = 0, l, nDummy = 0; int index; - for (k=0; knodes[0]->name); - if (layerWidthInfo[k].width > maxW)// && layerWidthInfo[k].nNodeGroupsInLayer > 0) - { + if (layerWidthInfo[k].width > maxW) // && layerWidthInfo[k].nNodeGroupsInLayer > 0) + { maxW = layerWidthInfo[k].width; nNodeG = layerWidthInfo[k].nNodeGroupsInLayer; l = layerWidthInfo[k].layerNumber; nDummy = layerWidthInfo[k].nDummyNodes; index = k; - } - } + } + } //printf("Ht=%d, MxW=%d, #ndGr=%d, #dumNd=%d, lyr#=%d, 1stNd=%s\n", (nLayers-1)*DPI, maxW, nNodeG, nDummy, l, layerWidthInfo[index].nodeGroupsInLayer[0]->nodes[0]->name); // printf("Finally...\n------------------\n"); - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - //printf("%s, rank = %d, ranktype = %d\n", v->name, ND_rank(v), ND_ranktype(v)); + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + //printf("%s, rank = %d, ranktype = %d\n", v->name, ND_rank(v), ND_ranktype(v)); } } +#endif - - - -/***************************************************************** +/* applyPacking2: * The following is the packing heuristic for wide layout. - *****************************************************************/ - -void applyPacking2(graph_t *g) + */ +static void applyPacking2(graph_t * g) { - int i; - - sortedLayerIndex = (int *)malloc(sizeof(int)*agnnodes(g)); - if (sortedLayerIndex == NULL) - agerr(AGERR, "Memory allocation error in applyPacking function.\n"); - - for (i=0; iname, ND_rank(v)); - } - */ - + for (i = 0; i < 1; i++) { + /* printf("iteration = %d\n----------------------\n", i); + for (v = agfstnode(g); v; v = agnxtnode(g,v)) + { + printf("%s rank = %d\n", v->name, ND_rank(v)); + } + */ - computeLayerWidths(g); - sortLayers(g); - reduceMaxWidth2(g); - //printf("====================\n"); - } + + computeLayerWidths(g); + sortLayers(g); + reduceMaxWidth2(g); + //printf("====================\n"); + } } -/******************************************************************************************** -* NOCOLOV & HEALY'S NODE PROMOTION HEURISTIC -*********************************************************************************************/ +/* + * NOCOLOV & HEALY'S NODE PROMOTION HEURISTIC + */ /**************************************************************** * This data structure is needed for backing up node information * during node promotion ****************************************************************/ -typedef struct myNodeInfo_t -{ - int indegree; - int outdegree; - int rank; - Agnode_t *node; +typedef struct myNodeInfo_t { + int indegree; + int outdegree; + int rank; + Agnode_t *node; } myNodeInfo_t; myNodeInfo_t *myNodeInfo; - -//return the maximum level number assigned -int getMaxLevelNumber(graph_t *g) +/* getMaxLevelNumber: + * return the maximum level number assigned + */ +int getMaxLevelNumber(graph_t * g) { - int max; - Agnode_t *n; - - max = ND_rank(agfstnode(g)); - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - { - if (ND_rank(n) > max) - max = ND_rank(n); - } - - return max; + int max; + Agnode_t *n; + + max = ND_rank(agfstnode(g)); + + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + if (ND_rank(n) > max) + max = ND_rank(n); + } + + return max; } -/**************************************************************** +/* countDummyDiff: * return the difference in the count of dummy nodes before * and after promoting the node v - ****************************************************************/ - -static int -countDummyDiff(graph_t *g, Agnode_t *v, int max) + */ +static int countDummyDiff(graph_t * g, Agnode_t * v, int max) { - int dummydiff = 0; - Agedge_t *e; - Agnode_t *u; - - int maxR = 0; + int dummydiff = 0; + Agedge_t *e; + Agnode_t *u; + int maxR = 0; + int j; + for (j = 0; j < ND_in(v).size; j++) { + e = ND_in(v).list[j]; + u = e->tail; - int j; + if (myNodeInfo[ND_id(u)].rank == myNodeInfo[ND_id(v)].rank + 1) { + dummydiff += countDummyDiff(g, u, max); + } + } - //for (e = agfstin(g,v); e; e = agnxtin(g,e)) - for (j = 0; j < ND_in(v).size; j++) - { - e = ND_in(v).list[j]; - u = e->tail; + if (myNodeInfo[ND_id(v)].rank + 1 < max + || (ND_in(v).size == 0 && myNodeInfo[ND_id(v)].rank + 1 <= max)) + myNodeInfo[ND_id(v)].rank += 1; - if (myNodeInfo[ND_id(u)].rank == myNodeInfo[ND_id(v)].rank+1) - { - dummydiff += countDummyDiff(g,u,max); - } - } - - if (myNodeInfo[ND_id(v)].rank+1 < max || (ND_in(v).size == 0 && myNodeInfo[ND_id(v)].rank+1 <= max)) - myNodeInfo[ND_id(v)].rank += 1; + dummydiff = dummydiff - ND_in(v).size + ND_out(v).size; - dummydiff = dummydiff - ND_in(v).size + ND_out(v).size; - - return dummydiff; + return dummydiff; } -/**************************************************************** +/* applyPromotionHeuristic: * Node Promotion Heuristic * by Nikolov and Healy - ****************************************************************/ - -static void -applyPromotionHeuristic(graph_t *g) + */ +static void applyPromotionHeuristic(graph_t * g) { - graph_t graphBkup = *g; - Agnode_t * v; - int promotions; - - int max = getMaxLevelNumber(g); - int count = 0; - int nNodes = agnnodes(g); - int i, j; - - myNodeInfo = (myNodeInfo_t *) malloc(sizeof(myNodeInfo_t) * nNodes); - myNodeInfo_t *myNodeInfoBak = (myNodeInfo_t *) malloc(sizeof(myNodeInfo_t) * nNodes); - - for (v = agfstnode(g), i = 0; v; v = agnxtnode(g,v), i++) - { - myNodeInfo[i].indegree = ND_in(v).size; - myNodeInfo[i].outdegree = ND_out(v).size; - myNodeInfo[i].rank = ND_rank(v); - myNodeInfo[i].node = v; - ND_id(v) = i; - - myNodeInfoBak[i] = myNodeInfo[i]; - } - - do - { - promotions = 0; - - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - if (ND_in(v).size > 0) - { - if (countDummyDiff(g,v,max) <= 0) - { - promotions++; - - for (j = 0; j < nNodes; j++) - { - myNodeInfoBak[j] = myNodeInfo[j]; - } - - } - else - { - for (j = 0; j < nNodes; j++) - { - myNodeInfo[j] = myNodeInfoBak[j]; - } - } - } + graph_t graphBkup = *g; + Agnode_t *v; + int promotions; + + int max = getMaxLevelNumber(g); + int count = 0; + int nNodes = agnnodes(g); + int i, j; + + myNodeInfo = N_NEW(nNodes, myNodeInfo_t); + myNodeInfo_t *myNodeInfoBak = N_NEW(nNodes, myNodeInfo_t); + + for (v = agfstnode(g), i = 0; v; v = agnxtnode(g, v), i++) { + myNodeInfo[i].indegree = ND_in(v).size; + myNodeInfo[i].outdegree = ND_out(v).size; + myNodeInfo[i].rank = ND_rank(v); + myNodeInfo[i].node = v; + ND_id(v) = i; + + myNodeInfoBak[i] = myNodeInfo[i]; } - count++; - } while (count < max); - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - ND_rank(v) = myNodeInfo[ND_id(v)].rank; - } -} + do { + promotions = 0; + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + if (ND_in(v).size > 0) { + if (countDummyDiff(g, v, max) <= 0) { + promotions++; -/******************************************************************************************** -* LONGEST PATH ALGORITHM -*********************************************************************************************/ + for (j = 0; j < nNodes; j++) { + myNodeInfoBak[j] = myNodeInfo[j]; + } + + } else { + for (j = 0; j < nNodes; j++) { + myNodeInfo[j] = myNodeInfoBak[j]; + } + } + } + } + count++; + } while (count < max); + + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + ND_rank(v) = myNodeInfo[ND_id(v)].rank; + } +} -/******************************************************************************************** -* Return 1 if all the neighbors of n already ranked, else 0 -*********************************************************************************************/ -int -allNeighborsAreBelow (Agnode_t *n) +/* + * LONGEST PATH ALGORITHM + */ + +/* allNeighborsAreBelow: + * Return 1 if all the neighbors of n already ranked, else 0 + */ +static int allNeighborsAreBelow(Agnode_t * n) { Agedge_t *e; graph_t *g = n->graph; int i; //for (e = agfstout(g,n); e; e = agnxtout(g,e)) - for (i = 0; i < ND_out(n).size; i++) - { - e = ND_out(n).list[i]; - if (ED_edge_type(e) == VIRTUAL) - { - if (ED_to_orig(e) != NULL) - e = ED_to_orig(e); - else if (ND_node_type(e->head) == VIRTUAL) - continue; - } - - if(ND_pinned(e->head) != 2) //neighbor of n is not below - { - return 0; - } + for (i = 0; i < ND_out(n).size; i++) { + e = ND_out(n).list[i]; + if (ED_edge_type(e) == VIRTUAL) { + if (ED_to_orig(e) != NULL) + e = ED_to_orig(e); + else if (ND_node_type(e->head) == VIRTUAL) + continue; + } + + if (ND_pinned(e->head) != 2) //neighbor of n is not below + { + return 0; + } } return 1; } - -/**************************************************************** +/* reverseLevelNumbers: * In Nikolov and Healy ranking, bottom layer ranking is 0 and * top layer ranking is the maximum. * Graphviz does the opposite. * This function does the reversing from Nikolov to Graphviz. - ****************************************************************/ - -static void -reverseLevelNumbers(graph_t *g) + */ +static void reverseLevelNumbers(graph_t * g) { Agnode_t *n; int max; - + max = getMaxLevelNumber(g); //printf("max = %d\n", max); //return; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - { - ND_rank(n) = max - ND_rank(n); + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + ND_rank(n) = max - ND_rank(n); } } - -/**************************************************************** +/* doSameRank: * Maintain the same ranking constraint. * Can only be used with the Nikolov and Healy algorithm - ****************************************************************/ - -static void -doSameRank(graph_t *g) + */ +static void doSameRank(graph_t * g) { - int i; - for (i = 0; i < nNodeGroups; i++) - { - int j; + int i; + for (i = 0; i < nNodeGroups; i++) { + int j; - for (j = 0; j < nodeGroups[i].nNodes; j++) - { - 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 - { - int k; - int r = ND_rank(UF_find(nodeGroups[i].nodes[j])); - for (k = 0; k < nodeGroups[i].nNodes; k++) - { - ND_rank(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = r; + for (j = 0; j < nodeGroups[i].nNodes; j++) { + 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 + { + int k; + int r = ND_rank(UF_find(nodeGroups[i].nodes[j])); + for (k = 0; k < nodeGroups[i].nNodes; k++) { + ND_rank(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = r; + } + + break; + } } - - break; - } } - } - } - -/**************************************************************** +/* doMinRank: * Maintain the MIN ranking constraint. * Can only be used with the Nikolov and Healy algorithm - ****************************************************************/ - -void -doMinRank(graph_t *g) + */ +void doMinRank(graph_t * g) { - int i; - for (i = 0; i < nNodeGroups; i++) - { - int j; + int i; + for (i = 0; i < nNodeGroups; i++) { + int j; - for (j = 0; j < nodeGroups[i].nNodes; j++) - { - 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 - { - int k; - for (k = 0; k < nodeGroups[i].nNodes; k++) - { - ND_rank(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = 0; - if (ND_ranktype(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) != SOURCERANK) - ND_ranktype(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = MINRANK; + for (j = 0; j < nodeGroups[i].nNodes; j++) { + 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 + { + int k; + for (k = 0; k < nodeGroups[i].nNodes; k++) { + ND_rank(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = 0; + if (ND_ranktype + (nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) != + SOURCERANK) + ND_ranktype(nodeGroups[i]. + nodes[(j + + k) % nodeGroups[i].nNodes]) = + MINRANK; + } + + break; + } } - - break; - } } - } } - -/**************************************************************** +/* getMaxRank: * Return the maximum rank among all nodes. - ****************************************************************/ - -static int -getMaxRank(graph_t *g) + */ +static int getMaxRank(graph_t * g) { - int i; - node_t *v; - int maxR = ND_rank(agfstnode(g)); - for (v = agfstnode(g); v; v = agnxtnode(g,v)) - { - if (ND_rank(v) > maxR) - maxR = ND_rank(v); - } - - return maxR; -} + int i; + node_t *v; + int maxR = ND_rank(agfstnode(g)); + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + if (ND_rank(v) > maxR) + maxR = ND_rank(v); + } + return maxR; +} -/**************************************************************** +/* doMaxRank: * Maintain the MAX ranking constraint. * Can only be used with the Nikolov and Healy algorithm - ****************************************************************/ - -static void -doMaxRank(graph_t *g) + */ +static void doMaxRank(graph_t * g) { - int i; - for (i = 0; i < nNodeGroups; i++) - { - int j; - int maxR = getMaxRank(g); - - for (j = 0; j < nodeGroups[i].nNodes; j++) - { - 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 - { - int k; - for (k = 0; k < nodeGroups[i].nNodes; k++) - { - ND_rank(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = maxR; - if (ND_ranktype(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) != SINKRANK) - ND_ranktype(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = MAXRANK; + int i; + for (i = 0; i < nNodeGroups; i++) { + int j; + int maxR = getMaxRank(g); + + for (j = 0; j < nodeGroups[i].nNodes; j++) { + 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 + { + int k; + for (k = 0; k < nodeGroups[i].nNodes; k++) { + ND_rank(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = maxR; + if (ND_ranktype + (nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) != + SINKRANK) + ND_ranktype(nodeGroups[i]. + nodes[(j + + k) % nodeGroups[i].nNodes]) = + MAXRANK; + } + + break; + } } - - break; - } } - } } - -/**************************************************************** +/* doSourceRank: * Maintain the SOURCE ranking constraint. * Can only be used with the Nikolov and Healy algorithm - ****************************************************************/ - -static void -doSourceRank(graph_t *g) + */ +static void doSourceRank(graph_t * g) { - int i; - int flag = 0; - - for (i = 0; i < nNodeGroups; i++) - { - int j; + int i; + int flag = 0; + + for (i = 0; i < nNodeGroups; i++) { + int j; + + for (j = 0; j < nodeGroups[i].nNodes; j++) { + //once we find a SOURCERANK node in a group- make the rank of all the members of the group 0 + if (ND_ranktype(nodeGroups[i].nodes[j]) == SOURCERANK) { + int k; + for (k = 0; k < nodeGroups[i].nNodes; k++) { + ND_rank(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = 0; + ND_ranktype(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = + SOURCERANK; + } - for (j = 0; j < nodeGroups[i].nNodes; j++) - { - //once we find a SOURCERANK node in a group- make the rank of all the members of the group 0 - if ( ND_ranktype(nodeGroups[i].nodes[j]) == SOURCERANK) - { - int k; - for (k = 0; k < nodeGroups[i].nNodes; k++) - { - ND_rank(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = 0; - ND_ranktype(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = SOURCERANK; + flag = 1; + break; + } } - - flag = 1; - break; - } } - } - if (!flag) - return; + if (!flag) + return; - flag = 0; + flag = 0; - //The SourceRank group might be the only group having rank 0. Check if increment of ranking of other nodes is necessary at all. - for (i = 0; i < nNodeGroups; i++) - { - if (nodeGroups[i].nNodes > 0 && ND_ranktype(nodeGroups[i].nodes[0]) != SOURCERANK && ND_rank(nodeGroups[i].nodes[0]) == 0) - { - flag = 1; - break; - } - } - - - if (!flag) - return; - - //Now make all NON-SourceRank nodes' ranking nonzero (increment) - for (i = 0; i < nNodeGroups; i++) - { - if (nodeGroups[i].nNodes > 0 && ND_ranktype(nodeGroups[i].nodes[0]) != SOURCERANK) - { - int j; - - for (j = 0; j < nodeGroups[i].nNodes; j++) - { - ND_rank(nodeGroups[i].nodes[j])++; - } + //The SourceRank group might be the only group having rank 0. Check if increment of ranking of other nodes is necessary at all. + for (i = 0; i < nNodeGroups; i++) { + if (nodeGroups[i].nNodes > 0 + && ND_ranktype(nodeGroups[i].nodes[0]) != SOURCERANK + && ND_rank(nodeGroups[i].nodes[0]) == 0) { + flag = 1; + break; + } } - } -} + if (!flag) + return; -/**************************************************************** + //Now make all NON-SourceRank nodes' ranking nonzero (increment) + for (i = 0; i < nNodeGroups; i++) { + if (nodeGroups[i].nNodes > 0 + && ND_ranktype(nodeGroups[i].nodes[0]) != SOURCERANK) { + int j; + + for (j = 0; j < nodeGroups[i].nNodes; j++) { + ND_rank(nodeGroups[i].nodes[j])++; + } + } + } +} + +/* doSinkRank: * Maintain the SINK ranking constraint. * Can only be used with the Nikolov and Healy algorithm - ****************************************************************/ - -static void -doSinkRank(graph_t *g) + */ +static void doSinkRank(graph_t * g) { - int i, max; - int flag = 0; + int i, max; + int flag = 0; - max = getMaxRank(g); + max = getMaxRank(g); - //Check if any non-sink node has rank = max - for (i = 0; i < nNodeGroups; i++) - { - if (nodeGroups[i].nNodes > 0 && ND_ranktype(nodeGroups[i].nodes[0]) != SINKRANK && ND_rank(nodeGroups[i].nodes[0]) == max) - { - flag = 1; - break; + //Check if any non-sink node has rank = max + for (i = 0; i < nNodeGroups; i++) { + if (nodeGroups[i].nNodes > 0 + && ND_ranktype(nodeGroups[i].nodes[0]) != SINKRANK + && ND_rank(nodeGroups[i].nodes[0]) == max) { + flag = 1; + break; + } } - } - if (!flag) - return; + if (!flag) + return; - for (i = 0; i < nNodeGroups; i++) - { - int j; + for (i = 0; i < nNodeGroups; i++) { + int j; - for (j = 0; j < nodeGroups[i].nNodes; j++) - { - 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 - { - int k; - for (k = 0; k < nodeGroups[i].nNodes; k++) - { - ND_rank(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = max+1; - ND_ranktype(nodeGroups[i].nodes[(j+k)%nodeGroups[i].nNodes]) = SINKRANK; + for (j = 0; j < nodeGroups[i].nNodes; j++) { + 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 + { + int k; + for (k = 0; k < nodeGroups[i].nNodes; k++) { + ND_rank(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = + max + 1; + ND_ranktype(nodeGroups[i]. + nodes[(j + k) % nodeGroups[i].nNodes]) = + SINKRANK; + } + + break; + } } - - break; - } } - } } - -/**************************************************************** - * rank2: Initial codes for ranking (Nikolov-Healy). +/* rank2: + * Initial codes for ranking (Nikolov-Healy). * It's no longer used. - ****************************************************************/ - -void -rank2(graph_t * g) + */ +void rank2(graph_t * g) { int currentLayer = 1; int nNodes = agnnodes(g); int nEdges = agnedges(g); int nPinnedNodes = 0, nSelected = 0; Agnode_t *n, **UArray; - int USize = 0; + int USize = 0; int i, prevSize = 0; - UArray = (Agnode_t **) malloc(sizeof(Agnode_t *) * nEdges * 2); - if (UArray == NULL) - agerr(AGERR, "Memory allocation error for the graph \"%s\"\n", g->name); + UArray = N_NEW(nEdges * 2, Agnode_t *); - //make all pinning values 0 - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - { - ND_pinned(n) = 0; + /* make all pinning values 0 */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + ND_pinned(n) = 0; } - while (nPinnedNodes != nNodes) - { - for (nSelected = 0, n = agfstnode(g); n; n = agnxtnode(g,n)) - { - if (ND_pinned(n) == 0) - { - if (allNeighborsAreBelow(n)) - { - ND_pinned(n) = 1; - - UArray[USize] = n; - USize++; - - ND_rank(n) = currentLayer; - nPinnedNodes++; - nSelected++; - } - } - } - - if (nSelected == 0) //no node has been selected - { - currentLayer++; - for (i = prevSize; i < USize; i++) - { - ND_pinned(UArray[i]) = 2; //pinning value of 2 indicates this node is below the current node under consideration - } - - prevSize = USize; - } + while (nPinnedNodes != nNodes) { + for (nSelected = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) { + if (ND_pinned(n) == 0) { + if (allNeighborsAreBelow(n)) { + ND_pinned(n) = 1; + + UArray[USize] = n; + USize++; + + ND_rank(n) = currentLayer; + nPinnedNodes++; + nSelected++; + } + } + } + + if (nSelected == 0) //no node has been selected + { + currentLayer++; + for (i = prevSize; i < USize; i++) { + ND_pinned(UArray[i]) = 2; //pinning value of 2 indicates this node is below the current node under consideration + } + + prevSize = USize; + } } //Apply Nikolov's node promotion heuristic @@ -1664,11 +1572,11 @@ rank2(graph_t * g) //this is for the sake of graphViz layer numbering scheme reverseLevelNumbers(g); - computeNodeGroups(g); //groups of UF DS nodes + computeNodeGroups(g); //groups of UF DS nodes //modify the ranking to respect the same ranking constraint doSameRank(g); - + //satisfy min ranking constraints doMinRank(g); doMaxRank(g); @@ -1678,223 +1586,199 @@ rank2(graph_t * g) doSinkRank(g); //Apply the FFDH algorithm to achieve better aspect ratio; - applyPacking(g,1); //achieve an aspect ratio of 1 + applyPacking(g, 1); //achieve an aspect ratio of 1 } - +#endif /**************************************************************** * Initialize all the edge types to NORMAL ****************************************************************/ - -void initEdgeTypes(g) +void initEdgeTypes(graph_t * g) { edge_t *e; node_t *n; - int cnt = 0; int lc; - - for (n = agfstnode(g); n; n = agnxtnode(g, n)) - for (lc = 0; lc < ND_in(n).size; lc++) - { - e = ND_in(n).list[lc]; - ED_edge_type(e) = NORMAL; - } -} + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + for (lc = 0; lc < ND_in(n).size; lc++) { + e = ND_in(n).list[lc]; + ED_edge_type(e) = NORMAL; + } + } +} -/**************************************************************** +/* computeCombiAR: * Compute and return combinatorial aspect ratio * = * Width of the widest layer / Height * (in ranking phase) - ****************************************************************/ - -static double -computeCombiAR(graph_t *g) + */ +static double computeCombiAR(graph_t * g) { - int i, maxLayerIndex; - double maxW = 0; - double maxH; - double ratio; - - computeLayerWidths(g); - maxH = (nLayers - 1) * GD_ranksep(g); - - for (i = 0; i < nLayers; i++) - { - if (maxW < layerWidthInfo[i].width + layerWidthInfo[i].nDummyNodes*GD_nodesep(g)) - { - maxW = layerWidthInfo[i].width + layerWidthInfo[i].nDummyNodes*GD_nodesep(g); - maxLayerIndex = i; + int i, maxLayerIndex; + double maxW = 0; + double maxH; + double ratio; + + computeLayerWidths(g); + maxH = (nLayers - 1) * GD_ranksep(g); + + for (i = 0; i < nLayers; i++) { + if (maxW < + layerWidthInfo[i].width + + layerWidthInfo[i].nDummyNodes * GD_nodesep(g)) { + maxW = + layerWidthInfo[i].width + + layerWidthInfo[i].nDummyNodes * GD_nodesep(g); + maxLayerIndex = i; + } + maxH += layerWidthInfo[i].height; } - maxH += layerWidthInfo[i].height; - } - ratio = maxW/maxH; + ratio = maxW / maxH; - return ratio; + return ratio; } - -node_t *sink = NULL; - - -/**************************************************************** +#ifdef UNUSED +/* applyExpansion: * Heuristic for expanding very narrow graphs by edge reversal. * Needs improvement. - ****************************************************************/ - -void -applyExpansion(graph_t *g) + */ +void applyExpansion(graph_t * g) { - int i, k; - edge_t *e; - - computeLayerWidths(g); - - for (i = 0; i < nLayers; i++) - { - if (layerWidthInfo[i].layerNumber == nLayers/2) - { - k = i; - break; - } - } - - //now reverse the edges, from the k-th layer nodes to their parents - for (i = 0; i < layerWidthInfo[k].nNodeGroupsInLayer; i++) - { - int p; - nodeGroup_t *ng = layerWidthInfo[k].nodeGroupsInLayer[i]; - for (p = 0; p < ng->nNodes; p++) - { - node_t *nd = ng->nodes[p]; - - while (e = ND_in(nd).list[0]) - { - printf("Reversing edge: %s->%s\n", e->tail->name, e->head->name); - reverse_edge(e); - } - - int j, l; - node_t *v3; - edge_t *e3; - for (v3 = agfstnode(g); v3; v3 = agnxtnode(g,v3)) - { - for (e3 = agfstout(g,v3); e3; e3 = agnxtout(g,e3)) - { - if (ND_rank(e3->head) > k && ND_rank(e3->tail) < k) - { - printf("Reversing long edge: %s->%s\n", e3->tail->name, e3->head->name); - reverse_edge(e3); - } + node_t *sink = NULL; + int i, k; + edge_t *e; + computeLayerWidths(g); + + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[i].layerNumber == nLayers / 2) { + k = i; + break; } - } + } - /*for (l = 0; l < nLayers; l++) - { - if (layerWidthInfo[l].layerNumber <= k) - continue; - - for (j = 0; j < layerWidthInfo[l].nNodeGroupsInLayer; j++) - { - int q; - nodeGroup_t *ng2 = layerWidthInfo[l].nodeGroupsInLayer[j]; - for (q = 0; q < ng2->nNodes; q++) - { - node_t *nd2 = ng2->nodes[q]; - edge_t *e2; - int s = 0; - while (e2 = ND_in(nd2).list[s]) - { - if (ND_rank(e2->tail) < k) - { - printf("Reversing edge: %s->%s\n", e2->tail->name, e2->head->name); - getchar(); - //reverse_edge(e2); - } - else s++; + //now reverse the edges, from the k-th layer nodes to their parents + for (i = 0; i < layerWidthInfo[k].nNodeGroupsInLayer; i++) { + int p; + nodeGroup_t *ng = layerWidthInfo[k].nodeGroupsInLayer[i]; + for (p = 0; p < ng->nNodes; p++) { + node_t *nd = ng->nodes[p]; + + while (e = ND_in(nd).list[0]) { + printf("Reversing edge: %s->%s\n", e->tail->name, + e->head->name); + reverse_edge(e); } - } - } - }*/ - - if (sink == NULL) - { - int brFlag = 1; - for (l = 0; l < nLayers && brFlag; l++) - { - for (j = 0; j < layerWidthInfo[l].nNodeGroupsInLayer && brFlag; j++) - { - int q; - nodeGroup_t *ng2 = layerWidthInfo[l].nodeGroupsInLayer[j]; - for (q = 0; q < ng2->nNodes && brFlag; q++) - { - node_t *nd2 = ng2->nodes[q]; - if (ND_in(nd2).size == 0) - { - sink = nd2; - brFlag = 0; + + int j, l; + node_t *v3; + edge_t *e3; + for (v3 = agfstnode(g); v3; v3 = agnxtnode(g, v3)) { + for (e3 = agfstout(g, v3); e3; e3 = agnxtout(g, e3)) { + if (ND_rank(e3->head) > k && ND_rank(e3->tail) < k) { + printf("Reversing long edge: %s->%s\n", + e3->tail->name, e3->head->name); + reverse_edge(e3); + } + + } } - } - } - } - } + /*for (l = 0; l < nLayers; l++) + { + if (layerWidthInfo[l].layerNumber <= k) + continue; + + for (j = 0; j < layerWidthInfo[l].nNodeGroupsInLayer; j++) + { + int q; + nodeGroup_t *ng2 = layerWidthInfo[l].nodeGroupsInLayer[j]; + for (q = 0; q < ng2->nNodes; q++) + { + node_t *nd2 = ng2->nodes[q]; + edge_t *e2; + int s = 0; + while (e2 = ND_in(nd2).list[s]) + { + if (ND_rank(e2->tail) < k) + { + printf("Reversing edge: %s->%s\n", e2->tail->name, e2->head->name); + getchar(); + //reverse_edge(e2); + } + else s++; + } + } + } + } */ + + if (sink == NULL) { + int brFlag = 1; + for (l = 0; l < nLayers && brFlag; l++) { + for (j = 0; + j < layerWidthInfo[l].nNodeGroupsInLayer + && brFlag; j++) { + int q; + nodeGroup_t *ng2 = + layerWidthInfo[l].nodeGroupsInLayer[j]; + for (q = 0; q < ng2->nNodes && brFlag; q++) { + node_t *nd2 = ng2->nodes[q]; + if (ND_in(nd2).size == 0) { + sink = nd2; + brFlag = 0; + } + } + } + } + + } - virtual_edge(nd, /*sink*/ layerWidthInfo[0].nodeGroupsInLayer[0]->nodes[0], NULL); + virtual_edge(nd, /*sink */ + layerWidthInfo[0].nodeGroupsInLayer[0]->nodes[0], + NULL); + } } - } - //collapse_sets(g); + //collapse_sets(g); } +#endif - -/**************************************************************** +/* zapLayers: * After applying the expansion heuristic, some layers are * found to be empty. * This function removes the empty layers. - ****************************************************************/ - -static void -zapLayers(graph_t *g) + */ +static void zapLayers(graph_t * g) { - int i, j; - int start = 0; - int count = 0; - - //the layers are sorted by the layer number. - //now zap the empty layers - - for (i = 0; i < nLayers; i++) - { - if (layerWidthInfo[i].nNodeGroupsInLayer == 0) - { - if (count == 0) - start = layerWidthInfo[i].layerNumber; - count ++; - } - else if (count && layerWidthInfo[i].layerNumber > start) - { - for (j = 0; j < layerWidthInfo[i].nNodeGroupsInLayer; j++) - { - int q; - nodeGroup_t *ng = layerWidthInfo[i].nodeGroupsInLayer[j]; - for (q = 0; q < ng->nNodes; q++) - { - node_t *nd = ng->nodes[q]; - ND_rank(nd) -= count; - } + int i, j; + int start = 0; + int count = 0; + + /* the layers are sorted by the layer number. now zap the empty layers */ + + for (i = 0; i < nLayers; i++) { + if (layerWidthInfo[i].nNodeGroupsInLayer == 0) { + if (count == 0) + start = layerWidthInfo[i].layerNumber; + count++; + } else if (count && layerWidthInfo[i].layerNumber > start) { + for (j = 0; j < layerWidthInfo[i].nNodeGroupsInLayer; j++) { + int q; + nodeGroup_t *ng = layerWidthInfo[i].nodeGroupsInLayer[j]; + for (q = 0; q < ng->nNodes; q++) { + node_t *nd = ng->nodes[q]; + ND_rank(nd) -= count; + } + } } } - } - } - -/**************************************************************** - * rank3: ranking function for dealing with wide/narrow graphs, +/* rank3: + * ranking function for dealing with wide/narrow graphs, * or graphs with varying node widths and heights. * This function iteratively calls dot's rank1() function and * applies packing (by calling the applyPacking2 function. @@ -1903,135 +1787,111 @@ zapLayers(graph_t *g) * Initially the iterations argument is -1, for which rank3 * callse applyPacking2 function until the combinatorial aspect * ratio is <= the desired aspect ratio. - ****************************************************************/ - -void -rank3(graph_t * g, int iterations) + */ +void rank3(graph_t * g, aspect_t * asp) { - int currentLayer = 1; - int nNodes = agnnodes(g); - int nEdges = agnedges(g); - int nPinnedNodes = 0, nSelected = 0; - Agnode_t *n, **UArray; - int USize = 0; - int i, prevSize = 0; + Agnode_t *n; + int i; + int iterations = asp->nextIter; + computeNodeGroups(g); /* groups of UF DS nodes */ - computeNodeGroups(g); //groups of UF DS nodes + for (i = 0; i < iterations || iterations == -1; i++) { + /* initialize all ranks to be 0 */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + ND_rank(n) = 0; + } + /* need to compute ranking first--- by Network flow */ - edge_t *e; - int cnt = 0; - int lc; - - - for (i=0; icombiAR = computeCombiAR(g); + if (Verbose) + fprintf(stderr, "combiAR = %lf\n", asp->combiAR); - break; - } - //Apply the FFDH algorithm to reduce the aspect ratio; - applyPacking2(g); - } + /* Uncomment the following codes, for working with narrow graphs */ +#ifdef UNUSED + if (combiAR < 0.8 * targetAR) { + char str[20]; + printf("Apply expansion? (y/n):"); + scanf("%s", str); + if (strcmp(str, "y") == 0) + applyExpansion(g); + break; + } else +#endif + if (iterations == -1 && asp->combiAR <= asp->targetAR) { + asp->prevIterations = asp->curIterations; + asp->curIterations = i; - //do network flow once again... incorporating the added edges + break; + } + /* Apply the FFDH algorithm to reduce the aspect ratio; */ + applyPacking2(g); + } + + /* do network flow once again... incorporating the added edges */ rank1(g); computeLayerWidths(g); zapLayers(g); - combiAR = computeCombiAR(g); + asp->combiAR = computeCombiAR(g); } -/**************************************************************** +#ifdef UNUSED +/* NikolovHealy: * Nikolov-Healy approach to ranking. * First, use longest path algorithm. * Then use node promotion heuristic. * This function is called by rank4 function. - ****************************************************************/ - -void NikolovHealy(graph_t *g) + */ +static void NikolovHealy(graph_t * g) { int currentLayer = 1; int nNodes = agnnodes(g); int nEdges = agnedges(g); int nPinnedNodes = 0, nSelected = 0; Agnode_t *n, **UArray; - int USize = 0; + int USize = 0; int i, prevSize = 0; /************************************************************************ * longest path algorithm ************************************************************************/ - UArray = (Agnode_t **) malloc(sizeof(Agnode_t *) * nEdges * 2); - if (UArray == NULL) - agerr(AGERR, "Memory allocation error for the graph \"%s\"\n", g->name); - - //make all pinning values 0 - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - { - ND_pinned(n) = 0; + UArray = N_NEW(nEdges * 2, Agnode_t *); + + /* make all pinning values 0 */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + ND_pinned(n) = 0; } - while (nPinnedNodes != nNodes) - { - for (nSelected = 0, n = agfstnode(g); n; n = agnxtnode(g,n)) - { - if (ND_pinned(n) == 0) - { - if (allNeighborsAreBelow(n)) - { - ND_pinned(n) = 1; - - UArray[USize] = n; - USize++; - - ND_rank(n) = currentLayer; - nPinnedNodes++; - nSelected++; - } - } - } - - if (nSelected == 0) //no node has been selected - { - currentLayer++; - for (i = prevSize; i < USize; i++) - { - ND_pinned(UArray[i]) = 2; //pinning value of 2 indicates this node is below the current node under consideration - } - - prevSize = USize; - } + while (nPinnedNodes != nNodes) { + for (nSelected = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) { + if (ND_pinned(n) == 0) { + if (allNeighborsAreBelow(n)) { + ND_pinned(n) = 1; + + UArray[USize] = n; + USize++; + + ND_rank(n) = currentLayer; + nPinnedNodes++; + nSelected++; + } + } + } + + if (nSelected == 0) //no node has been selected + { + currentLayer++; + for (i = prevSize; i < USize; i++) { + ND_pinned(UArray[i]) = 2; //pinning value of 2 indicates this node is below the current node under consideration + } + + prevSize = USize; + } } @@ -2047,82 +1907,71 @@ void NikolovHealy(graph_t *g) } -/**************************************************************** + +/* rank4: * This function is calls the NikolovHealy function * for ranking in the Nikolov-Healy approach. - ****************************************************************/ - -void -rank4(graph_t * g, int iterations) + */ +void rank4(graph_t * g, int iterations) { int currentLayer = 1; int nNodes = agnnodes(g); int nEdges = agnedges(g); int nPinnedNodes = 0, nSelected = 0; Agnode_t *n, **UArray; - int USize = 0; + int USize = 0; int i, prevSize = 0; - + int it; printf("# of interations of packing: "); scanf("%d", &it); printf("it=%d\n", it); - - computeNodeGroups(g); //groups of UF DS nodes - for (i=0; i static void @@ -96,27 +97,6 @@ dot_cleanup_node(node_t * n) memset(&(n->u), 0, sizeof(Agnodeinfo_t)); } -static void -dot_free_splines(edge_t * e) -{ - int i; - if (ED_spl(e)) { - for (i = 0; i < ED_spl(e)->size; i++) - free(ED_spl(e)->list[i].list); - free(ED_spl(e)->list); - free(ED_spl(e)); - } - ED_spl(e) = NULL; -} - -static void -dot_cleanup_edge(edge_t * e) -{ - dot_free_splines(e); - free_label(ED_label(e)); - memset(&(e->u), 0, sizeof(Agedgeinfo_t)); -} - static void free_virtual_edge_list(node_t * n) { edge_t *e; @@ -221,94 +201,63 @@ dumpRanks (graph_t * g) } #endif +#define MIN_AR 1.0 +#define MAX_AR 20.0 +#define DEF_PASSES 5 -/*********************************************************************** - * The codes in the dot_layout function has been changed. - * It gets an estimation of next number of iterations for ranking - * from the positioning step. - * User can change the number of iterations or stop the iterations. - ***********************************************************************/ - -/**************************** EXTERNAL VARIABLES ***********************/ -extern double targetAR; -extern double currentAR; -extern double combiAR; -extern int prevIterations; -extern int curIterations; -/**************************** EXTERNAL VARIABLES ***********************/ - -int packiter = 0; - -void dot_layout(Agraph_t * g) +static aspect_t* +setAspect (Agraph_t * g, aspect_t* adata) { - int rvi, targetITR, iter, packiter = 0; - double rv, start, finish, totalCLK; - setEdgeType (g, ET_SPLINE); - attrsym_t *a; + double rv; char *p; + int r, passes = DEF_PASSES; + p = agget (g, "aspect"); -#define MIN_AR 1.0 -#define MAX_AR 20.0 -#define MIN_ITR 1 -#define DEF_ITR 5 -#define MAX_ITR 200 - - targetAR = MIN_AR; /* default target aspect-ratio and iterations */ - targetITR = MIN_ITR; /* if targetAR isn't given, the do just the minimum*/ - if ((a = agfindattr(g, "aspect"))) { - p = agxget(g, a->index); - if (p[0]) { - if ((rv = atof(p)) > MIN_AR) targetAR = rv; - if (targetAR > MAX_AR) targetAR = MAX_AR; - targetITR = DEF_ITR; /* if targetAR *is* given, the init default */ - if ((p = strchr(p, ','))) { - p++; - if (p[0]) { - if ((rvi = atoi(p)) > MIN_ITR) targetITR = rvi; - if (targetITR > MAX_ITR) targetITR = MAX_ITR; - } - } - } + if (!p || ((r = sscanf (p, "%lf,%d", &rv, &passes)) <= 0)) { + adata->nextIter = 0; + adata->badGraph = 0; + return NULL; } + + if (rv < MIN_AR) rv = MIN_AR; + else if (rv > MAX_AR) rv = MAX_AR; + adata->targetAR = rv; + adata->nextIter = -1; + adata->nPasses = passes; + adata->badGraph = 0; if (Verbose) - fprintf(stderr, "Target AR = %g\n", targetAR); - - dot_init_node_edge(g); - - iter = 0; - while (iter < targetITR) { - iter++; + fprintf(stderr, "Target AR = %g\n", adata->targetAR); - if (Verbose) - fprintf(stderr, "Iteration = %d (of %d max) Current AR = %g\n", - iter, targetITR, currentAR); + return adata; +} - start = clock(); - dot_rank(g); - packiter += curIterations; +void dot_layout(Agraph_t * g) +{ + aspect_t aspect; + aspect_t* asp; - dot_mincross(g); - /* dumpRanks (g); */ + setEdgeType (g, ET_SPLINE); + asp = setAspect (g, &aspect); - dot_position(g); + dot_init_node_edge(g); - finish = clock(); - totalCLK += finish - start; - } + do { + dot_rank(g, asp); + if (aspect.badGraph) { + agerr(AGWARN, "dot does not support the aspect attribute for disconnected graphs or graphs with clusters\n"); + asp = NULL; + aspect.nextIter = 0; + } + dot_mincross(g, (asp != NULL)); + dot_position(g, asp); + aspect.nPasses--; + } while (aspect.nextIter && aspect.nPasses); dot_sameports(g); - dot_splines(g); - if (mapbool(agget(g, "compound"))) dot_compoundEdges(g); - dotneato_postprocess(g); - - if (Verbose) { - fprintf(stderr, "Packing iterations=%d\n# of Passes=%d\n", packiter, iter); - fprintf(stderr, "Total time = %0.3lf sec\n\n", totalCLK/CLOCKS_PER_SEC); - } } diff --git a/lib/dotgen/dotprocs.h b/lib/dotgen/dotprocs.h index ba313a0e3..c3f4aee17 100644 --- a/lib/dotgen/dotprocs.h +++ b/lib/dotgen/dotprocs.h @@ -25,6 +25,8 @@ _BEGIN_EXTERNS_ /* public data */ extern "C" { #endif +#include "aspect.h" + extern void acyclic(Agraph_t *); extern void allocate_ranks(Agraph_t *); extern void build_ranks(Agraph_t *, int); @@ -61,6 +63,7 @@ extern "C" { extern Agedge_t *new_virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *); extern int nonconstraint_edge(Agedge_t *); extern void other_edge(Agedge_t *); + extern void rank1(graph_t * g); extern int portcmp(port p0, port p1); extern int ports_eq(edge_t *, edge_t *); extern void rec_reset_vlists(Agraph_t *); @@ -79,9 +82,9 @@ extern "C" { #endif extern void dot_nodesize(Agnode_t *, boolean); extern void dot_concentrate(Agraph_t *); - extern void dot_mincross(Agraph_t *); - extern void dot_position(Agraph_t *); - extern void dot_rank(Agraph_t *); + extern void dot_mincross(Agraph_t *, int); + extern void dot_position(Agraph_t *, aspect_t*); + extern void dot_rank(Agraph_t *, aspect_t*); extern void dot_sameports(Agraph_t *); extern void dot_splines(Agraph_t *); #undef extern diff --git a/lib/dotgen/dotsplines.c b/lib/dotgen/dotsplines.c index 7a6409f2d..361e1e95c 100644 --- a/lib/dotgen/dotsplines.c +++ b/lib/dotgen/dotsplines.c @@ -801,9 +801,9 @@ make_flat_adj_edges(path* P, edge_t** edges, int ind, int cnt, edge_t* e0, setEdgeType (auxg, et); dot_init_node_edge(auxg); - dot_rank(auxg); - dot_mincross(auxg); - dot_position(auxg); + dot_rank(auxg, 0); + dot_mincross(auxg, 0); + dot_position(auxg, 0); /* reposition */ midx = (ND_coord(tn).x - ND_rw(tn) + ND_coord(hn).x + ND_lw(hn))/2; diff --git a/lib/dotgen/mincross.c b/lib/dotgen/mincross.c index c174472c7..8d6186f76 100644 --- a/lib/dotgen/mincross.c +++ b/lib/dotgen/mincross.c @@ -40,8 +40,8 @@ static void init_mincross(graph_t * g); static void merge2(graph_t * g); static void init_mccomp(graph_t * g, int c); static void cleanup2(graph_t * g, int nc); -static int mincross_clust(graph_t * par, graph_t * g); -static int mincross(graph_t * g, int startpass, int endpass); +static int mincross_clust(graph_t * par, graph_t * g, int); +static int mincross(graph_t * g, int startpass, int endpass, int); static void init_mincross(graph_t * g); static void mincross_step(graph_t * g, int pass); static void mincross_options(graph_t * g); @@ -72,7 +72,7 @@ static boolean ReMincross; * Note that nodes are not placed into GD_rank(g) until mincross() * is called. */ -void dot_mincross(graph_t * g) +void dot_mincross(graph_t * g, int doBalance) { int c, nc; char *s; @@ -81,14 +81,14 @@ void dot_mincross(graph_t * g) for (nc = c = 0; c < GD_comp(g).size; c++) { init_mccomp(g, c); - nc += mincross(g, 0, 2); + nc += mincross(g, 0, 2, doBalance); } merge2(g); /* run mincross on contents of each cluster */ for (c = 1; c <= GD_n_cluster(g); c++) { - nc += mincross_clust(g, GD_clust(g)[c]); + nc += mincross_clust(g, GD_clust(g)[c], doBalance); #ifdef DEBUG check_vlists(GD_clust(g)[c]); check_order(); @@ -99,7 +99,7 @@ void dot_mincross(graph_t * g) && (!(s = agget(g, "remincross")) || (mapbool(s)))) { mark_lowclusters(g); ReMincross = TRUE; - nc = mincross(g, 2, 2); + nc = mincross(g, 2, 2, doBalance); #ifdef DEBUG for (c = 1; c <= GD_n_cluster(g); c++) check_vlists(GD_clust(g)[c]); @@ -224,7 +224,7 @@ static void ordered_edges(graph_t * g) } } -static int mincross_clust(graph_t * par, graph_t * g) +static int mincross_clust(graph_t * par, graph_t * g, int doBalance) { int c, nc; @@ -232,10 +232,10 @@ static int mincross_clust(graph_t * par, graph_t * g) ordered_edges(g); flat_breakcycles(g); flat_reorder(g); - nc = mincross(g, 2, 2); + nc = mincross(g, 2, 2, doBalance); for (c = 1; c <= GD_n_cluster(g); c++) - nc += mincross_clust(g, GD_clust(g)[c]); + nc += mincross_clust(g, GD_clust(g)[c], doBalance); save_vlist(g); return nc; @@ -331,167 +331,144 @@ static void exchange(node_t * v, node_t * w) GD_rank(Root)[r].v[vi] = w; } - -void -balanceNodes(graph_t *g, int r, node_t *v, node_t* w) +static void balanceNodes(graph_t * g, int r, node_t * v, node_t * w) { - node_t *s; //separator node - int sepIndex; - int nullType; //type of null nodes - int cntDummy = 0, cntOri = 0; - int k = 0, m = 0, k1 = 0, m1 = 0, i = 0; - - //printf("Balancing nodes ... \n"); - //printf("r = %d\n", r); - - //we only consider v and w of different types - if (ND_node_type(v) == ND_node_type(w)) - return; - - //count the number of dummy and original nodes - for (i = 0; i < GD_rank(g)[r].n; i++) - { - if (ND_node_type(GD_rank(g)[r].v[i]) == NORMAL ) - cntOri++; - else - cntDummy++; - } - - if (cntOri < cntDummy) - { - if (ND_node_type(v) == NORMAL) - s = v; - else s = w; - } - else - { - if (ND_node_type(v) == NORMAL) - s = w; - else s = v; - } - - //get the separator node index - for (i = 0; i < GD_rank(g)[r].n; i++) - { - if (GD_rank(g)[r].v[i] == s) - sepIndex = i; - } - - nullType = (ND_node_type(s) == NORMAL) ? VIRTUAL : NORMAL; - - //count the number of null nodes to the left and right of the separator node - for (i = sepIndex-1; i >= 0; i--) - { - if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) - k++; - else break; - } - - for (i = sepIndex+1; i < GD_rank(g)[r].n; i++) - { - if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) - m++; - else break; - - } - - //now exchange v,w and calculate the same counts - - exchange(v, w); - - //get the separator node index - for (i = 0; i < GD_rank(g)[r].n; i++) - { - if (GD_rank(g)[r].v[i] == s) - sepIndex = i; - } - - //count the number of null nodes to the left and right of the separator node - for (i = sepIndex-1; i >= 0; i--) - { - if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) - k1++; - else break; - } - - for (i = sepIndex+1; i < GD_rank(g)[r].n; i++) - { - if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) - m1++; - else break; - } - - if (abs(k1-m1) > abs(k-m)) - { - //printf("exchanging to revert to original ordering...\n"); - exchange(v,w); //revert to the original ordering - } - - //printf("v=%s, w=%s, k=%d, m=%d, k1=%d, m1=%d\n", v->name, w->name, k, m, k1, m1); -} + node_t *s; /* separator node */ + int sepIndex; + int nullType; /* type of null nodes */ + int cntDummy = 0, cntOri = 0; + int k = 0, m = 0, k1 = 0, m1 = 0, i = 0; + + /* we only consider v and w of different types */ + if (ND_node_type(v) == ND_node_type(w)) + return; + /* count the number of dummy and original nodes */ + for (i = 0; i < GD_rank(g)[r].n; i++) { + if (ND_node_type(GD_rank(g)[r].v[i]) == NORMAL) + cntOri++; + else + cntDummy++; + } -static int -balance(graph_t * g) -{ - int i, c0, c1, rv; - node_t *v, *w; - int r; + if (cntOri < cntDummy) { + if (ND_node_type(v) == NORMAL) + s = v; + else + s = w; + } else { + if (ND_node_type(v) == NORMAL) + s = w; + else + s = v; + } - rv = 0; + /* get the separator node index */ + for (i = 0; i < GD_rank(g)[r].n; i++) { + if (GD_rank(g)[r].v[i] == s) + sepIndex = i; + } - //printf("maxr = %d, minr = %d\n", GD_maxrank(g), GD_minrank(g)); + nullType = (ND_node_type(s) == NORMAL) ? VIRTUAL : NORMAL; - for (r = GD_maxrank(g); r >= GD_minrank(g); r--) - { + /* count the number of null nodes to the left and + * right of the separator node + */ + for (i = sepIndex - 1; i >= 0; i--) { + if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) + k++; + else + break; + } - GD_rank(g)[r].candidate = FALSE; - for (i = 0; i < GD_rank(g)[r].n - 1; i++) - //for (i = GD_rank(g)[r].n-2; i >= 0; i--) - { - v = GD_rank(g)[r].v[i]; - w = GD_rank(g)[r].v[i + 1]; - assert(ND_order(v) < ND_order(w)); - if (left2right(g, v, w)) - continue; - c0 = c1 = 0; - if (r > 0) { - c0 += in_cross(v, w); - c1 += in_cross(w, v); - } + for (i = sepIndex + 1; i < GD_rank(g)[r].n; i++) { + if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) + m++; + else + break; + } - //printf("before.... c0 = %d, c1 = %d\n", c0, c1); + /* now exchange v,w and calculate the same counts */ - if (GD_rank(g)[r + 1].n > 0) { - c0 += out_cross(v, w); - c1 += out_cross(w, v); - } + exchange(v, w); - //printf("after.... c0 = %d, c1 = %d\n", c0, c1); + /* get the separator node index */ + for (i = 0; i < GD_rank(g)[r].n; i++) { + if (GD_rank(g)[r].v[i] == s) + sepIndex = i; + } - //printf("r = %d, c0 = %d, c1 = %d\n",r, c0, c1); + /* count the number of null nodes to the left and + * right of the separator node + */ + for (i = sepIndex - 1; i >= 0; i--) { + if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) + k1++; + else + break; + } - /*if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { - exchange(v, w); - rv += (c0 - c1); - GD_rank(Root)[r].valid = FALSE; - GD_rank(g)[r].candidate = TRUE; + for (i = sepIndex + 1; i < GD_rank(g)[r].n; i++) { + if (ND_node_type(GD_rank(g)[r].v[i]) == nullType) + m1++; + else + break; + } - if (r > GD_minrank(g)) { - GD_rank(Root)[r - 1].valid = FALSE; - GD_rank(g)[r - 1].candidate = TRUE; + if (abs(k1 - m1) > abs(k - m)) { + exchange(v, w); //revert to the original ordering + } +} + +static int balance(graph_t * g) +{ + int i, c0, c1, rv; + node_t *v, *w; + int r; + + rv = 0; + + for (r = GD_maxrank(g); r >= GD_minrank(g); r--) { + + GD_rank(g)[r].candidate = FALSE; + for (i = 0; i < GD_rank(g)[r].n - 1; i++) { + v = GD_rank(g)[r].v[i]; + w = GD_rank(g)[r].v[i + 1]; + assert(ND_order(v) < ND_order(w)); + if (left2right(g, v, w)) + continue; + c0 = c1 = 0; + if (r > 0) { + c0 += in_cross(v, w); + c1 += in_cross(w, v); } - if (r < GD_maxrank(g)) { - GD_rank(Root)[r + 1].valid = FALSE; - GD_rank(g)[r + 1].candidate = TRUE; + + if (GD_rank(g)[r + 1].n > 0) { + c0 += out_cross(v, w); + c1 += out_cross(w, v); + } +#if 0 + if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { + exchange(v, w); + rv += (c0 - c1); + GD_rank(Root)[r].valid = FALSE; + GD_rank(g)[r].candidate = TRUE; + + if (r > GD_minrank(g)) { + GD_rank(Root)[r - 1].valid = FALSE; + GD_rank(g)[r - 1].candidate = TRUE; + } + if (r < GD_maxrank(g)) { + GD_rank(Root)[r + 1].valid = FALSE; + GD_rank(g)[r + 1].candidate = TRUE; + } + } +#endif + + if (c1 <= c0) { + balanceNodes(g, r, v, w); } - }*/ - - if (c1 <= c0) - { - balanceNodes(g, r, v, w); } - } } return rv; } @@ -562,7 +539,7 @@ static void transpose(graph_t * g, int reverse) } while (delta >= 1); } -static int mincross(graph_t * g, int startpass, int endpass) +static int mincross(graph_t * g, int startpass, int endpass, int doBalance) { int maxthispass, iter, trying, pass; int cur_cross, best_cross; @@ -619,6 +596,11 @@ static int mincross(graph_t * g, int startpass, int endpass) transpose(g, FALSE); best_cross = ncross(g); } + if (doBalance) { + for (iter = 0; iter < maxthispass; iter++) + balance(g); + } + return best_cross; } @@ -860,10 +842,12 @@ void flat_rev(Agraph_t * g, Agedge_t * e) int j; Agedge_t *rev; - if (!ND_flat_out(e->head).list) rev = NULL; - else for (j = 0; (rev = ND_flat_out(e->head).list[j]); j++) - if (rev->head == e->tail) - break; + if (!ND_flat_out(e->head).list) + rev = NULL; + else + for (j = 0; (rev = ND_flat_out(e->head).list[j]); j++) + if (rev->head == e->tail) + break; if (rev) { merge_oneway(e, rev); if (ED_to_virt(e) == 0) diff --git a/lib/dotgen/position.c b/lib/dotgen/position.c index 42b2ffe3c..b03a6ca3c 100644 --- a/lib/dotgen/position.c +++ b/lib/dotgen/position.c @@ -24,13 +24,14 @@ */ #include "dot.h" +#include "aspect.h" static int nsiter2(graph_t * g); static void create_aux_edges(graph_t * g); static void remove_aux_edges(graph_t * g); static void set_xcoords(graph_t * g); static void set_ycoords(graph_t * g); -static void set_aspect(graph_t * g); +static void set_aspect(graph_t * g, aspect_t* ); static void expand_leaves(graph_t * g); static void make_lrvn(graph_t * g); static void contain_nodes(graph_t * g); @@ -118,7 +119,7 @@ connectGraph (graph_t* g) } } -void dot_position(graph_t * g) +void dot_position(graph_t * g, aspect_t* asp) { if (GD_nlist(g) == NULL) return; /* ignore empty graph */ @@ -135,7 +136,7 @@ void dot_position(graph_t * g) assert(rank(g, 2, nsiter2(g)) == 0); } set_xcoords(g); - set_aspect(g); + set_aspect(g, asp); remove_aux_edges(g); /* must come after set_aspect since we now * use GD_ln and GD_rn for bbox width. */ @@ -938,28 +939,36 @@ static void scale_bb(graph_t * g, graph_t * root, double xf, double yf) GD_bb(g).UR.y *= yf; } -/**************************** EXTERNAL VARIABLES ***********************/ -extern double targetAR; -extern double currentAR; -extern double combiAR; -extern int prevIterations; -extern int curIterations; -extern int nextiter; -/**************************** EXTERNAL VARIABLES ***********************/ - - -/*********************************************************************** - * Some additional codes have been added at the end of set_aspect - * function to estimate the next number of iterations for ranking phase - ***********************************************************************/ - +/* adjustAspectRatio: + */ +static void adjustAspectRatio (graph_t* g, aspect_t* asp) +{ + double AR = (GD_bb(g).UR.x - GD_bb(g).LL.x)/(GD_bb(g).UR.y - GD_bb(g).LL.y); + if (Verbose) { + fprintf(stderr, "AR=%0.4lf\t Area= %0.4lf\t", AR, (double)(GD_bb(g).UR.x - GD_bb(g).LL.x)*(GD_bb(g).UR.y - GD_bb(g).LL.y)/10000.0); + fprintf(stderr, "Dummy=%d\n", countDummyNodes(g)); + } + if (AR > 1.1*asp->targetAR) { + asp->nextIter = (int)(asp->targetAR * (double)(asp->curIterations - asp->prevIterations)/(AR)); + } + else if (AR <= 0.8 * asp->targetAR) { + asp->nextIter = -1; + if (Verbose) + fprintf(stderr, "Going to apply another expansion.\n"); + } + else { + asp->nextIter = 0; + } + if (Verbose) + fprintf(stderr, "next#iter=%d\n", asp->nextIter); +} /* set_aspect: * Set bounding boxes and, if ratio is set, rescale graph. * Note that if some dimension shrinks, there may be problems * with labels. */ -static void set_aspect(graph_t * g) +static void set_aspect(graph_t * g, aspect_t* asp) { double xf = 0.0, yf = 0.0, actual, desired; node_t *n; @@ -1037,28 +1046,7 @@ static void set_aspect(graph_t * g) } } -#ifdef ASPECT - double AR = (GD_bb(g).UR.x - GD_bb(g).LL.x)/(GD_bb(g).UR.y - GD_bb(g).LL.y); - if (Verbose) { - fprintf(stderr, "AR=%0.4lf\t Area= %0.4lf\t", AR, (double)(GD_bb(g).UR.x - GD_bb(g).LL.x)*(GD_bb(g).UR.y - GD_bb(g).LL.y)/10000.0); - fprintf(stderr, "Dummy=%d\n", countDummyNodes(g)); - } - if (AR > 1.1*targetAR) - { - nextiter = (int)(targetAR * (double)(curIterations - prevIterations)/(AR)); - } - else if (AR <= 0.8 * targetAR) - { - nextiter = -1; - if (Verbose) - fprintf(stderr, "Going to apply another expansion.\n"); - } - else { - nextiter = 0; - } - if (Verbose) - fprintf(stderr, "next#iter=%d\n", nextiter); -#endif + if (asp) adjustAspectRatio (g, asp); } static point resize_leaf(node_t * leaf, point lbound) diff --git a/lib/dotgen/rank.c b/lib/dotgen/rank.c index 695cfc442..747a3df84 100644 --- a/lib/dotgen/rank.c +++ b/lib/dotgen/rank.c @@ -31,10 +31,6 @@ #include "dot.h" -void expand_ranksets(graph_t *); -static void saveVirtualEdges(graph_t *); -static void restoreVirtualEdges(graph_t *); - static void renewlist(elist * L) { @@ -62,10 +58,11 @@ cleanup1(graph_t * g) for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { f = ED_to_virt(e); + /* Null out any other references to f to make sure we don't + * handle it a second time. For example, parallel multiedges + * share a virtual edge. + */ if (f && (e == ED_to_orig(f))) { - /* Null out any other references to f to make sure we don't handle it - * a second time. For example, parallel multiedges share a virtual edge. - */ edge_t *e1, *f1; for (e1 = agfstout(g, n); e1; e1 = agnxtout(g, e1)) { if (e != e1) { @@ -262,7 +259,7 @@ collapse_cluster(graph_t * g, graph_t * subg) return; make_new_cluster(g, subg); if (CL_type == LOCAL) { - dot_rank(subg); + dot_rank(subg, 0); cluster_leader(subg); } else dot_scan_ranks(subg); @@ -405,7 +402,7 @@ void rank1(graph_t * g) * Leaf sets and clusters remain merged. * Sets minrank and maxrank appropriately. */ -void expand_ranksets(graph_t * g) +static void expand_ranksets(graph_t * g, aspect_t* asp) { int c; node_t *n, *leader; @@ -418,11 +415,8 @@ void expand_ranksets(graph_t * g) /* The following works because ND_rank(n) == 0 if n is not in a * cluster, and ND_rank(n) = the local rank offset if n is in * a cluster. */ - if (leader != n) -#ifdef ASPECT - if (ND_rank(n) == 0) -#endif - ND_rank(n) += ND_rank(leader); + if ((leader != n) && (!asp || (ND_rank(n) == 0))) + ND_rank(n) += ND_rank(leader); if (GD_maxrank(g) < ND_rank(n)) GD_maxrank(g) = ND_rank(n); @@ -465,96 +459,98 @@ setRanks (graph_t* g, attrsym_t* lsym) } #endif -node_t **virtualEdgeHeadList = NULL; -node_t **virtualEdgeTailList = NULL; - -int nVirtualEdges = 0; +#ifdef UNUSED +static node_t **virtualEdgeHeadList = NULL; +static node_t **virtualEdgeTailList = NULL; +static int nVirtualEdges = 0; static void saveVirtualEdges(graph_t *g) { - if (virtualEdgeHeadList != NULL) - { - free(virtualEdgeHeadList); - } - if (virtualEdgeTailList != NULL) - { - free(virtualEdgeTailList); - } - - //allocate memory edge_t *e; node_t *n; int cnt = 0; int lc; - for (n = agfstnode(g); n; n = agnxtnode(g, n)) - for (lc = 0; lc < ND_in(n).size; lc++) - { - e = ND_in(n).list[lc]; - if (ED_edge_type(e) == VIRTUAL) - cnt++; - } + if (virtualEdgeHeadList != NULL) { + free(virtualEdgeHeadList); + } + if (virtualEdgeTailList != NULL) { + free(virtualEdgeTailList); + } + + /* allocate memory */ + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + for (lc = 0; lc < ND_in(n).size; lc++) { + e = ND_in(n).list[lc]; + if (ED_edge_type(e) == VIRTUAL) cnt++; + } + } nVirtualEdges = cnt; - virtualEdgeHeadList = (node_t **)malloc(sizeof(node_t *) * cnt); - virtualEdgeTailList = (node_t **)malloc(sizeof(node_t *) * cnt); - - for (n = agfstnode(g); n; n = agnxtnode(g, n)) - for (lc = 0, cnt = 0; lc < ND_in(n).size; lc++) - { - e = ND_in(n).list[lc]; - if (ED_edge_type(e) == VIRTUAL) - { - virtualEdgeHeadList[cnt] = e->head; - virtualEdgeTailList[cnt] = e->tail; - printf("saved virtual edge: %s->%s\n", virtualEdgeTailList[cnt]->name, virtualEdgeHeadList[cnt]->name); - cnt++; - } - } + virtualEdgeHeadList = N_GNEW(cnt, node_t*); + virtualEdgeTailList = N_GNEW(cnt, node_t*); + + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + for (lc = 0, cnt = 0; lc < ND_in(n).size; lc++) { + e = ND_in(n).list[lc]; + if (ED_edge_type(e) == VIRTUAL) { + virtualEdgeHeadList[cnt] = e->head; + virtualEdgeTailList[cnt] = e->tail; + if (Verbose) + printf("saved virtual edge: %s->%s\n", + virtualEdgeTailList[cnt]->name, + virtualEdgeHeadList[cnt]->name); + cnt++; + } + } + } } static void restoreVirtualEdges(graph_t *g) { - int i; - edge_t e; - - for (i = 0; i < nVirtualEdges; i++) - { - if (virtualEdgeTailList[i] && virtualEdgeHeadList[i]) - { - printf("restoring virtual edge: %s->%s\n", virtualEdgeTailList[i]->name, virtualEdgeHeadList[i]->name); - virtual_edge(virtualEdgeTailList[i], virtualEdgeHeadList[i], NULL); - } - else - { - printf("Deleted?\n"); - } - } - printf("restored %d virt edges\n", nVirtualEdges); - getchar(); + int i; + edge_t e; + + for (i = 0; i < nVirtualEdges; i++) { + if (virtualEdgeTailList[i] && virtualEdgeHeadList[i]) { + if (Verbose) + printf("restoring virtual edge: %s->%s\n", + virtualEdgeTailList[i]->name, virtualEdgeHeadList[i]->name); + virtual_edge(virtualEdgeTailList[i], virtualEdgeHeadList[i], NULL); + } + } + if (Verbose) + printf("restored %d virt edges\n", nVirtualEdges); } +#endif -extern int nextiter; - - -void dot_rank(graph_t * g) +/* dot_rank: + * asp != NULL => g is root + */ +void dot_rank(graph_t * g, aspect_t* asp) { point p; #ifdef ALLOW_LEVELS attrsym_t* N_level; #endif edgelabel_ranks(g); -#ifdef ASPECT - init_UF_size(g); - initEdgeTypes(g); -#endif + + if (asp) { + init_UF_size(g); + initEdgeTypes(g); + } + collapse_sets(g,g); /*collapse_leaves(g); */ class1(g); p = minmax_edges(g); decompose(g, 0); + if (asp && ((g->u.comp.size > 1)||(g->u.n_cluster > 0))) { + asp->badGraph = 1; + asp = NULL; + } acyclic(g); if (minmax_edges2(g, p)) decompose(g, 0); @@ -563,11 +559,13 @@ void dot_rank(graph_t * g) setRanks(g, N_level); else #endif -#ifdef ASPECT -#else - rank1(g); -#endif - expand_ranksets(g); + + if (asp) + rank3(g, asp); + else + rank1(g); + + expand_ranksets(g, asp); cleanup1(g); }