|
|
1.1 ! root 1: #include "draw_dag.h" ! 2: ! 3: #include <sys/types.h> ! 4: #include <sys/times.h> ! 5: #define TIC 60 ! 6: ! 7: /* ! 8: Create an ordering of nodes on each level. ! 9: The ordering attempts to minimize edge crossing ! 10: */ ! 11: static float Convergence = .005; // convergence rate ! 12: static int Maxiter = 24; // max number of iterations ! 13: static int Minquit = 10; // quit after this many iterations ! 14: // if not improved ! 15: static int **List; // temp space for rank construction ! 16: static int *Count, // to aid rcross() ! 17: *Cross, // current numbers of crossings between levels ! 18: *Levelmarked; // used in transpose() ! 19: static edge_t **Flatedges; // transitive closure of flat edges ! 20: static int *Flatindeg; // in-degree of nodes using Flatedges ! 21: ! 22: static long *Median; ! 23: static int *Medadj; ! 24: ! 25: static void decompose(), ! 26: flatclosure(), ! 27: removestem(), ! 28: installstem(int**,int); ! 29: static int cross_stat(int**), rcross(int*,int*), ! 30: buildrank(int**,int**,int); ! 31: extern void inversion(int**); ! 32: ! 33: void dag_ranks() ! 34: { ! 35: struct tms begtm, endtm; ! 36: int startcross = 0; ! 37: ! 38: if(Verbose) ! 39: { ! 40: #ifndef TIMING ! 41: fprintf(stderr,"Minimize edge crossing\n"); ! 42: #endif ! 43: times(&begtm); ! 44: } ! 45: #ifdef TIMING ! 46: Maxiter = 20; ! 47: Minquit = 20; ! 48: Convergence = .0001; ! 49: #else ! 50: // reset parameters for speed ! 51: if(N_real_nodes > 500) ! 52: { ! 53: float density = ((float) N_edges)/N_nodes; ! 54: if(density >= 2.) ! 55: { ! 56: Maxiter = N_real_nodes <= 1000 ? 8 : 4; ! 57: Minquit = N_real_nodes <= 1000 ? 4 : 2; ! 58: Convergence = N_real_nodes <= 1000 ? .01 : .1; ! 59: } ! 60: } ! 61: #endif ! 62: ! 63: // number of nodes in each level ! 64: N_level = new int[Maxlevel+1]; ! 65: for(int i = 0; i < N_nodes; i++) ! 66: N_level[Level[i]] += 1; ! 67: ! 68: // create space for node lists ! 69: List = new int*[Maxlevel+1]; ! 70: Rank = new int*[Maxlevel+1]; ! 71: int **tryout = new int*[Maxlevel+1]; ! 72: int **target = new int*[Maxlevel+1]; ! 73: for(i = 0; i <= Maxlevel; ++i) ! 74: { ! 75: List[i] = new int[N_level[i]+1]; ! 76: tryout[i] = new int[N_level[i]+1]; ! 77: Rank[i] = new int[N_level[i]+1]; ! 78: Rank[i][0] = -1; ! 79: } ! 80: ! 81: // space for intermediate calculations ! 82: Invert = new int[N_nodes]; ! 83: Count = new int[N_nodes]; ! 84: Cross = new int[Maxlevel]; ! 85: Levelmarked = new int[Maxlevel+1]; ! 86: Median = new long[N_nodes]; ! 87: Medadj = new int[N_nodes+N_repeat_edges]; ! 88: ! 89: // compute the transitive closure of the set of flat edges ! 90: if(N_flat_edges > 0) ! 91: { ! 92: Flatedges = new edge_t*[N_real_nodes]; ! 93: Flatindeg = new int[N_real_nodes]; ! 94: flatclosure(); ! 95: } ! 96: ! 97: // detect connected components ! 98: Component = new int[N_nodes]; ! 99: decompose(); ! 100: ! 101: // build up the ordering component by component ! 102: for(int component = 1; component <= N_component; ++component) ! 103: { ! 104: for(i = 0; i <= Maxlevel; ++i) ! 105: { ! 106: for(int k = 0; ; ++k) ! 107: if(Rank[i][k] == -1) ! 108: break; ! 109: target[i] = Rank[i]+k; ! 110: } ! 111: startcross += buildrank(target,tryout,component); ! 112: } ! 113: inversion(Rank); ! 114: ! 115: if(Verbose) ! 116: { ! 117: times(&endtm); ! 118: int total = (endtm.tms_utime - begtm.tms_utime)+ ! 119: (endtm.tms_stime - begtm.tms_stime); ! 120: int percent = (total - (total/TIC)*TIC)*100/TIC; ! 121: int bestcross = cross_stat(Rank); ! 122: #ifdef TIMING ! 123: fprintf(stderr,"%d\t%d\t%d.%02d\t", ! 124: startcross,bestcross,total/TIC,percent); ! 125: #else ! 126: fprintf(stderr,"Starting crossing number = %d\n",startcross); ! 127: fprintf(stderr,"Crossings between ranks:\n"); ! 128: for(i = 0; i < Maxlevel; ++i) ! 129: fprintf(stderr,"(%2d,%2d):\tx=%d\n",i,i+1,Cross[i]); ! 130: fprintf(stderr,"Ending crossing number = %d\n",bestcross); ! 131: fprintf(stderr,"Time in minimizing crossing: %d.%02ds\n", ! 132: total/TIC, percent); ! 133: #endif ! 134: } ! 135: ! 136: // release temp space ! 137: delete Median; ! 138: delete Medadj; ! 139: delete Levelmarked; ! 140: delete Cross; ! 141: delete Count; ! 142: for(i = 0; i <= Maxlevel; ++i) ! 143: { ! 144: delete List[i]; ! 145: delete tryout[i]; ! 146: } ! 147: delete List; ! 148: delete tryout; ! 149: delete target; ! 150: if(N_flat_edges > 0) ! 151: deledges(N_real_nodes,Flatedges); ! 152: } ! 153: ! 154: // compute the transitive closure of flat edges ! 155: // and remove resulting bidirectional edges. ! 156: // The final graph defines a partial order on the nodes. ! 157: static void flatedges(int root, int here, int *marked) ! 158: { ! 159: marked[here] = 1; ! 160: ! 161: for(edge_t *e = Noedges[here]; e; e = e->next) ! 162: if(e->weight > 0 && !marked[e->node]) ! 163: { ! 164: // check for bi-directional edges ! 165: edge_t *lastf = NULL, *f = Flatedges[e->node]; ! 166: for(; f != NULL; lastf = f, f = f->next) ! 167: if(f->node == root) ! 168: break; ! 169: ! 170: // remove bidirectional edges ! 171: if(f != NULL) ! 172: { ! 173: if(lastf) ! 174: lastf->next = f->next; ! 175: else Flatedges[e->node] = f->next; ! 176: delete f; ! 177: } ! 178: // add a new edge ! 179: else Flatedges[root] = ! 180: new edge_t(e->node,0,0,0,Flatedges[root]); ! 181: ! 182: flatedges(root,e->node,marked); ! 183: } ! 184: } ! 185: ! 186: static void flatclosure() ! 187: { ! 188: int *marked = Count; ! 189: for(int v = 0; v < N_real_nodes; ++v) ! 190: { ! 191: for(int i = 0; i < N_real_nodes; ++i) ! 192: marked[i] = 0; ! 193: flatedges(v,v,marked); ! 194: } ! 195: ! 196: for(v = 0; v < N_real_nodes; ++v) ! 197: for(edge_t *e = Flatedges[v]; e; e = e->next) ! 198: Flatindeg[e->node]++; ! 199: } ! 200: ! 201: // assign component numbers to nodes so that nodes in the same ! 202: // connected component get the same number. ! 203: static void decompose() ! 204: { ! 205: // make a reverse flat edge list ! 206: edge_t **noedges = NULL; ! 207: if(N_flat_edges > 0) ! 208: { ! 209: noedges = new edge_t*[N_real_nodes]; ! 210: for(int v = 0; v < N_real_nodes; ++v) ! 211: for(edge_t *e = Noedges[v]; e; e = e->next) ! 212: { ! 213: int w = e->node; ! 214: if(w != v) ! 215: noedges[w] = new edge_t(v,0,0,0,noedges[w]); ! 216: } ! 217: } ! 218: ! 219: // all adjacent edge lists ! 220: edge_t **adjlist[5]; ! 221: adjlist[0] = Outedges; ! 222: adjlist[1] = Inedges; ! 223: adjlist[2] = N_flat_edges > 0 ? Noedges : NULL; ! 224: adjlist[3] = N_flat_edges > 0 ? noedges : NULL; ! 225: adjlist[4] = NULL; ! 226: ! 227: // space for the breadth-first search ! 228: int *queue = new int[N_nodes]; ! 229: ! 230: N_component = 0; ! 231: for(int n = 0; n < N_nodes; ++n) ! 232: { ! 233: if(Component[n] > 0) ! 234: continue; ! 235: ! 236: // initialize for component search ! 237: N_component += 1; ! 238: Component[n] = N_component; ! 239: ! 240: // breadth-first search ! 241: int first = 0, last = 1; ! 242: queue[0] = n; ! 243: while(first < last) ! 244: { ! 245: int v = queue[first++]; ! 246: for(int i = 0; adjlist[i] != NULL; ++i) ! 247: { ! 248: if(v >= N_real_nodes && i >= 2) ! 249: continue; ! 250: for(edge_t *e = adjlist[i][v]; e; e = e->next) ! 251: { ! 252: int w = e->node; ! 253: if(Component[w] != 0) ! 254: continue; ! 255: Component[w] = N_component; ! 256: queue[last++] = w; ! 257: } ! 258: } ! 259: } ! 260: } ! 261: ! 262: delete queue; ! 263: if(N_flat_edges > 0) ! 264: deledges(N_real_nodes,noedges); ! 265: } ! 266: ! 267: // copy a ranking to another ! 268: static void copyrank(int **from, int **to) ! 269: { ! 270: for(int i = 0; i <= Maxlevel; ++i) ! 271: { ! 272: register int *frp = from[i], *top = to[i]; ! 273: while(*frp != -1) ! 274: *top++ = *frp++; ! 275: *top = -1; ! 276: } ! 277: } ! 278: ! 279: // see if one vertex must be left of another ! 280: static int left2right(int v, int w) ! 281: { ! 282: if(v >= N_real_nodes || w >= N_real_nodes) ! 283: return 0; ! 284: ! 285: for(edge_t *e = Flatedges[v]; e; e = e->next) ! 286: if(e->node == w) ! 287: return 1; ! 288: return 0; ! 289: } ! 290: ! 291: // construct nodes reachable from 'here' in post-order. ! 292: // This is the same as doing a topological sort in reverse order. ! 293: static void postorder(int here,int *marked,int *list, int &n_search) ! 294: { ! 295: marked[here] = 1; ! 296: for(edge_t *e = Flatedges[here]; e; e = e->next) ! 297: if(!marked[e->node]) ! 298: postorder(e->node,marked,list,n_search); ! 299: list[n_search++] = here; ! 300: } ! 301: ! 302: static void reorder(int *list, int *marked, int *temp) ! 303: { ! 304: for(int i = 0; list[i] >= 0; ++i) ! 305: marked[list[i]] = 0; ! 306: ! 307: int n_temp = 0; ! 308: for(i = 0; list[i] >= 0; ++i) ! 309: { ! 310: // dummy nodes ! 311: if(list[i] >= N_real_nodes) ! 312: temp[n_temp++] = list[i]; ! 313: // real nodes ! 314: else if(!marked[list[i]] && Flatindeg[list[i]] == 0) ! 315: { ! 316: int n_search = 0; ! 317: postorder(list[i],marked,temp+n_temp,n_search); ! 318: int *left = temp+n_temp, *right = left+n_search-1; ! 319: for(; left < right; ++left, --right) ! 320: { ! 321: int t = *left; ! 322: *left = *right; ! 323: *right = t; ! 324: } ! 325: n_temp += n_search; ! 326: } ! 327: } ! 328: ! 329: // recopy the list ! 330: for(i = 0; list[i] >= 0; ++i) ! 331: list[i] = temp[i]; ! 332: } ! 333: ! 334: // Compute an initial ordering of nodes belonging to some connected component. ! 335: static void initrank(int *rank[], int component, int isdown) ! 336: { ! 337: // use breadth-first search to build the list ! 338: int *marked = new int[N_nodes]; ! 339: int *queue = new int[N_nodes]; ! 340: int *n_lev = new int[Maxlevel+1]; ! 341: ! 342: // now do the rank partitioning by components ! 343: edge_t **those = isdown ? Inedges : Outedges; ! 344: edge_t **these = isdown ? Outedges : Inedges; ! 345: for(int n = 0; n < N_nodes; ++n) ! 346: { ! 347: if(marked[n] || those[n] || Component[n] != component || ! 348: (n < N_real_nodes && N_flat_edges <= 0 && Stems[n])) ! 349: continue; ! 350: ! 351: marked[n] = 1; ! 352: queue[0] = n; ! 353: int first = 0, last = 1; ! 354: while(first < last) ! 355: { ! 356: int node = queue[first++]; ! 357: rank[Level[node]][n_lev[Level[node]]++] = node; ! 358: for(edge_t *e = these[node]; e; e = e->next) ! 359: { ! 360: if(!marked[e->node]) ! 361: { ! 362: marked[e->node] = 1; ! 363: queue[last++] = e->node; ! 364: } ! 365: } ! 366: } ! 367: } ! 368: ! 369: for(n = 0; n <= Maxlevel; ++n) ! 370: { ! 371: rank[n][n_lev[n]] = -1; ! 372: ! 373: // make sure that implicit left-to-right orders are satisfied ! 374: if(N_flat_edges > 0) ! 375: reorder(rank[n],marked,queue); ! 376: } ! 377: ! 378: delete marked; ! 379: delete queue; ! 380: delete n_lev; ! 381: } ! 382: ! 383: // Compute the crossing of two levels. ! 384: // We'll assume that edges point from top to bot. ! 385: static int rcross(int *top, int *bot) ! 386: { ! 387: // clear up work space ! 388: for (int i = 0; bot[i] != -1; i++) ! 389: Count[i] = 0; ! 390: ! 391: register int cross = 0; // the crossing count ! 392: int max = 0; // index we have to sum to during counting ! 393: for (i = 0; top[i] != -1; i++) ! 394: { ! 395: register edge_t *e; ! 396: ! 397: if (max > 0) ! 398: { ! 399: /* iterate over each edge */ ! 400: for (e = Outedges[top[i]]; e; e = e->next) ! 401: for(int k = Invert[e->node]+1; k <= max; k++) ! 402: cross += Count[k]*e->count; ! 403: } ! 404: ! 405: /* update the counts */ ! 406: for (e = Outedges[top[i]]; e; e = e->next) ! 407: { ! 408: register int inv = Invert[e->node]; ! 409: if (inv > max) ! 410: max = inv; ! 411: Count[inv] += e->count; ! 412: } ! 413: } ! 414: return cross; ! 415: } ! 416: ! 417: // compute the inverted indices of all vertices in their rank lists ! 418: // and the crossing statistics between ranks. ! 419: static void inversion(int **ranks) ! 420: { ! 421: for(int i = 0; i <= Maxlevel; ++i) ! 422: { ! 423: int *rank = ranks[i]; ! 424: for(int k = 0; rank[k] != -1; ++k) ! 425: Invert[rank[k]] = k; ! 426: } ! 427: } ! 428: ! 429: static int cross_stat(int **ranks) ! 430: { ! 431: int cross = 0; ! 432: for(int i = 0; i < Maxlevel; ++i) ! 433: cross += (Cross[i] = rcross(ranks[i],ranks[i+1])); ! 434: return cross; ! 435: } ! 436: ! 437: // Compute the crossing of incident edges of two vertices ! 438: static int vcross(edge_t *adj1, edge_t *adj2) ! 439: { ! 440: register int cross = 0; ! 441: for (register edge_t *e2 = adj2; e2; e2 = e2->next) ! 442: { ! 443: register int inv = Invert[e2->node]; ! 444: register int cnt = e2->count; ! 445: for(register edge_t *e1 = adj1; e1; e1 = e1->next) ! 446: if(Invert[e1->node] > inv) ! 447: cross += e1->count * cnt; ! 448: } ! 449: return cross; ! 450: } ! 451: ! 452: // Reduce crossings by adjacent tranpositions of vertices ! 453: static void transpose(int **ranks, int revert) ! 454: { ! 455: // current number of crossings ! 456: int curcross = 0; ! 457: for(int l = 0; l < Maxlevel; ++l) ! 458: { ! 459: curcross += Cross[l]; ! 460: Levelmarked[l] = 1; ! 461: } ! 462: if(curcross == 0) ! 463: return; ! 464: else Levelmarked[l] = 1; ! 465: ! 466: while(1) ! 467: { ! 468: int delta = 0; ! 469: for (int lev = 0; lev <= Maxlevel; lev++) ! 470: if(Levelmarked[lev]) ! 471: { ! 472: int *rank = ranks[lev]; ! 473: if(rank[0] == -1 || rank[1] == -1) ! 474: { ! 475: Levelmarked[lev] = 0; ! 476: continue; ! 477: } ! 478: for(; rank[1] != -1; ++rank) ! 479: { ! 480: register int c0 = 0, c1 = 0; ! 481: int v = rank[0], w = rank[1]; ! 482: ! 483: if(N_flat_edges > 0 && left2right(v,w) != 0) ! 484: continue; ! 485: ! 486: if(lev > 0) ! 487: { ! 488: edge_t *vadj = Inedges[v], *wadj = Inedges[w]; ! 489: c0 += vcross(vadj,wadj); ! 490: c1 += vcross(wadj,vadj); ! 491: } ! 492: if(lev < Maxlevel) ! 493: { ! 494: edge_t *vadj = Outedges[v], *wadj = Outedges[w]; ! 495: c0 += vcross(vadj,wadj); ! 496: c1 += vcross(wadj,vadj); ! 497: } ! 498: ! 499: if (c1 < c0 || (c1 > 0 && c1 == c0 && revert)) ! 500: { ! 501: Levelmarked[lev] = 2; ! 502: Invert[v]++; ! 503: Invert[w]--; ! 504: rank[0] = w; ! 505: rank[1] = v; ! 506: delta += c0-c1; ! 507: } ! 508: } ! 509: ! 510: if(Levelmarked[lev] == 2) ! 511: { ! 512: Levelmarked[lev] = 1; ! 513: if(lev > 0) ! 514: { ! 515: Levelmarked[lev-1] = 1; ! 516: Cross[lev-1] = -1; ! 517: } ! 518: if(lev < Maxlevel) ! 519: { ! 520: Levelmarked[lev+1] = 1; ! 521: Cross[lev] = -1; ! 522: } ! 523: } ! 524: else Levelmarked[lev] = 0; ! 525: } ! 526: ! 527: curcross -= delta; ! 528: float reduce = curcross <= 0 ? 0. : ((float)delta)/curcross; ! 529: if(curcross == 0 || reduce <= Convergence) ! 530: break; ! 531: } ! 532: ! 533: // restore crossing statistics ! 534: for(l = 0; l < Maxlevel; ++l) ! 535: if(Cross[l] < 0) ! 536: Cross[l] = rcross(ranks[l],ranks[l+1]); ! 537: } ! 538: ! 539: // sort nodes by their median values. ! 540: // This is basically a bubble sort that respects fixed points ! 541: static int mediansort(int *array, int nelt, int revert, int hasfixed) ! 542: { ! 543: int changed = 0; ! 544: ! 545: register int *ep = array+nelt, *lp, *rp; ! 546: for(nelt -= 1; nelt > 0; --nelt) ! 547: { ! 548: lp = array; ! 549: while(lp < ep) ! 550: { ! 551: // -1 nodes are FIXED points ! 552: if(Median[*lp] < 0) ! 553: for(; lp < ep; lp++) ! 554: if(Median[*lp] >= 0) ! 555: break; ! 556: if(lp >= ep) ! 557: break; ! 558: ! 559: // find the one that can be compared with ! 560: int muststay = 0; ! 561: for(rp = lp+1; rp < ep; ++rp) ! 562: { ! 563: if(N_flat_edges > 0 && left2right(*lp,*rp)) ! 564: { ! 565: muststay = 1; ! 566: break; ! 567: } ! 568: if(Median[*rp] >= 0) ! 569: break; ! 570: } ! 571: if(rp >= ep) ! 572: break; ! 573: ! 574: // switch if appropriate ! 575: if(!muststay && ! 576: (Median[*lp] > Median[*rp] || ! 577: (Median[*lp] == Median[*rp] && revert))) ! 578: { ! 579: register int t = *lp; ! 580: *lp = *rp; ! 581: *rp = t; ! 582: changed++; ! 583: } ! 584: lp = rp; ! 585: } ! 586: ! 587: if(!hasfixed && !revert) ! 588: --ep; ! 589: } ! 590: return changed; ! 591: } ! 592: ! 593: ! 594: // reduce crossing using weighted median sorting ! 595: static int intcmp(register int *i1, register int *i2) ! 596: { ! 597: return *i1 - *i2; ! 598: } ! 599: static void median(int **ranks, int revert, int isup) ! 600: { ! 601: #define SCALE 16 ! 602: for (int lev = 1; lev <= Maxlevel; lev++) ! 603: { ! 604: int thislev = isup ? Maxlevel-lev : lev; ! 605: int thatlev = isup ? thislev+1 : thislev-1; ! 606: edge_t **edges = isup ? Outedges : Inedges; ! 607: int *thislist = ranks[thislev]; ! 608: int *thatlist = ranks[thatlev]; ! 609: ! 610: // compute medians of thislist ! 611: int hasfixed = 0; ! 612: for(int n_this = 0; thislist[n_this] != -1; n_this++) ! 613: { ! 614: register int node = thislist[n_this]; ! 615: register int *endadj = Medadj; ! 616: for(register edge_t *e = edges[node]; e; e = e->next) ! 617: for(int k = e->count; k > 0; --k) ! 618: *endadj++ = Invert[e->node]; ! 619: register int cnt = endadj-Medadj; ! 620: #ifdef BCENTER ! 621: // barycenter method ! 622: if(cnt > 0) ! 623: { ! 624: int ave = 0; ! 625: for(int m = 0; m < cnt; ++m) ! 626: ave += Medadj[m]; ! 627: Median[node] = (SCALE*ave)/cnt; ! 628: } ! 629: else ! 630: { ! 631: Median[node] = -1; ! 632: hasfixed = 1; ! 633: } ! 634: #else /* a right median method */ ! 635: #ifdef RMEDIAN ! 636: if(cnt > 1) ! 637: qsort((char*)Medadj,cnt,sizeof(Medadj[0]),(qsortcmpfun)intcmp); ! 638: if(cnt == 0) ! 639: { ! 640: Median[node] = -1; ! 641: hasfixed = 1; ! 642: } ! 643: else Median[node] = SCALE*Medadj[cnt/2]; ! 644: #else /* weighted median */ ! 645: switch(cnt) ! 646: { ! 647: case 0 : ! 648: Median[node] = -1; ! 649: hasfixed = 1; ! 650: break; ! 651: case 1 : ! 652: Median[node] = SCALE*Medadj[0]; ! 653: break; ! 654: case 2 : ! 655: Median[node] = (Medadj[0]+Medadj[1])*(SCALE/2); ! 656: break; ! 657: default : ! 658: qsort((char*)Medadj,cnt,sizeof(Medadj[0]),(qsortcmpfun)intcmp); ! 659: if(cnt%2) ! 660: { ! 661: Median[node] = SCALE*Medadj[cnt/2]; ! 662: break; ! 663: } ! 664: ! 665: register int r = cnt/2; ! 666: register int l = r-1; ! 667: ! 668: // compute left/right spans ! 669: int lspan = 0, rspan = 0; ! 670: int curinv = Medadj[l]; ! 671: int nextinv; ! 672: for(k = l-1; k >= 0; --k) ! 673: { ! 674: nextinv = Medadj[k]; ! 675: lspan += curinv-nextinv; ! 676: curinv = nextinv; ! 677: } ! 678: curinv = Medadj[r]; ! 679: for(k = r+1; k < cnt; ++k) ! 680: { ! 681: nextinv = Medadj[k]; ! 682: rspan += nextinv-curinv; ! 683: curinv = nextinv; ! 684: } ! 685: if(lspan == rspan) ! 686: Median[node] = (Medadj[l]+Medadj[r])*(SCALE/2); ! 687: else ! 688: { ! 689: int w = Medadj[l]*rspan+ Medadj[r]*lspan; ! 690: Median[node] = (w*SCALE)/(lspan+rspan); ! 691: } ! 692: break; ! 693: } ! 694: #endif /* RMEDIAN */ ! 695: #endif /* BCENTER */ ! 696: } ! 697: ! 698: // sort by medians ! 699: if(mediansort(thislist,n_this,revert,hasfixed)) ! 700: { ! 701: for(int i = 0; *thislist != -1; ++i) ! 702: Invert[*thislist++] = i; ! 703: if(thislev > 0) ! 704: Cross[thislev-1] = -1; ! 705: if(thislev < Maxlevel) ! 706: Cross[thislev] = -1; ! 707: } ! 708: } ! 709: for(lev = 0; lev < Maxlevel; ++lev) ! 710: if(Cross[lev] < 0) ! 711: Cross[lev] = rcross(ranks[lev],ranks[lev+1]); ! 712: } ! 713: ! 714: // minimizing crossing using the median and transpose heuristics ! 715: static int mincross(int **ranks, int bestcross) ! 716: { ! 717: // copy current rank to List to start the process ! 718: copyrank(ranks,List); ! 719: ! 720: inversion(List); ! 721: int curcross = cross_stat(List); ! 722: if(curcross < bestcross) ! 723: bestcross = curcross; ! 724: ! 725: int counter = 1; ! 726: for (int iter = 0; iter < Maxiter; iter++) ! 727: { ! 728: median(List,iter%4 < 2 ? 1 : 0,iter%2 ? 1 : 0); ! 729: #ifndef NOTRANSPOSE ! 730: transpose(List,iter%4 < 2 ? 0 : 1); ! 731: #endif ! 732: curcross = 0; ! 733: for(int i = 0; i < Maxlevel; ++i) ! 734: curcross += Cross[i]; ! 735: #ifdef BIGGRAPH ! 736: if(Verbose) ! 737: fprintf(stderr,"Iteration %d, curcross=%d bestcross=%d\n", ! 738: iter,curcross,bestcross); ! 739: #endif ! 740: if(curcross < bestcross) ! 741: { ! 742: float reduce = curcross <= 0 ? 0. : ! 743: ((float)(bestcross-curcross))/curcross; ! 744: ! 745: copyrank(List,ranks); ! 746: bestcross = curcross; ! 747: ! 748: if(bestcross == 0 || reduce < Convergence) ! 749: break; ! 750: ! 751: counter = 1; ! 752: } ! 753: else ! 754: { ! 755: if(counter > Minquit) ! 756: break; ! 757: ++counter; ! 758: } ! 759: } ! 760: ! 761: return bestcross; ! 762: } ! 763: ! 764: // compute edge crossings ! 765: static int scross(int iw, int count, edge_t *adj, int dir) ! 766: { ! 767: int cross = 0; ! 768: if(dir > 0) ! 769: { ! 770: for(register edge_t *e = adj; e; e = e->next) ! 771: if(Invert[e->node] < iw) ! 772: cross += e->count*count; ! 773: } ! 774: else ! 775: { ! 776: for(register edge_t *e = adj; e; e = e->next) ! 777: if(Invert[e->node] > iw) ! 778: cross += e->count*count; ! 779: } ! 780: return cross; ! 781: } ! 782: ! 783: // put stems in place where they'll be close to their adjacent nodes ! 784: static void fixstem(int **ranks, int *stem) ! 785: { ! 786: for(int dir = 1; dir >= -1; dir -= 2) ! 787: for(int l = dir > 0 ? 1 : Maxlevel-1; l >= 0 && l <= Maxlevel; l += dir) ! 788: { ! 789: edge_t **these = dir > 0 ? Inedges : Outedges; ! 790: edge_t **those = dir > 0 ? Outedges : Inedges; ! 791: int *rank = ranks[l]; ! 792: ! 793: // count the list size ! 794: int n_rank = 0; ! 795: int n_stem = 0; ! 796: for(int k = 0; rank[k] >= 0; ++k, ++n_rank) ! 797: { ! 798: int v = rank[k]; ! 799: if(these[v] && !these[v]->next && !those[v]) ! 800: stem[n_stem++] = v; ! 801: } ! 802: if(n_stem <= 0) ! 803: continue; ! 804: ! 805: for(k = 0; k < n_stem; ++k) ! 806: { ! 807: int v = stem[k], iv = Invert[v]; ! 808: int w = these[v]->node, iw = Invert[w]; ! 809: int count = these[v]->count; ! 810: ! 811: // find the left and right medians and bounds ! 812: int n = 0; ! 813: for(edge_t *e = those[w]; e; e = e->next) ! 814: if(e->node != v) ! 815: Medadj[n++] = Invert[e->node]; ! 816: if(n == 0) ! 817: continue; ! 818: if(n > 2) ! 819: qsort((char*)Medadj,n,sizeof(Medadj[0]),(qsortcmpfun)intcmp); ! 820: int rmed = Medadj[n/2]; ! 821: int lmed = n%2 ? rmed : Medadj[n/2-1]; ! 822: ! 823: // check each position ! 824: int best = iv, cross = 0; ! 825: int dist = iabs(2*iv - (rmed+lmed)); ! 826: for(int d = -1; d <= 1; d += 2) ! 827: { ! 828: int c = 0, lm = lmed, rm = rmed; ! 829: for(int p = iv+d; p >= 0 && p < n_rank; p += d) ! 830: { ! 831: int x = rank[p]; ! 832: if(p == lm) ! 833: lm -= d; ! 834: if(p == rm) ! 835: rm -= d; ! 836: ! 837: int c0 = scross(iw,count,these[x],d); ! 838: int c1 = scross(iw,count,these[x],-d); ! 839: c += c1-c0; ! 840: if(c == cross) ! 841: { ! 842: int di = iabs(2*p -(lm+rm)); ! 843: if(di < dist) ! 844: { ! 845: best = p; ! 846: dist = di; ! 847: } ! 848: } ! 849: else if(c < cross) ! 850: { ! 851: cross = c; ! 852: best = p; ! 853: dist = iabs(2*p - (lm+rm)); ! 854: } ! 855: } ! 856: } ! 857: if(best == iv) ! 858: continue; ! 859: ! 860: // move v to its best place ! 861: d = best < iv ? -1 : 1; ! 862: for(register int p = iv; p != best; p += d) ! 863: { ! 864: rank[p] = rank[p+d]; ! 865: Invert[rank[p]] = p; ! 866: } ! 867: rank[p] = v; ! 868: Invert[v] = p; ! 869: ! 870: } ! 871: } ! 872: } ! 873: ! 874: // make node orderings for a connected component ! 875: static int buildrank(int **target, int **tryout, int component) ! 876: { ! 877: // build order using downward depth-first search ! 878: int start_target, start_tryout, bestcross, curcross; ! 879: initrank(target,component,1); ! 880: inversion(target); ! 881: start_target = bestcross = cross_stat(target); ! 882: start_tryout = 0; ! 883: ! 884: if(bestcross > 0) ! 885: { ! 886: #ifndef NOTRANSPOSE ! 887: transpose(target,0); ! 888: bestcross = 0; ! 889: for(int i = 0; i < Maxlevel; ++i) ! 890: bestcross += Cross[i]; ! 891: #endif ! 892: } ! 893: ! 894: // rebuild order using upward depth-first search ! 895: if(bestcross > 0) ! 896: { ! 897: initrank(tryout,component,0); ! 898: inversion(tryout); ! 899: start_tryout = curcross = cross_stat(tryout); ! 900: ! 901: if(curcross > 0) ! 902: { ! 903: #ifndef NOTRANSPOSE ! 904: transpose(tryout,0); ! 905: curcross = 0; ! 906: for(int i = 0; i < Maxlevel; ++i) ! 907: curcross += Cross[i]; ! 908: #endif ! 909: } ! 910: if(curcross == 0) ! 911: { ! 912: copyrank(tryout,target); ! 913: bestcross = curcross; ! 914: } ! 915: } ! 916: ! 917: // iterations to improve crossing ! 918: if(bestcross > 0) ! 919: bestcross = mincross(target,Maxint); ! 920: if(bestcross > 0 && (curcross = mincross(tryout,bestcross)) < bestcross) ! 921: copyrank(tryout,target); ! 922: ! 923: // fix dangling stems ! 924: if(N_flat_edges <= 0) ! 925: { ! 926: inversion(target); ! 927: fixstem(target,Count); ! 928: } ! 929: ! 930: return max(start_target,start_tryout); ! 931: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.