#include #include #include #include #include #include #include using std::min; using std::max; #include "dl.h" #include "flute.h" #include "mst2.h" namespace Flute { #define INFNTY INT_MAX #define D2M D2(1) // Max net degree that flute_mr will handle #define MR_FOR_SMALL_CASES_ONLY 1 #if MR_FOR_SMALL_CASES_ONLY #define MAXPART D2M // max partition of an MST #define MAXT (D2M/DPARAM*2) #else #define MAXPART (d/9*2) //(MAXD/THD*2) // max partition of an MST #define MAXPART2 ((t1.deg+t2.deg)/9*2) #define MAXT (d/5) #endif int D3=INFNTY; int FIRST_ROUND=2; // note that num of total rounds = 1+FIRST_ROUND int EARLY_QUIT_CRITERIA=1; #define DEFAULT_QSIZE (3+min(d,1000)) #define USE_HASHING 1 #if USE_HASHING #define new_ht 1 //int new_ht=1; dl_t ht[D2M+1]; // hash table of subtrees indexed by degree #endif unsigned int curr_mark=0; Tree wmergetree(Tree t1, Tree t2, int *order1, int *order2, DTYPE cx, DTYPE cy, int acc); Tree xmergetree(Tree t1, Tree t2, int *order1, int *order2, DTYPE cx, DTYPE cy); void color_tree(Tree t, int *color); int longest_path_edge(int i, int j, int *e, int *p, int *es); void preprocess_edges(int num_edges, int *edges, DTYPE *len, int *e, int *p, int *es); #define init_queue(q) { q[1] = 2; } inline void enqueue(int **q, int e) { int _qsize; if ((*q)[0]==(*q)[1]) { _qsize=2*((*q)[0]+1); (*q)=(int*)realloc((*q), _qsize*sizeof(int)); (*q)[0]=_qsize; } (*q)[(*q)[1]++]=e; } #define MAX_HEAP_SIZE (MAXD*2) DTYPE **hdist; typedef struct node_pair_s { // pair of nodes representing an edge int node1, node2; } node_pair; node_pair *heap; //heap[MAXD*MAXD]; int heap_size=0; int max_heap_size = MAX_HEAP_SIZE; int in_heap_order(int e1, int e2) { if (hdist[heap[e1].node1][heap[e1].node2] < hdist[heap[e2].node1][heap[e2].node2]) { return 1; } else { return 0; } } void sift_up(int i) { node_pair tmp; int j; for (j=i/2; j>=1 && in_heap_order(i, j); i=j, j/=2) { tmp = heap[j]; heap[j] = heap[i]; heap[i] = tmp; } } void sift_down(int i) { int left, right, j; node_pair tmp; left = i*2; right = left+1; while (left <= heap_size) { if (left == heap_size || in_heap_order(left, right)) { j = left; } else { j = right; } if (in_heap_order(j, i)) { tmp = heap[j]; heap[j] = heap[i]; heap[i] = tmp; i = j; left = i*2; right = left+1; } else { break; } } } void insert_heap(node_pair *np) { if (heap_size >= max_heap_size) { max_heap_size *= 2; heap = (node_pair*)realloc(heap, sizeof(node_pair)*(max_heap_size+1)); } heap[++heap_size] = *np; sift_up(heap_size); } void extract_heap(node_pair *np) { // caller has to make sure heap is not empty *np = heap[1]; heap[1] = heap[heap_size--]; sift_down(1); } void init_param() { int i; heap = (node_pair*)malloc(sizeof(node_pair)*(max_heap_size+1)); } Tree reftree; // reference for qsort int cmp_branch(const void *a, const void *b) { int n; DTYPE x1, x2, x3; x1 = reftree.branch[*(int*)a].x; n = reftree.branch[*(int*)a].n; x3 = reftree.branch[n].x; if (x3 < x1) x1=x3; x2 = reftree.branch[*(int*)b].x; n = reftree.branch[*(int*)b].n; x3 = reftree.branch[n].x; if (x3 < x2) x2=x3; return (x1 <= x2) ? -1 : 1; } void update_dist2(Tree t, DTYPE **dist, DTYPE longest, int *host, int *min_node1, int *min_node2, int **nb) { int i, j, m, n, dd, node1, node2, node3, node4, p1, p2, pi, pn; DTYPE min_dist, smallest; DTYPE x1, x2, x3, x4, y1, y2, y3, y4; DTYPE threshold_x, threshold_y; DTYPE md = dist[*min_node1][*min_node2]; #if MR_FOR_SMALL_CASES_ONLY int isPin_base[D2M], *isPin, id[2*D2M]; int u, v, b[D2M*2]; #else int *isPin_base, *isPin, *id; int u, v, *b; isPin_base = (int*)malloc(sizeof(int)*t.deg); id = (int*)malloc(sizeof(int)*t.deg*2); b = (int*)malloc(sizeof(int)*t.deg*2); #endif isPin = &(isPin_base[0]) - t.deg; dd = t.deg*2-2; for (i=0; i=0 || n==i) { continue; } if (id[i] < id[n]) { id[n] = id[i]; } else { id[i] = id[n]; } } for (i=0; ithreshold_x || ADIFF(t.branch[i].y, t.branch[j].y)>threshold_y) continue; m = t.branch[j].n; node3 = host[j]; node4 = host[m]; if (node3 < 0 && node4 < 0) { continue; } if (t.branch[j].x <= t.branch[m].x) { x1 = t.branch[j].x; x2 = t.branch[m].x; } else { x1 = t.branch[m].x; x2 = t.branch[j].x; } if (t.branch[j].y <= t.branch[m].y) { y1 = t.branch[j].y; y2 = t.branch[m].y; } else { y1 = t.branch[m].y; y2 = t.branch[j].y; } if (x2 < x3) { min_dist = x3 - x2; } else if (x4 < x1) { min_dist = x1 - x4; } else { min_dist = 0; } if (min_dist >= threshold_x) { break; } if (y2 < y3) { min_dist += y3 - y2; } else if (y4 < y1) { min_dist += y1 - y4; } if (min_dist >= longest) { continue; } p1 = (node1 < 0) ? node2 : ((node2 < 0) ? node1 : -1); p2 = (node3 < 0) ? node4 : ((node4 < 0) ? node3 : -1); if (p1 >= 0 && p2 < 0) { dist[p1][node3] = ADIFF(t.branch[p1].x, t.branch[node3].x) + ADIFF(t.branch[p1].y, t.branch[node3].y); dist[p1][node4] = ADIFF(t.branch[p1].x, t.branch[node4].x) + ADIFF(t.branch[p1].y, t.branch[node4].y); p2 = (dist[p1][node3] <= dist[p1][node4]) ? node3 : node4; } else if (p1 < 0 && p2 >= 0) { dist[node1][p2] = ADIFF(t.branch[node1].x, t.branch[p2].x) + ADIFF(t.branch[node1].y, t.branch[p2].y); dist[node2][p2] = ADIFF(t.branch[node2].x, t.branch[p2].x) + ADIFF(t.branch[node2].y, t.branch[p2].y); p1 = (dist[node1][p2] <= dist[node2][p2]) ? node1 : node2; } else if (p1 < 0 && p2 < 0) { // all 4 nodes are real, pick the closest pair dist[node1][node3] = ADIFF(t.branch[node1].x, t.branch[node3].x) + ADIFF(t.branch[node1].y, t.branch[node3].y); dist[node1][node4] = ADIFF(t.branch[node1].x, t.branch[node4].x) + ADIFF(t.branch[node1].y, t.branch[node4].y); dist[node2][node3] = ADIFF(t.branch[node2].x, t.branch[node3].x) + ADIFF(t.branch[node2].y, t.branch[node3].y); dist[node2][node4] = ADIFF(t.branch[node2].x, t.branch[node4].x) + ADIFF(t.branch[node2].y, t.branch[node4].y); p1 = node1; p2 = node3; smallest = dist[p1][p2]; if (dist[node2][node3] < smallest) { p1 = node2; smallest = dist[p1][p2]; } if (dist[node1][node4] < smallest) { p1 = node1; p2 = node4; smallest = dist[p1][p2]; } if (dist[node2][node4] < smallest) { p1 = node2; p2 = node4; smallest = dist[p1][p2]; } } else { dist[p1][p2] = ADIFF(t.branch[p1].x, t.branch[p2].x) + ADIFF(t.branch[p1].y, t.branch[p2].y); } if (min_dist < dist[p1][p2]) { dist[p1][p2] = dist[p2][p1] = min_dist; enqueue(&nb[p1], p2); enqueue(&nb[p2], p1); if (min_dist < md) { md = min_dist; *min_node1 = p1; *min_node2 = p2; } } } } #if !(MR_FOR_SMALL_CASES_ONLY) free(isPin_base); free(id); free(b); #endif } void mst_from_heap(int d, DTYPE **dist, int node1, int node2, int **nb, int *edges, int *tree_id) { int i, j, itr, idx; node_pair e; hdist = dist; heap_size=0; for (i=0; i1; j--) { i=nb[node1][j]; if (tree_id[i]) continue; { e.node2 = i; insert_heap(&e); } } for (itr=d-2; itr>=1; itr--) { e.node1 = node2; for (j=nb[node2][1]-1; j>1; j--) { i=nb[node2][j]; if (tree_id[i]) continue; { e.node2 = i; insert_heap(&e); } } do { //assert(heap_size>0); //extract_heap(&e); e = heap[1]; while (tree_id[heap[heap_size].node2]) { heap_size--; } heap[1] = heap[heap_size--]; sift_down(1); node2 = e.node2; } while (tree_id[node2]); node1 = e.node1; tree_id[node2] = tree_id[node1]; edges[idx++] = node1; edges[idx++] = node2; } //assert(idx==2*d-2); } void build_rmst(long d, DTYPE *x, DTYPE *y, int *edges, int *inMST) { int i, j, idx, n; int *map = (int*)calloc(d, sizeof(int)); Point *pt = (Point*)calloc( 4*d, sizeof(Point) ); long *parent = (long*)calloc( 4*d, sizeof(long) ); long *par = (long*)calloc( 4*d, sizeof(long) ); int *size = (int*)calloc(d, sizeof(int)); for (i=0; i=0; j--) { if (pt[j].x==pt[i].x && pt[j].y==pt[i].y && par[j]>=0) { par[i]=j; break; } } } } for (i=0; i=0); size[parent[i]]++; } idx = 2*d-3; for (i=0; i0) { //assert(!inMST[j]); inMST[j] = 1; edges[idx--] = j; edges[idx--] = j = parent[j]; size[j]--; } } //assert(idx==-1); inMST[edges[0]]=1; free(pt); free(map); free(parent); free(par); free(size); } /* cached version */ Tree flutes_c(int d, DTYPE *xs, DTYPE *ys, int *s, int acc) { int i; //int orig_ht_flag; Tree t, tdup; #if USE_HASHING dl_forall(Tree, ht[d], t) { for (i=0; i= d) { // found a match tdup = t; tdup.branch = (Branch*)malloc(sizeof(Branch)*(2*d-2)); for (i=2*d-3; i>=0; i--) { tdup.branch[i] = t.branch[i]; } return tdup; } } dl_endfor; //orig_ht_flag = new_ht; //new_ht = 0; #endif t = flutes_LMD(d, xs, ys, s, acc); #if USE_HASHING //new_ht = orig_ht_flag; tdup = t; tdup.branch = (Branch*)malloc(sizeof(Branch)*(2*d-2)); for (i=2*d-3; i>=0; i--) { tdup.branch[i] = t.branch[i]; } dl_prepend(Tree, ht[d], tdup); #endif return t; } Tree flute_mr(int d, DTYPE *xs, DTYPE *ys, int *s, int acc, int rounds, DTYPE **dist, DTYPE *threshold_x, DTYPE *threshold_y, DTYPE *threshold, int *best_round, int *min_node1, int *min_node2, int **nb) { int i, j, k, m, n, itr, node1, node2; DTYPE min_dist, longest; DTYPE dist1, dist2; Tree t, best_t, *subtree, ttmp; DTYPE min_x, max_x; #if MR_FOR_SMALL_CASES_ONLY int num_subtree, subroot[MAXPART], suproot[MAXPART], isSuperRoot[D2M]; int tree_id[D2M], tid, tree_size[D2M], edges[2*D2M]; int idx[MAXPART], offset[MAXPART], *order[MAXT], order_base[MAXT*D2M]; DTYPE x[D2M+MAXPART], y[D2M+MAXPART]; int new_s[D2M+MAXPART], si[D2M], xmap[D2M+MAXPART]; #else int num_subtree, *subroot, *suproot, *isSuperRoot; int *tree_id, tid, *tree_size, *edges; int *idx, *offset, **order, *order_base; DTYPE *x, *y; int *new_s, *si, *xmap; subroot = (int*)malloc(sizeof(int)*MAXPART); suproot = (int*)malloc(sizeof(int)*MAXPART); idx = (int*)malloc(sizeof(int)*MAXPART); offset = (int*)malloc(sizeof(int)*MAXPART); order = (int**)malloc(sizeof(int*)*MAXT); isSuperRoot = (int*)malloc(sizeof(int)*d); tree_id = (int*)malloc(sizeof(int)*d); tree_size = (int*)malloc(sizeof(int)*d); edges = (int*)malloc(sizeof(int)*d*2); order_base = (int*)malloc(sizeof(int)*d*MAXT); new_s = (int*)malloc(sizeof(int)*(d+MAXPART)); si = (int*)malloc(sizeof(int)*d); xmap = (int*)malloc(sizeof(int)*(d+MAXPART)); x = (DTYPE*)malloc(sizeof(DTYPE)*(d+MAXPART)); y = (DTYPE*)malloc(sizeof(DTYPE)*(d+MAXPART)); #endif #if USE_HASHING if (new_ht) { for (i=0; i<=d; i++) { ht[i] = dl_alloc(); } } #endif best_t.branch = NULL; best_t.length = INFNTY; for (i=0; i=0) { for (i=0; i=0; ) { node2 = edges[i--]; node1 = edges[i--]; j = tree_size[node1]+tree_size[node2]; //Chris if (j >= TAU(acc)) { isSuperRoot[node1] = 1; suproot[num_subtree] = node1; subroot[num_subtree++] = node2; } else { tree_size[node1] = j; } } //assert(num_subtree<=MAXT); for (i=1; i= EARLY_QUIT_CRITERIA) { if (t.branch) { free(t.branch); } break; } } else if (best_t.length == t.length) { *best_round = rounds; } else if (best_t.length > t.length) { if (best_t.branch) { free(best_t.branch); } best_t = t; *best_round = rounds; } if (rounds > 0) { for (i=0; i=0; ) { node2 = edges[i--]; node1 = edges[i--]; j = tree_size[node1]+tree_size[node2]; //if (j >= d/2) { if (j >= d/2 && num_subtree<2) { isSuperRoot[node1] = 1; suproot[num_subtree] = node1; subroot[num_subtree++] = node2; } else { tree_size[node1] = j; } } */ for (i=2*d-3; i>=0; ) { node2 = edges[i--]; node1 = edges[i--]; tree_size[node1] += tree_size[node2]; } j = 0; smallest_gap = ADIFF(tree_size[j], d/2); for (i=1; i=0; ) { node2 = edges[i--]; node1 = edges[i--]; if (node2==j) { isSuperRoot[node1] = 1; suproot[num_subtree] = node1; subroot[num_subtree++] = node2; tree_size[subroot[0]] -= tree_size[j]; break; } } //assert(num_subtree<=MAXT); for (i=1; i= INFNTY && d > 1000) { D3 = (d <= 10000) ? 1000 : 10000; } t = flute_am(d, xs, ys, s, A, &threshold_x, &threshold_y, &threshold); if (orig_D3 >= INFNTY) { D3 = orig_D3; } } return t; } int pickWin(Tree t, DTYPE cx, DTYPE cy, int inWin[]) { #if MR_FOR_SMALL_CASES_ONLY int i, j, n, dd, cnt, stack[D2M*2], top=0, prev, curr, next; int isPin_base[D2M], *isPin, nghbr_base[D2M], *nghbr, q[2*D2M]; #else int i, j, n, dd, cnt, *stack, top=0, prev, curr, next; int *isPin_base, *isPin, *nghbr_base, *nghbr, *q; stack = (int*)malloc(sizeof(int)*t.deg*2); isPin_base = (int*)malloc(sizeof(int)*t.deg); nghbr_base = (int*)malloc(sizeof(int)*t.deg); q = (int*)malloc(sizeof(int)*t.deg*2); #endif if (t.deg <= 3) { for (i=0; i 0); while (top > 0) { i = stack[--top]; if (inWin[i]) { continue; } inWin[i] = 1; if (i < t.deg) { cnt++; continue; } n = isPin[i]; if (n >= 0) { if (!inWin[n]) { inWin[n] = 1; cnt++; } } else { stack[top++] = t.branch[i].n; for (j=nghbr[i]; j0); #if !(MR_FOR_SMALL_CASES_ONLY) free(stack); free(isPin_base); free(nghbr_base); free(q); #endif return cnt; } /* merge tree t2 into tree t1, which have shared common nodes. The intention is to add the non-common tree nodes of t2 into t1, as well as the associated steiner nodes */ Tree merge_into(Tree t1, Tree t2, int common[], int nc, int *o1, int *o2) { Tree t; DTYPE cx, cy; #if MR_FOR_SMALL_CASES_ONLY int i, j, k, d, n, offset, map[2*D2M], reachable[2*D2M]; int o[D2M+MAXPART]; #else int i, j, k, d, n, offset, *map, *reachable; int *o; map = (int*)malloc(sizeof(int)*(t1.deg+t2.deg)*2); reachable = (int*)malloc(sizeof(int)*(t1.deg+t2.deg)*2); o = (int*)malloc(sizeof(int)*(t1.deg+t2.deg+MAXPART2)); #endif if (t2.deg <= nc) { free(t2.branch); #if !(MR_FOR_SMALL_CASES_ONLY) free(map); free(reachable); free(o); #endif return t1; } t.deg = t1.deg + t2.deg - nc; t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch)); offset = t2.deg - nc; for (i=t1.deg; i=0; i--) { if (!common[i] && t2.branch[i].n!=i) { reachable[t2.branch[i].n] = 1; } } for (i=2*t2.deg-3; i>=0; i--) { map[i] = -1; } d = t1.deg*2 - 2; /* a slow method; could be sped up here */ for (i=0; i=t2.deg) { for (; i=t1.deg) { for (; k=t1.deg); t.branch[j].n = map[n] + offset; o[j] = o2[k]; j++; } } else if (o1[i] < o2[k]) { t.branch[j] = t1.branch[i]; t.branch[j].n = t1.branch[i].n + offset; o[j] = o1[i]; j++; i++; } else { t.branch[j] = t2.branch[k]; n = t2.branch[k].n; //assert(map[n]>=t1.deg); t.branch[j].n = map[n] + offset; o[j] = o2[k]; j++; do { k++; } while (k=t1.deg); t.branch[map[i]+offset].n = map[n] + offset; j++; } } j = d+offset; //assert(j <= t.deg*2-2); while (j < t.deg*2-2) { /* redundant steiner nodes */ t.branch[j] = t2.branch[0]; t.branch[j].n = j; j++; } /* for (i=0; i=t.deg); } */ t.length = wirelength(t); free(t1.branch); free(t2.branch); #if !(MR_FOR_SMALL_CASES_ONLY) free(map); free(reachable); free(o); #endif return t; } /* simply merge two trees at their common node */ Tree smergetree(Tree t1, Tree t2, int *o1, int *o2, DTYPE cx, DTYPE cy) { Tree t; int d, i, j, k, n, ci, cn, mapped_cn, prev, curr, next, offset; #if MR_FOR_SMALL_CASES_ONLY int o[D2M+MAXPART], map[2*D2M]; #else int *o, *map; map = (int*)malloc(sizeof(int)*(t1.deg+t2.deg)*2); o = (int*)malloc(sizeof(int)*(t1.deg+t2.deg+MAXPART2)); #endif t.deg = t1.deg + t2.deg - 1; t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch)); offset = t2.deg - 1; d = t1.deg*2-2; for (i=0; i=t2.deg) { for (; i=t1.deg) { for (; k2 && t2.deg>2) { if (d= t2.deg) { for (; i1= t1.deg) { for (; i2 2) { for (i=0; i0) { dl_pop_first(TreeNode*, subtree, p); p->e = p; grandp = p->parent; if (grandp) { p->len = p->blen = ADIFF(p->x, grandp->x) + ADIFF(p->y, grandp->y); if (p->len < grandp->len) { p->len = grandp->len; p->e = grandp->e; } } else { p->len = 0; } if (id) { p->id = id; } dl_forall(TreeNode*, p->children, child) { dl_prepend(TreeNode*, subtree, child); } dl_endfor; } dl_free(subtree); } TreeNode *createRootedTree(Tree t, int *order, int id, dl_t list_of_nodes) { int i, dd, n; TreeNode *root=0, **nodes, *p; dd = t.deg*2-2; nodes = (TreeNode**)malloc(sizeof(TreeNode*)*dd); for (i=0; imark = curr_mark; nodes[i]->children = dl_alloc(); } curr_mark++; for (i=0; imark = curr_mark; n = t.branch[i].n; if (i==n) { if (i < t.deg) { //assert(root==0); nodes[i]->parent = 0; root = nodes[i]; } else { /* must be redundant */ dl_free(nodes[i]->children); free(nodes[i]); nodes[i] = 0; continue; } } else { p = nodes[n]; nodes[i]->parent = p; dl_append(TreeNode*, p->children, nodes[i]); } nodes[i]->order = (i < t.deg) ? order[i] : -1; nodes[i]->id = id; nodes[i]->x = t.branch[i].x; nodes[i]->y = t.branch[i].y; /* len will be computed in update_subtree nodes[i]->blen = ADIFF(t.branch[i].x, t.branch[n].x)+ADIFF(t.branch[i].y, t.branch[n].y); nodes[i]->e = nodes[i]; nodes[i]->len = ADIFF(t.branch[i].x, t.branch[n].x)+ADIFF(t.branch[i].y, t.branch[n].y); */ dl_append(TreeNode*, list_of_nodes, nodes[i]); } //assert(root); update_subtree(root, 0); for (i=0; imark!=curr_mark) { dl_free(nodes[i]->children); free(nodes[i]); } } free(nodes); return root; } void freeTree(TreeNode *t) { TreeNode *child; dl_forall(TreeNode *, t->children, child) { freeTree(child); } dl_endfor; dl_free(t->children); free(t); } int cmpNodeByYX(const void* a, const void* b) { DTYPE ay = (*(TreeNode**)a)->y; DTYPE by = (*(TreeNode**)b)->y; DTYPE ax, bx; if (ay < by) return -1; if (ay > by) return 1; ax = (*(TreeNode**)a)->x; bx = (*(TreeNode**)b)->x; if (ax < bx) return -1; if (ax > bx) return 1; return 0; } int cmpNodeByXY(const void* a, const void* b) { DTYPE ax = (*(TreeNode**)a)->x; DTYPE bx = (*(TreeNode**)b)->x; DTYPE ay, by; if (ax < bx) return -1; if (ax > bx) return 1; ay = (*(TreeNode**)a)->y; by = (*(TreeNode**)b)->y; if (ay < by) return -1; if (ay > by) return 1; return 0; } void remove_child(dl_t children_list, TreeNode* c) { TreeNode *child; dl_forall(TreeNode*, children_list, child) { if (child==c) { dl_delete_current(); break; } } dl_endfor; } void cleanTree(TreeNode* tn) { /* TreeNode *c, *p; dl_forall(TreeNode*, tn->children, c) { cleanTree(c); } dl_endfor; p = tn->parent; if (!p) return; if (tn->order >= 0) return; // don't clean pin nodes if (dl_length(tn->children)<=0) { remove_child(p->children, tn); dl_free(tn->children); free(tn); } else if (dl_length(tn->children)<=1) { c = dl_first(TreeNode*, tn->children); c->parent = p; dl_append(TreeNode*, p->children, c); remove_child(p->children, tn); dl_free(tn->children); free(tn); } */ // non-recursive version TreeNode *c, *p; dl_t nlist=dl_alloc(); dl_append(TreeNode*, nlist, tn); while (dl_length(nlist)>0) { dl_pop_first(TreeNode*, nlist, tn); dl_forall(TreeNode*, tn->children, c) { dl_append(TreeNode*, nlist, c); } dl_endfor; p = tn->parent; if (p && tn->order < 0) { if (dl_length(tn->children)<=0) { remove_child(p->children, tn); dl_free(tn->children); free(tn); } else if (dl_length(tn->children)<=1) { c = dl_first(TreeNode*, tn->children); c->parent = p; dl_append(TreeNode*, p->children, c); remove_child(p->children, tn); dl_free(tn->children); free(tn); } } } dl_free(nlist); } int cmpNodeByOrder(void* a, void* b) { int ax = (*(TreeNode**)a)->order; int bx = (*(TreeNode**)b)->order; if (ax < bx) return -1; if (ax > bx) return 1; return 0; } Tree mergeRootedTrees(TreeNode *tn1, TreeNode *tn2, int *order1) { int i, n, redundant; Tree t; TreeNode *child, *p; dl_t list_of_nodes=dl_alloc(); dl_t pin_nodes=dl_alloc(), steiner_nodes=dl_alloc(); //assert(tn1->x==tn2->x && tn1->y==tn2->y); /* merge tn2 to tn1 */ while (dl_length(tn2->children)>0) { dl_pop_first(TreeNode*, tn2->children, child); child->parent = tn1; dl_append(TreeNode*, tn1->children, child); } dl_free(tn2->children); free(tn2); cleanTree(tn1); /* convert tn1 back to a Tree */ dl_append(TreeNode*, list_of_nodes, tn1); do { dl_pop_first(TreeNode*, list_of_nodes, child); if (child->order < 0) { if (dl_length(child->children)==1) { /* redundant steiner node */ p = dl_first(TreeNode*, child->children); p->parent = child->parent; /* note that p->parent's children list is already gone */ dl_append(TreeNode*, list_of_nodes, p); dl_free(child->children); free(child); continue; } else if (dl_length(child->children)==0) { dl_free(child->children); free(child); continue; } dl_append(TreeNode*, steiner_nodes, child); } else { dl_append(TreeNode*, pin_nodes, child); } dl_concat(list_of_nodes, child->children); } while (dl_length(list_of_nodes)>0); dl_free(list_of_nodes); dl_sort(pin_nodes, sizeof(TreeNode*), cmpNodeByOrder); i=0; dl_forall(TreeNode*, pin_nodes, child) { child->id = i++; } dl_endfor; t.deg = i; dl_forall(TreeNode*, steiner_nodes, child) { child->id = i++; } dl_endfor; //assert(i<=2*t.deg-2); t.branch = (Branch*)malloc(sizeof(Branch)*(t.deg*2-2)); redundant = i; for (; i<2*t.deg-2; i++) { t.branch[i].n = i; t.branch[i].x = tn1->x; t.branch[i].y = tn1->y; } t.branch[tn1->id].n = -1; dl_forall(TreeNode*, pin_nodes, child) { i = child->id; if (child->order >= 0) { order1[i] = child->order; } t.branch[i].x = child->x; t.branch[i].y = child->y; p = child->parent; if (p) { if (p->id >= t.deg) { t.branch[i].n = p->id; } else { //assert(p==tn1); //assert(redundantid].n = redundant; t.branch[redundant].x = p->x; t.branch[redundant].y = p->y; redundant++; } } } dl_endfor; dl_forall(TreeNode*, steiner_nodes, child) { i = child->id; if (child->order >= 0) { order1[i] = child->order; } t.branch[i].x = child->x; t.branch[i].y = child->y; p = child->parent; if (p->id < t.deg) { // must be the root if (t.branch[p->id].n < 0) { t.branch[p->id].n = i; t.branch[i].n = i; } else { n = t.branch[p->id].n; if (t.branch[p->id].x==t.branch[n].x && t.branch[p->id].y==t.branch[n].y) { t.branch[i].n = n; } else { //assert(redundantid].x; t.branch[redundant].y = t.branch[p->id].y; t.branch[redundant].n = t.branch[p->id].n; t.branch[p->id].n = redundant; t.branch[i].n = redundant; redundant++; } } } else { t.branch[i].n = p->id; } } dl_endfor; dl_forall(TreeNode*, pin_nodes, child) { free(child); } dl_endfor; dl_free(pin_nodes); dl_forall(TreeNode*, steiner_nodes, child) { free(child); } dl_endfor; dl_free(steiner_nodes); t.length = wirelength(t); return t; } void collect_nodes(TreeNode* tn, dl_t nlist) { /* TreeNode* c; dl_append(TreeNode*, nlist, tn); dl_forall(TreeNode*, tn->children, c) { collect_nodes(c, nlist); }dl_endfor; */ // non-recursive version TreeNode* c; dl_el *curr; dl_append(TreeNode*, nlist, tn); for (curr=nlist->last; curr; curr=curr->next) { tn = dl_data(TreeNode*, curr); dl_forall(TreeNode*, tn->children, c) { dl_append(TreeNode*, nlist, c); }dl_endfor; } } typedef struct { TreeNode *n1, *n2; DTYPE new_x, new_y, gain; } xdata; int cmpXdata(void *a, void *b) { DTYPE ga = (*(xdata*)a).gain; DTYPE gb = (*(xdata*)b).gain; if (ga > gb) return -1; if (ga < gb) return 1; return 0; } inline TreeNode *cedge_lca(TreeNode* n1, TreeNode* n2, DTYPE *len, int *n2ton1) { int i; TreeNode *curr, *lca, *e; curr_mark++; curr = n1; while (curr) { curr->mark = curr_mark; curr = curr->parent; } lca = n2; while (lca && lca->mark!=curr_mark) { lca->mark = curr_mark; lca = lca->parent; } if (!lca) { n1 = n1->parent; if (n1 && n1!=lca && (n1->len > n2->len)) { *n2ton1 = 0; *len = n1->len; return n1->e; } else { *n2ton1 = 1; *len = n2->len; return n2->e; } } if (lca==n1 || lca==n1->parent || lca==n2) { if (lca!=n2) { *n2ton1 = 1; *len = n2->blen; e = n2; curr = n2->parent; } else { *n2ton1 = 0; *len = n1->blen; e = n1; curr = n1->parent; } while (curr != lca) { if (*len < curr->blen) { *len = curr->blen; e = curr; } curr = curr->parent; } return e; } /* lca is above both n1 and n2 */ *n2ton1 = 0; n1 = n1->parent; *len = n1->blen; e = n1; curr = n1; for (i=0; i<2; i++, curr=n2) { while (curr != lca) { if (*len < curr->blen) { if (i>0) { *n2ton1 = 1; } *len = curr->blen; e = curr; } curr = curr->parent; } } return e; } TreeNode *critical_edge(TreeNode* n1, TreeNode* n2, DTYPE *len, int *n2ton1) { if (n1->id != n2->id) { n1 = n1->parent; if (n1 && (n1->len > n2->len)) { *n2ton1 = 0; *len = n1->len; return n1->e; } else { *n2ton1 = 1; *len = n2->len; return n2->e; } } return cedge_lca(n1, n2, len, n2ton1); } void splice2(TreeNode *n1, TreeNode *n2, TreeNode *e) { TreeNode *curr, *prev, *next, *s; //assert(n2->parent); //assert(e->id==n2->id); prev = n2; curr = n2->parent; next = curr->parent; while (prev != e) { remove_child(curr->children, prev); curr->parent = prev; dl_append(TreeNode*, prev->children, curr); prev = curr; curr = next; next = curr->parent; } remove_child(curr->children, prev); n2->parent = n1; dl_append(TreeNode*, n1->children, n2); update_subtree(n1, n1->parent->id); } void cut_and_splice(TreeNode *n1, TreeNode *n2, DTYPE new_x, DTYPE new_y, DTYPE *x1, DTYPE *y1, DTYPE *x2, DTYPE *y2, TreeNode *e, int n2ton1) { TreeNode *p1, *node, *s; /* new steiner node */ p1 = n1->parent; remove_child(p1->children, n1); node = (TreeNode*)malloc(sizeof(TreeNode)); node->x = new_x; node->y = new_y; node->mark = curr_mark; node->parent = p1; dl_append(TreeNode*, p1->children, node); n1->parent = node; node->children = dl_alloc(); dl_append(TreeNode*, node->children, n1); node->order = -1; node->e = n1->e; node->id = n1->id; if (*x1==n1->x) { *x2 = new_x; } else { *x1 = new_x; } if (*y1==n1->y) { *y2 = new_y; } else { *y1 = new_y; } if (n2->order >= 0) { /* n2 is a pin, need to replicate a steiner node */ s = n2->parent; if (s->x!=n2->x || s->y!=n2->y) { s = (TreeNode*)malloc(sizeof(TreeNode)); s->mark = curr_mark; s->order = -1; s->id = n2->id; s->x = n2->x; s->y = n2->y; s->e = n2->e; if (s->e == n2) { s->e = s; } if (e == n2) { e = s; } s->len = n2->len; s->blen = n2->blen; n2->blen = 0; remove_child(n2->parent->children, n2); dl_append(TreeNode*, n2->parent->children, s); s->parent = n2->parent; n2->parent = s; s->children = dl_alloc(); dl_append(TreeNode*, s->children, n2); } n2 = s; } if (n2ton1) { splice2(node, n2, e); } else { splice2(n2, node, e); } } typedef struct { TreeNode *n1, *n2; DTYPE min_dist, new_x, new_y; int n2ton1; } splice_info; DTYPE exchange_branches_order_x(int num_nodes, TreeNode **nodes, DTYPE threshold_x, DTYPE threshold_y, DTYPE max_len) { int n2ton1; TreeNode *n1, *p1, *n2, *p2, *node, *e, *s; DTYPE x1, x2, y1, y2, min_dist, new_x, new_y, len; DTYPE gain=0; int i, j, curr_row, next_header, num_rows, start, end, mid; int *header=(int*)malloc(sizeof(int)*(num_nodes+1)); dl_t batch_list=dl_alloc(); splice_info sinfo; int batch_mode = (num_nodes >= D3); header[0]=0; y1 = nodes[0]->y; for (i=num_rows=1; iy == y1) { continue; } header[num_rows++] = i; y1 = nodes[i]->y; } header[num_rows] = i; curr_row = 0; next_header = header[1]; for (i=0; i= next_header) { curr_row++; next_header = header[curr_row+1]; } n1 = nodes[i]; p1 = n1->parent; if (!p1) { continue; } if (p1->x == n1->x && p1->y == n1->y) { continue; } if (n1->x <= p1->x) { x1 = n1->x; x2 = p1->x; } else { x1 = p1->x; x2 = n1->x; } if (n1->y <= p1->y) { y1 = n1->y; y2 = p1->y; } else { y1 = p1->y; y2 = n1->y; } if (curr_row > 0) { for (j=curr_row-1; j>0; j--) { if (y1 - threshold_y > nodes[header[j]]->y) { j++; break; } } } else { j = 0; } for (;j < num_rows && nodes[header[j]]->y <= y2 + threshold_y; j++) { /* find the closest node on row j */ start = header[j]; end = header[j+1]; while (start < end) { mid = (start+end)/2; if (nodes[mid]->x <= x1) { start = mid + 1; } else { end = mid; } } //assert(start==end); if (start >= header[j+1]) { continue; } n2 = nodes[start]; if (batch_mode && n1->id==n2->id) continue; if (!n2->parent) { continue; } min_dist = n2->x - x2; if (abs(min_dist) > threshold_x) { continue; } else if (min_dist < 0) { min_dist = 0; new_x = n2->x; } else { new_x = x2; } if (n2->y < y1) { min_dist += y1 - n2->y; new_y = y1; } else if (n2->y > y2) { min_dist += n2->y - y2; new_y = y2; } else { new_y = n2->y; } if (min_dist ==0 || min_dist > max_len) { continue; } e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { if (batch_mode) { sinfo.n1 = n1; sinfo.n2 = n2; sinfo.min_dist = min_dist; sinfo.new_x = new_x; sinfo.new_y = new_y; sinfo.n2ton1 = n2ton1; dl_append(splice_info, batch_list, sinfo); } else { gain += len - min_dist; cut_and_splice(n1, n2, new_x, new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } } } dl_forall(splice_info, batch_list, sinfo) { n1 = sinfo.n1; n2 = sinfo.n2; n2ton1 = sinfo.n2ton1; min_dist = sinfo.min_dist; e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { gain += len - min_dist; cut_and_splice(n1, n2, sinfo.new_x, sinfo.new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } dl_endfor; dl_free(batch_list); free(header); return gain; } DTYPE exchange_branches_order_y(int num_nodes, TreeNode **nodes, DTYPE threshold_x, DTYPE threshold_y, DTYPE max_len) { int n2ton1; TreeNode *n1, *p1, *n2, *p2, *node, *e, *s; DTYPE x1, x2, y1, y2, min_dist, new_x, new_y, len; DTYPE gain=0; int i, j, curr_row, next_header, num_rows, start, end, mid; int *header=(int*)malloc(sizeof(int)*(num_nodes+1)); dl_t batch_list=dl_alloc(); splice_info sinfo; int batch_mode = (num_nodes >= D3); header[0]=0; x1 = nodes[0]->x; for (i=num_rows=1; ix == x1) { continue; } header[num_rows++] = i; x1 = nodes[i]->x; } header[num_rows] = i; curr_row = 0; next_header = header[1]; for (i=0; i= next_header) { curr_row++; next_header = header[curr_row+1]; } n1 = nodes[i]; p1 = n1->parent; if (!p1) { continue; } if (p1->x == n1->x && p1->y == n1->y) { continue; } if (n1->x <= p1->x) { x1 = n1->x; x2 = p1->x; } else { x1 = p1->x; x2 = n1->x; } if (n1->y <= p1->y) { y1 = n1->y; y2 = p1->y; } else { y1 = p1->y; y2 = n1->y; } if (curr_row > 0) { for (j=curr_row-1; j>0; j--) { if (x1 - threshold_x > nodes[header[j]]->x) { j++; break; } } } else { j = 0; } for (;j < num_rows && nodes[header[j]]->x <= x2 + threshold_x; j++) { /* find the closest node on row j */ start = header[j]; end = header[j+1]; while (start < end) { mid = (start+end)/2; if (nodes[mid]->y <= y1) { start = mid + 1; } else { end = mid; } } //assert(start==end); if (start >= header[j+1]) { continue; } n2 = nodes[start]; if (batch_mode && n1->id==n2->id) continue; if (!n2->parent) { continue; } min_dist = n2->y - y2; if (abs(min_dist) > threshold_y) { continue; } else if (min_dist < 0) { min_dist = 0; new_y = n2->y; } else { new_y = y2; } if (n2->x < x1) { min_dist += x1 - n2->x; new_x = x1; } else if (n2->x > x2) { min_dist += n2->x - x2; new_x = x2; } else { new_x = n2->x; } if (min_dist ==0 || min_dist > max_len) { continue; } e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { if (batch_mode) { sinfo.n1 = n1; sinfo.n2 = n2; sinfo.min_dist = min_dist; sinfo.new_x = new_x; sinfo.new_y = new_y; sinfo.n2ton1 = n2ton1; dl_append(splice_info, batch_list, sinfo); } else { gain += len - min_dist; cut_and_splice(n1, n2, new_x, new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } } } dl_forall(splice_info, batch_list, sinfo) { n1 = sinfo.n1; n2 = sinfo.n2; n2ton1 = sinfo.n2ton1; min_dist = sinfo.min_dist; e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { gain += len - min_dist; cut_and_splice(n1, n2, sinfo.new_x, sinfo.new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } dl_endfor; dl_free(batch_list); free(header); return gain; } /* cross exchange branches after merging */ Tree xmergetree(Tree t1, Tree t2, int *order1, int *order2, DTYPE cx, DTYPE cy) { int i, num, cnt, order_by_x=1; Tree t; TreeNode *tn1, *tn2, *n1, *p1, **nodes; dl_t list_of_nodes=dl_alloc(); DTYPE threshold_x, threshold_y; DTYPE min_x, max_x, max_len, len, gain; if (t1.deg <= 0) { for (i=0; ix; for (i=0; iparent; if (p1) { len = ADIFF(n1->x, p1->x) + ADIFF(n1->y, p1->y); if (len > max_len) { max_len = len; } } if (n1->x < min_x) { min_x = n1->x; } else if (n1->x > max_x) { max_x = n1->x; } } threshold_x = (max_x - min_x)/4; threshold_y = (nodes[num-1]->y - nodes[0]->y)/4; threshold_x = min(threshold_x, max_len); threshold_y = min(threshold_y, max_len); for (cnt=(t1.deg+t2.deg)/2; cnt>0; cnt--) { gain = (order_by_x) ? exchange_branches_order_x(num, nodes, threshold_x, threshold_y, max_len): exchange_branches_order_y(num, nodes, threshold_x, threshold_y, max_len); //assert(gain>=0); if (gain <= 0 && !order_by_x) { break; } if (cnt>1) { collect_nodes(tn1, list_of_nodes); num = dl_length(list_of_nodes); if (num <= 1) { break; } collect_nodes(tn2, list_of_nodes); if (dl_length(list_of_nodes)-num <= 1) { break; } free(nodes); num = dl_length(list_of_nodes); nodes = (TreeNode**)malloc(sizeof(TreeNode*)*num); i = 0; dl_forall(TreeNode*, list_of_nodes, n1) { nodes[i++] = n1; } dl_endfor; dl_clear(list_of_nodes); if (order_by_x) { order_by_x = 0; qsort(nodes, num, sizeof(TreeNode*), cmpNodeByXY); } else { order_by_x = 1; qsort(nodes, num, sizeof(TreeNode*), cmpNodeByYX); } } } dl_free(list_of_nodes); free(nodes); t = mergeRootedTrees(tn1, tn2, order1); free(t1.branch); free(t2.branch); return t; } } // Flute namespace.