Xplace_for_ICCAD/thirdparty/flute/flute.cpp

1470 lines
43 KiB
C++
Raw Permalink Normal View History

2022-10-20 22:46:17 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include "flute.h"
namespace Flute {
#define D 9
#if D<=7
#define MGROUP 5040/4 // Max. # of groups, 7! = 5040
#define MPOWV 15 // Max. # of POWVs per group
#elif D==8
#define MGROUP 40320/4 // Max. # of groups, 8! = 40320
#define MPOWV 33 // Max. # of POWVs per group
#elif D==9
#define MGROUP 362880/4 // Max. # of groups, 9! = 362880
#define MPOWV 79 // Max. # of POWVs per group
#endif
int numgrp[10]={0,0,0,0,6,30,180,1260,10080,90720};
struct csoln
{
unsigned char parent;
unsigned char seg[11]; // Add: 0..i, Sub: j..10; seg[i+1]=seg[j-1]=0
unsigned char rowcol[9-2]; // row = rowcol[]/16, col = rowcol[]%16,
unsigned char neighbor[2*9-2];
};
struct csoln *LUT[9+1][MGROUP]; // storing 4 .. D
int numsoln[9+1][MGROUP];
struct point
{
DTYPE x, y;
int o;
};
void readLUT(std::string FLUTE_POWVFILE, std::string FLUTE_POSTFILE);
DTYPE flute_wl(int d, DTYPE x[], DTYPE y[], int acc);
DTYPE flutes_wl_LD(int d, DTYPE xs[], DTYPE ys[], int s[]);
DTYPE flutes_wl_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc);
DTYPE flutes_wl_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc);
Tree flute(int d, DTYPE x[], DTYPE y[], int acc);
Tree flutes_LD(int d, DTYPE xs[], DTYPE ys[], int s[]);
Tree flutes_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc);
Tree flutes_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc);
Tree dmergetree(Tree t1, Tree t2);
Tree hmergetree(Tree t1, Tree t2, int s[]);
Tree vmergetree(Tree t1, Tree t2);
void local_refinement(Tree *tp, int p);
DTYPE wirelength(Tree t);
void printtree(Tree t);
void plottree(Tree t);
void readLUT(std::string FLUTE_POWVFILE, std::string FLUTE_POSTFILE)
{
unsigned char charnum[256], line[32], *linep, c;
FILE *fpwv, *fprt;
struct csoln *p;
int d, i, j, k, kk, ns, nn;
init_param();
for (i=0; i<=255; i++) {
if ('0'<=i && i<='9')
charnum[i] = i - '0';
else if (i>='A')
charnum[i] = i - 'A' + 10;
else // if (i=='$' || i=='\n' || ... )
charnum[i] = 0;
}
fpwv=fopen(FLUTE_POWVFILE.c_str(), "r");
if (fpwv == NULL) {
printf("Error in opening %s\n", FLUTE_POWVFILE.c_str());
exit(1);
}
#if FLUTE_ROUTING==1
fprt=fopen(FLUTE_POSTFILE.c_str(), "r");
if (fprt == NULL) {
printf("Error in opening %s\n", FLUTE_POSTFILE.c_str());
exit(1);
}
#endif
int status_code; // useles, just to stop compile warning
for (d=4; d<=D; d++) {
status_code = fscanf(fpwv, "d=%d\n", &d);
#if FLUTE_ROUTING==1
status_code = fscanf(fprt, "d=%d\n", &d);
#endif
for (k=0; k<numgrp[d]; k++) {
ns = (int) charnum[fgetc(fpwv)];
if (ns==0) { // same as some previous group
status_code = fscanf(fpwv, "%d\n", &kk);
numsoln[d][k] = numsoln[d][kk];
LUT[d][k] = LUT[d][kk];
}
else {
fgetc(fpwv); // '\n'
numsoln[d][k] = ns;
p = (struct csoln*) malloc(ns*sizeof(struct csoln));
LUT[d][k] = p;
for (i=1; i<=ns; i++) {
linep = (unsigned char *) fgets((char *) line, 32, fpwv);
p->parent = charnum[*(linep++)];
j = 0;
while ((p->seg[j++] = charnum[*(linep++)]) != 0) ;
j = 10;
while ((p->seg[j--] = charnum[*(linep++)]) != 0) ;
#if FLUTE_ROUTING==1
nn = 2*d-2;
status_code = fread(line, 1, d-2, fprt); linep=line;
for (j=d; j<nn; j++) {
c = charnum[*(linep++)];
p->rowcol[j-d] = c;
}
status_code = fread(line, 1, nn/2+1, fprt); linep=line; // last char \n
for (j=0; j<nn; ) {
c = *(linep++);
p->neighbor[j++] = c/16;
p->neighbor[j++] = c%16;
}
#endif
p++;
}
}
}
}
}
DTYPE flute_wl(int d, DTYPE x[], DTYPE y[], int acc)
{
DTYPE xs[FLUTE_MAXD], ys[FLUTE_MAXD], minval, l, xu, xl, yu, yl;
int s[FLUTE_MAXD];
int i, j, k, minidx;
struct point pt[FLUTE_MAXD], *ptp[FLUTE_MAXD], *tmpp;
if (d==2)
l = ADIFF(x[0], x[1]) + ADIFF(y[0], y[1]);
else if (d==3) {
if (x[0] > x[1]) {
xu = flute_max(x[0], x[2]);
xl = flute_min(x[1], x[2]);
}
else {
xu = flute_max(x[1], x[2]);
xl = flute_min(x[0], x[2]);
}
if (y[0] > y[1]) {
yu = flute_max(y[0], y[2]);
yl = flute_min(y[1], y[2]);
}
else {
yu = flute_max(y[1], y[2]);
yl = flute_min(y[0], y[2]);
}
l = (xu-xl) + (yu-yl);
}
else {
for (i=0; i<d; i++) {
pt[i].x = x[i];
pt[i].y = y[i];
ptp[i] = &pt[i];
}
// sort x
for (i=0; i<d-1; i++) {
minval = ptp[i]->x;
minidx = i;
for (j=i+1; j<d; j++) {
if (minval > ptp[j]->x) {
minval = ptp[j]->x;
minidx = j;
}
}
tmpp = ptp[i];
ptp[i] = ptp[minidx];
ptp[minidx] = tmpp;
}
#if FLUTE_REMOVE_DUPLICATE_PIN==1
ptp[d] = &pt[d];
ptp[d]->x = ptp[d]->y = -999999;
j = 0;
for (i=0; i<d; i++) {
for (k=i+1; ptp[k]->x == ptp[i]->x; k++)
if (ptp[k]->y == ptp[i]->y) // pins k and i are the same
break;
if (ptp[k]->x != ptp[i]->x)
ptp[j++] = ptp[i];
}
d = j;
#endif
for (i=0; i<d; i++) {
xs[i] = ptp[i]->x;
ptp[i]->o = i;
}
// sort y to find s[]
for (i=0; i<d-1; i++) {
minval = ptp[i]->y;
minidx = i;
for (j=i+1; j<d; j++) {
if (minval > ptp[j]->y) {
minval = ptp[j]->y;
minidx = j;
}
}
ys[i] = ptp[minidx]->y;
s[i] = ptp[minidx]->o;
ptp[minidx] = ptp[i];
}
ys[d-1] = ptp[d-1]->y;
s[d-1] = ptp[d-1]->o;
l = flutes_wl(d, xs, ys, s, acc);
}
return l;
}
// xs[] and ys[] are coords in x and y in sorted order
// s[] is a list of nodes in increasing y direction
// if nodes are indexed in the order of increasing x coord
// i.e., s[i] = s_i as defined in paper
// The points are (xs[s[i]], ys[i]) for i=0..d-1
// or (xs[i], ys[si[i]]) for i=0..d-1
DTYPE flutes_wl_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc)
{
int i, j, ss;
for (i=0; i<d-1; i++) {
if (xs[s[i]]==xs[s[i+1]] && ys[i]==ys[i+1]) {
if (s[i] < s[i+1])
ss = s[i+1];
else {
ss = s[i];
s[i] = s[i+1];
}
for (j=i+2; j<d; j++) {
ys[j-1] = ys[j];
s[j-1] = s[j];
}
for (j=ss+1; j<d; j++)
xs[j-1] = xs[j];
for (j=0; j<=d-2; j++)
if (s[j] > ss) s[j]--;
i--;
d--;
}
}
return flutes_wl_ALLD(d, xs, ys, s, acc);
}
// For low-degree, i.e., 2 <= d <= D
DTYPE flutes_wl_LD(int d, DTYPE xs[], DTYPE ys[], int s[])
{
int k, pi, i, j;
struct csoln *rlist;
DTYPE dd[2*D-2]; // 0..D-2 for v, D-1..2*D-3 for h
DTYPE minl, sum, l[MPOWV+1];
if (d <= 3)
minl = xs[d-1]-xs[0]+ys[d-1]-ys[0];
else {
k = 0;
if (s[0] < s[2]) k++;
if (s[1] < s[2]) k++;
for (i=3; i<=d-1; i++) { // p0=0 always, skip i=1 for symmetry
pi = s[i];
for (j=d-1; j>i; j--)
if (s[j] < s[i])
pi--;
k = pi + (i+1)*k;
}
if (k < numgrp[d]) // no horizontal flip
for (i=1; i<=d-3; i++) {
dd[i]=ys[i+1]-ys[i];
dd[d-1+i]=xs[i+1]-xs[i];
}
else {
k=2*numgrp[d]-1-k;
for (i=1; i<=d-3; i++) {
dd[i]=ys[i+1]-ys[i];
dd[d-1+i]=xs[d-1-i]-xs[d-2-i];
}
}
minl = l[0] = xs[d-1]-xs[0]+ys[d-1]-ys[0];
rlist = LUT[d][k];
for (i=0; rlist->seg[i]>0; i++)
minl += dd[rlist->seg[i]];
l[1] = minl;
j = 2;
while (j <= numsoln[d][k]) {
rlist++;
sum = l[rlist->parent];
for (i=0; rlist->seg[i]>0; i++)
sum += dd[rlist->seg[i]];
for (i=10; rlist->seg[i]>0; i--)
sum -= dd[rlist->seg[i]];
minl = flute_min(minl, sum);
l[j++] = sum;
}
}
return minl;
}
// For medium-degree, i.e., D+1 <= d
DTYPE flutes_wl_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc)
{
DTYPE x1[FLUTE_MAXD], x2[FLUTE_MAXD], y1[FLUTE_MAXD], y2[FLUTE_MAXD];
int si[FLUTE_MAXD], s1[FLUTE_MAXD], s2[FLUTE_MAXD];
float score[2*FLUTE_MAXD], penalty[FLUTE_MAXD], pnlty, dx, dy;
DTYPE ll, minl, extral;
int i, r, p, maxbp, nbp, bp, ub, lb, n1, n2, newacc;
int ms, mins, maxs, minsi, maxsi;
DTYPE distx[FLUTE_MAXD], disty[FLUTE_MAXD], xydiff;
if (s[0] < s[d-1]) {
ms = flute_max(s[0], s[1]);
for (i=2; i<=ms; i++)
ms = flute_max(ms, s[i]);
if (ms <= d-3) {
for (i=0; i<=ms; i++) {
x1[i] = xs[i];
y1[i] = ys[i];
s1[i] = s[i];
}
x1[ms+1] = xs[ms];
y1[ms+1] = ys[ms];
s1[ms+1] = ms+1;
s2[0] = 0;
for (i=1; i<=d-1-ms; i++)
s2[i] = s[i+ms]-ms;
return flutes_wl_LMD(ms+2, x1, y1, s1, acc)
+ flutes_wl_LMD(d-ms, xs+ms, ys+ms, s2, acc);
}
}
else { // (s[0] > s[d-1])
ms = flute_min(s[0], s[1]);
for (i=2; i<=d-1-ms; i++)
ms = flute_min(ms, s[i]);
if (ms >= 2) {
x1[0] = xs[ms];
y1[0] = ys[0];
s1[0] = s[0]-ms+1;
for (i=1; i<=d-1-ms; i++) {
x1[i] = xs[i+ms-1];
y1[i] = ys[i];
s1[i] = s[i]-ms+1;
}
x1[d-ms] = xs[d-1];
y1[d-ms] = ys[d-1-ms];
s1[d-ms] = 0;
s2[0] = ms;
for (i=1; i<=ms; i++)
s2[i] = s[i+d-1-ms];
return flutes_wl_LMD(d+1-ms, x1, y1, s1, acc)
+ flutes_wl_LMD(ms+1, xs, ys+d-1-ms, s2, acc);
}
}
// Find inverse si[] of s[]
for (r=0; r<d; r++)
si[s[r]] = r;
// Determine breaking directions and positions dp[]
lb=(d-2*acc+2)/4;
if (lb < 2) lb = 2;
ub=d-1-lb;
// Compute scores
#define AAWL 0.6
#define BBWL 0.3
float CCWL = 7.4/((d+10.)*(d-3.));
float DDWL = 4.8/(d-1);
// Compute penalty[]
dx = CCWL*(xs[d-2]-xs[1]);
dy = CCWL*(ys[d-2]-ys[1]);
for (r = d/2, pnlty = 0; r>=0; r--, pnlty += dx)
penalty[r] = pnlty, penalty[d-1-r] = pnlty;
for (r = d/2-1, pnlty = dy; r>=0; r--, pnlty += dy)
penalty[s[r]] += pnlty, penalty[s[d-1-r]] += pnlty;
//#define CCWL 0.16
// for (r=0; r<d; r++)
// penalty[r] = flute_abs(d-1-r-r)*dx + flute_abs(d-1-si[r]-si[r])*dy;
// Compute distx[], disty[]
xydiff = (xs[d-1] - xs[0]) - (ys[d-1] - ys[0]);
if (s[0] < s[1])
mins = s[0], maxs = s[1];
else mins = s[1], maxs = s[0];
if (si[0] < si[1])
minsi = si[0], maxsi = si[1];
else minsi = si[1], maxsi = si[0];
for (r=2; r<=ub; r++) {
if (s[r] < mins)
mins = s[r];
else if (s[r] > maxs)
maxs = s[r];
distx[r] = xs[maxs] - xs[mins];
if (si[r] < minsi)
minsi = si[r];
else if (si[r] > maxsi)
maxsi = si[r];
disty[r] = ys[maxsi] - ys[minsi] + xydiff;
}
if (s[d-2] < s[d-1])
mins = s[d-2], maxs = s[d-1];
else mins = s[d-1], maxs = s[d-2];
if (si[d-2] < si[d-1])
minsi = si[d-2], maxsi = si[d-1];
else minsi = si[d-1], maxsi = si[d-2];
for (r=d-3; r>=lb; r--) {
if (s[r] < mins)
mins = s[r];
else if (s[r] > maxs)
maxs = s[r];
distx[r] += xs[maxs] - xs[mins];
if (si[r] < minsi)
minsi = si[r];
else if (si[r] > maxsi)
maxsi = si[r];
disty[r] += ys[maxsi] - ys[minsi];
}
nbp=0;
for (r=lb; r<=ub; r++) {
if (si[r]==0 || si[r]==d-1)
score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r]
- AAWL*(ys[d-2]-ys[1]) - DDWL*disty[r];
else score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r]
- BBWL*(ys[si[r]+1]-ys[si[r]-1]) - DDWL*disty[r];
nbp++;
if (s[r]==0 || s[r]==d-1)
score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]]
- AAWL*(xs[d-2]-xs[1]) - DDWL*distx[r];
else score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]]
- BBWL*(xs[s[r]+1]-xs[s[r]-1]) - DDWL*distx[r];
nbp++;
}
if (acc <= 3)
newacc = 1;
else {
newacc = acc/2;
if (acc >= nbp) acc = nbp-1;
}
minl = (DTYPE) INT_MAX;
for (i=0; i<acc; i++) {
maxbp = 0;
for (bp=1; bp<nbp; bp++)
if (score[maxbp] < score[bp]) maxbp = bp;
score[maxbp] = -9e9;
#define BreakPt(bp) ((bp)/2+lb)
#define BreakInX(bp) ((bp)%2==0)
p = BreakPt(maxbp);
// Breaking in p
if (BreakInX(maxbp)) { // break in x
n1 = n2 = 0;
for (r=0; r<d; r++) {
if (s[r] < p) {
s1[n1] = s[r];
y1[n1] = ys[r];
n1++;
}
else if (s[r] > p) {
s2[n2] = s[r]-p;
y2[n2] = ys[r];
n2++;
}
else { // if (s[r] == p) i.e., r = si[p]
s1[n1] = p; s2[n2] = 0;
if (r == d-1 || r == d-2) {
y1[n1] = y2[n2] = ys[r-1];
extral = ys[r] - ys[r-1];
}
if (r == 0 || r == 1) {
y1[n1] = y2[n2] = ys[r+1];
extral = ys[r+1] - ys[r];
}
else {
y1[n1] = y2[n2] = ys[r];
extral = 0;
}
n1++; n2++;
}
}
ll = extral + flutes_wl_LMD(p+1, xs, y1, s1, newacc)
+ flutes_wl_LMD(d-p, xs+p, y2, s2, newacc);
}
else { // if (!BreakInX(maxbp))
n1 = n2 = 0;
for (r=0; r<d; r++) {
if (si[r] < p) {
s1[si[r]] = n1;
x1[n1] = xs[r];
n1++;
}
else if (si[r] > p) {
s2[si[r]-p] = n2;
x2[n2] = xs[r];
n2++;
}
else { // if (si[r] == p) i.e., r = s[p]
s1[p] = n1; s2[0] = n2;
if (r == d-1 || r == d-2) {
x1[n1] = x2[n2] = xs[r-1];
extral = xs[r] - xs[r-1];
}
if (r == 0 || r == 1) {
x1[n1] = x2[n2] = xs[r+1];
extral = xs[r+1] - xs[r];
}
else {
x1[n1] = x2[n2] = xs[r];
extral = 0;
}
n1++; n2++;
}
}
ll = extral + flutes_wl_LMD(p+1, x1, ys, s1, newacc)
+ flutes_wl_LMD(d-p, x2, ys+p, s2, newacc);
}
if (minl > ll) minl = ll;
}
return minl;
}
static int orderx(const void *a, const void *b)
{
struct point *pa, *pb;
pa = *(struct point**)a;
pb = *(struct point**)b;
if (pa->x < pb->x) return -1;
if (pa->x > pb->x) return 1;
return 0;
}
static int ordery(const void *a, const void *b)
{
struct point *pa, *pb;
pa = *(struct point**)a;
pb = *(struct point**)b;
if (pa->y < pb->y) return -1;
if (pa->y > pb->y) return 1;
return 0;
}
Tree flute(int d, DTYPE x[], DTYPE y[], int acc)
{
DTYPE *xs, *ys, minval;
int *s;
int i, j, k, minidx;
struct point *pt, **ptp, *tmpp;
Tree t;
if (d==2) {
t.deg = 2;
t.length = ADIFF(x[0], x[1]) + ADIFF(y[0], y[1]);
t.branch = (Branch *) malloc(2*sizeof(Branch));
t.branch[0].x = x[0];
t.branch[0].y = y[0];
t.branch[0].n = 1;
t.branch[1].x = x[1];
t.branch[1].y = y[1];
t.branch[1].n = 1;
}
else {
xs = (DTYPE *)malloc(sizeof(DTYPE)*(d));
ys = (DTYPE *)malloc(sizeof(DTYPE)*(d));
s = (int *)malloc(sizeof(int)*(d));
pt = (struct point *)malloc(sizeof(struct point)*(d+1));
ptp = (struct point **)malloc(sizeof(struct point*)*(d+1));
for (i=0; i<d; i++) {
pt[i].x = x[i];
pt[i].y = y[i];
ptp[i] = &pt[i];
}
// sort x
if (d<200) {
for (i=0; i<d-1; i++) {
minval = ptp[i]->x;
minidx = i;
for (j=i+1; j<d; j++) {
if (minval > ptp[j]->x) {
minval = ptp[j]->x;
minidx = j;
}
}
tmpp = ptp[i];
ptp[i] = ptp[minidx];
ptp[minidx] = tmpp;
}
} else {
qsort(ptp, d, sizeof(struct point *), orderx);
}
#if FLUTE_REMOVE_DUPLICATE_PIN==1
ptp[d] = &pt[d];
ptp[d]->x = ptp[d]->y = -999999;
j = 0;
for (i=0; i<d; i++) {
for (k=i+1; ptp[k]->x == ptp[i]->x; k++)
if (ptp[k]->y == ptp[i]->y) // pins k and i are the same
break;
if (ptp[k]->x != ptp[i]->x)
ptp[j++] = ptp[i];
}
d = j;
#endif
for (i=0; i<d; i++) {
xs[i] = ptp[i]->x;
ptp[i]->o = i;
}
// sort y to find s[]
if (d<200) {
for (i=0; i<d-1; i++) {
minval = ptp[i]->y;
minidx = i;
for (j=i+1; j<d; j++) {
if (minval > ptp[j]->y) {
minval = ptp[j]->y;
minidx = j;
}
}
ys[i] = ptp[minidx]->y;
s[i] = ptp[minidx]->o;
ptp[minidx] = ptp[i];
}
ys[d-1] = ptp[d-1]->y;
s[d-1] = ptp[d-1]->o;
} else {
qsort(ptp, d, sizeof(struct point *), ordery);
for (i=0; i<d; i++) {
ys[i] = ptp[i]->y;
s[i] = ptp[i]->o;
}
}
t = flutes(d, xs, ys, s, acc);
free(xs);
free(ys);
free(s);
free(pt);
free(ptp);
}
return t;
}
// xs[] and ys[] are coords in x and y in sorted order
// s[] is a list of nodes in increasing y direction
// if nodes are indexed in the order of increasing x coord
// i.e., s[i] = s_i as defined in paper
// The points are (xs[s[i]], ys[i]) for i=0..d-1
// or (xs[i], ys[si[i]]) for i=0..d-1
Tree flutes_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc)
{
int i, j, ss;
for (i=0; i<d-1; i++) {
if (xs[s[i]]==xs[s[i+1]] && ys[i]==ys[i+1]) {
if (s[i] < s[i+1])
ss = s[i+1];
else {
ss = s[i];
s[i] = s[i+1];
}
for (j=i+2; j<d; j++) {
ys[j-1] = ys[j];
s[j-1] = s[j];
}
for (j=ss+1; j<d; j++)
xs[j-1] = xs[j];
for (j=0; j<=d-2; j++)
if (s[j] > ss) s[j]--;
i--;
d--;
}
}
return flutes_ALLD(d, xs, ys, s, acc);
}
// For low-degree, i.e., 2 <= d <= D
Tree flutes_LD(int d, DTYPE xs[], DTYPE ys[], int s[])
{
int k, pi, i, j;
struct csoln *rlist, *bestrlist;
DTYPE dd[2*D-2]; // 0..D-2 for v, D-1..2*D-3 for h
DTYPE minl, sum, l[MPOWV+1];
int hflip;
Tree t;
t.deg = d;
t.branch = (Branch *) malloc((2*d-2)*sizeof(Branch));
if (d == 2) {
minl = xs[1]-xs[0]+ys[1]-ys[0];
t.branch[0].x = xs[s[0]];
t.branch[0].y = ys[0];
t.branch[0].n = 1;
t.branch[1].x = xs[s[1]];
t.branch[1].y = ys[1];
t.branch[1].n = 1;
}
else if (d == 3) {
minl = xs[2]-xs[0]+ys[2]-ys[0];
t.branch[0].x = xs[s[0]];
t.branch[0].y = ys[0];
t.branch[0].n = 3;
t.branch[1].x = xs[s[1]];
t.branch[1].y = ys[1];
t.branch[1].n = 3;
t.branch[2].x = xs[s[2]];
t.branch[2].y = ys[2];
t.branch[2].n = 3;
t.branch[3].x = xs[1];
t.branch[3].y = ys[1];
t.branch[3].n = 3;
}
else {
k = 0;
if (s[0] < s[2]) k++;
if (s[1] < s[2]) k++;
for (i=3; i<=d-1; i++) { // p0=0 always, skip i=1 for symmetry
pi = s[i];
for (j=d-1; j>i; j--)
if (s[j] < s[i])
pi--;
k = pi + (i+1)*k;
}
if (k < numgrp[d]) { // no horizontal flip
hflip = 0;
for (i=1; i<=d-3; i++) {
dd[i]=ys[i+1]-ys[i];
dd[d-1+i]=xs[i+1]-xs[i];
}
}
else {
hflip = 1;
k=2*numgrp[d]-1-k;
for (i=1; i<=d-3; i++) {
dd[i]=ys[i+1]-ys[i];
dd[d-1+i]=xs[d-1-i]-xs[d-2-i];
}
}
minl = l[0] = xs[d-1]-xs[0]+ys[d-1]-ys[0];
rlist = LUT[d][k];
for (i=0; rlist->seg[i]>0; i++)
minl += dd[rlist->seg[i]];
bestrlist = rlist;
l[1] = minl;
j = 2;
while (j <= numsoln[d][k]) {
rlist++;
sum = l[rlist->parent];
for (i=0; rlist->seg[i]>0; i++)
sum += dd[rlist->seg[i]];
for (i=10; rlist->seg[i]>0; i--)
sum -= dd[rlist->seg[i]];
if (sum < minl) {
minl = sum;
bestrlist = rlist;
}
l[j++] = sum;
}
t.branch[0].x = xs[s[0]];
t.branch[0].y = ys[0];
t.branch[1].x = xs[s[1]];
t.branch[1].y = ys[1];
for (i=2; i<d-2; i++) {
t.branch[i].x = xs[s[i]];
t.branch[i].y = ys[i];
t.branch[i].n = bestrlist->neighbor[i];
}
t.branch[d-2].x = xs[s[d-2]];
t.branch[d-2].y = ys[d-2];
t.branch[d-1].x = xs[s[d-1]];
t.branch[d-1].y = ys[d-1];
if (hflip) {
if (s[1] < s[0]) {
t.branch[0].n = bestrlist->neighbor[1];
t.branch[1].n = bestrlist->neighbor[0];
}
else {
t.branch[0].n = bestrlist->neighbor[0];
t.branch[1].n = bestrlist->neighbor[1];
}
if (s[d-1] < s[d-2]) {
t.branch[d-2].n = bestrlist->neighbor[d-1];
t.branch[d-1].n = bestrlist->neighbor[d-2];
}
else {
t.branch[d-2].n = bestrlist->neighbor[d-2];
t.branch[d-1].n = bestrlist->neighbor[d-1];
}
for (i=d; i<2*d-2; i++) {
t.branch[i].x = xs[d-1-bestrlist->rowcol[i-d]%16];
t.branch[i].y = ys[bestrlist->rowcol[i-d]/16];
t.branch[i].n = bestrlist->neighbor[i];
}
}
else { // !hflip
if (s[0] < s[1]) {
t.branch[0].n = bestrlist->neighbor[1];
t.branch[1].n = bestrlist->neighbor[0];
}
else {
t.branch[0].n = bestrlist->neighbor[0];
t.branch[1].n = bestrlist->neighbor[1];
}
if (s[d-2] < s[d-1]) {
t.branch[d-2].n = bestrlist->neighbor[d-1];
t.branch[d-1].n = bestrlist->neighbor[d-2];
}
else {
t.branch[d-2].n = bestrlist->neighbor[d-2];
t.branch[d-1].n = bestrlist->neighbor[d-1];
}
for (i=d; i<2*d-2; i++) {
t.branch[i].x = xs[bestrlist->rowcol[i-d]%16];
t.branch[i].y = ys[bestrlist->rowcol[i-d]/16];
t.branch[i].n = bestrlist->neighbor[i];
}
}
}
t.length = minl;
return t;
}
// For medium-degree, i.e., D+1 <= d
Tree flutes_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc)
{
DTYPE x1[FLUTE_MAXD], x2[FLUTE_MAXD], y1[FLUTE_MAXD], y2[FLUTE_MAXD];
int si[FLUTE_MAXD], s1[FLUTE_MAXD], s2[FLUTE_MAXD];
float score[2*FLUTE_MAXD], penalty[FLUTE_MAXD], pnlty, dx, dy;
DTYPE ll, minl, coord1, coord2;
int i, r, p, maxbp, bestbp, bp, nbp, ub, lb, n1, n2, nn1, nn2, newacc;
Tree t, t1, t2, bestt1, bestt2;
int ms, mins, maxs, minsi, maxsi;
DTYPE distx[FLUTE_MAXD], disty[FLUTE_MAXD], xydiff;
if (s[0] < s[d-1]) {
ms = flute_max(s[0], s[1]);
for (i=2; i<=ms; i++)
ms = flute_max(ms, s[i]);
if (ms <= d-3) {
for (i=0; i<=ms; i++) {
x1[i] = xs[i];
y1[i] = ys[i];
s1[i] = s[i];
}
x1[ms+1] = xs[ms];
y1[ms+1] = ys[ms];
s1[ms+1] = ms+1;
s2[0] = 0;
for (i=1; i<=d-1-ms; i++)
s2[i] = s[i+ms]-ms;
t1 = flutes_LMD(ms+2, x1, y1, s1, acc);
t2 = flutes_LMD(d-ms, xs+ms, ys+ms, s2, acc);
t = dmergetree(t1, t2);
free(t1.branch);
free(t2.branch);
return t;
}
}
else { // (s[0] > s[d-1])
ms = flute_min(s[0], s[1]);
for (i=2; i<=d-1-ms; i++)
ms = flute_min(ms, s[i]);
if (ms >= 2) {
x1[0] = xs[ms];
y1[0] = ys[0];
s1[0] = s[0]-ms+1;
for (i=1; i<=d-1-ms; i++) {
x1[i] = xs[i+ms-1];
y1[i] = ys[i];
s1[i] = s[i]-ms+1;
}
x1[d-ms] = xs[d-1];
y1[d-ms] = ys[d-1-ms];
s1[d-ms] = 0;
s2[0] = ms;
for (i=1; i<=ms; i++)
s2[i] = s[i+d-1-ms];
t1 = flutes_LMD(d+1-ms, x1, y1, s1, acc);
t2 = flutes_LMD(ms+1, xs, ys+d-1-ms, s2, acc);
t = dmergetree(t1, t2);
free(t1.branch);
free(t2.branch);
return t;
}
}
// Find inverse si[] of s[]
for (r=0; r<d; r++)
si[s[r]] = r;
// Determine breaking directions and positions dp[]
lb=(d-2*acc+2)/4;
if (lb < 2) lb = 2;
ub=d-1-lb;
// Compute scores
#define AA 0.6 // 2.0*BB
#define BB 0.3
float CC = 7.4/((d+10.)*(d-3.));
float DD = 4.8/(d-1);
// Compute penalty[]
dx = CC*(xs[d-2]-xs[1]);
dy = CC*(ys[d-2]-ys[1]);
for (r = d/2, pnlty = 0; r>=2; r--, pnlty += dx)
penalty[r] = pnlty, penalty[d-1-r] = pnlty;
penalty[1] = pnlty, penalty[d-2] = pnlty;
penalty[0] = pnlty, penalty[d-1] = pnlty;
for (r = d/2-1, pnlty = dy; r>=2; r--, pnlty += dy)
penalty[s[r]] += pnlty, penalty[s[d-1-r]] += pnlty;
penalty[s[1]] += pnlty, penalty[s[d-2]] += pnlty;
penalty[s[0]] += pnlty, penalty[s[d-1]] += pnlty;
//#define CC 0.16
//#define v(r) ((r==0||r==1||r==d-2||r==d-1) ? d-3 : flute_abs(d-1-r-r))
// for (r=0; r<d; r++)
// penalty[r] = v(r)*dx + v(si[r])*dy;
// Compute distx[], disty[]
xydiff = (xs[d-1] - xs[0]) - (ys[d-1] - ys[0]);
if (s[0] < s[1])
mins = s[0], maxs = s[1];
else mins = s[1], maxs = s[0];
if (si[0] < si[1])
minsi = si[0], maxsi = si[1];
else minsi = si[1], maxsi = si[0];
for (r=2; r<=ub; r++) {
if (s[r] < mins)
mins = s[r];
else if (s[r] > maxs)
maxs = s[r];
distx[r] = xs[maxs] - xs[mins];
if (si[r] < minsi)
minsi = si[r];
else if (si[r] > maxsi)
maxsi = si[r];
disty[r] = ys[maxsi] - ys[minsi] + xydiff;
}
if (s[d-2] < s[d-1])
mins = s[d-2], maxs = s[d-1];
else mins = s[d-1], maxs = s[d-2];
if (si[d-2] < si[d-1])
minsi = si[d-2], maxsi = si[d-1];
else minsi = si[d-1], maxsi = si[d-2];
for (r=d-3; r>=lb; r--) {
if (s[r] < mins)
mins = s[r];
else if (s[r] > maxs)
maxs = s[r];
distx[r] += xs[maxs] - xs[mins];
if (si[r] < minsi)
minsi = si[r];
else if (si[r] > maxsi)
maxsi = si[r];
disty[r] += ys[maxsi] - ys[minsi];
}
nbp=0;
for (r=lb; r<=ub; r++) {
if (si[r]<=1)
score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r]
- AA*(ys[2]-ys[1]) - DD*disty[r];
else if (si[r]>=d-2)
score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r]
- AA*(ys[d-2]-ys[d-3]) - DD*disty[r];
else score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r]
- BB*(ys[si[r]+1]-ys[si[r]-1]) - DD*disty[r];
nbp++;
if (s[r]<=1)
score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]]
- AA*(xs[2]-xs[1]) - DD*distx[r];
else if (s[r]>=d-2)
score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]]
- AA*(xs[d-2]-xs[d-3]) - DD*distx[r];
else score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]]
- BB*(xs[s[r]+1]-xs[s[r]-1]) - DD*distx[r];
nbp++;
}
if (acc <= 3)
newacc = 1;
else {
newacc = acc/2;
if (acc >= nbp) acc = nbp-1;
}
minl = (DTYPE) INT_MAX;
bestt1.branch = bestt2.branch = NULL;
for (i=0; i<acc; i++) {
maxbp = 0;
for (bp=1; bp<nbp; bp++)
if (score[maxbp] < score[bp]) maxbp = bp;
score[maxbp] = -9e9;
#define BreakPt(bp) ((bp)/2+lb)
#define BreakInX(bp) ((bp)%2==0)
p = BreakPt(maxbp);
// Breaking in p
if (BreakInX(maxbp)) { // break in x
n1 = n2 = 0;
for (r=0; r<d; r++) {
if (s[r] < p) {
s1[n1] = s[r];
y1[n1] = ys[r];
n1++;
}
else if (s[r] > p) {
s2[n2] = s[r]-p;
y2[n2] = ys[r];
n2++;
}
else { // if (s[r] == p) i.e., r = si[p]
s1[n1] = p; s2[n2] = 0;
y1[n1] = y2[n2] = ys[r];
nn1 = n1; nn2 = n2;
n1++; n2++;
}
}
t1 = flutes_LMD(p+1, xs, y1, s1, newacc);
t2 = flutes_LMD(d-p, xs+p, y2, s2, newacc);
ll = t1.length + t2.length;
coord1 = t1.branch[t1.branch[nn1].n].y;
coord2 = t2.branch[t2.branch[nn2].n].y;
if (t2.branch[nn2].y > flute_max(coord1, coord2))
ll -= t2.branch[nn2].y - flute_max(coord1, coord2);
else if (t2.branch[nn2].y < flute_min(coord1, coord2))
ll -= flute_min(coord1, coord2) - t2.branch[nn2].y;
}
else { // if (!BreakInX(maxbp))
n1 = n2 = 0;
for (r=0; r<d; r++) {
if (si[r] < p) {
s1[si[r]] = n1;
x1[n1] = xs[r];
n1++;
}
else if (si[r] > p) {
s2[si[r]-p] = n2;
x2[n2] = xs[r];
n2++;
}
else { // if (si[r] == p) i.e., r = s[p]
s1[p] = n1; s2[0] = n2;
x1[n1] = x2[n2] = xs[r];
n1++; n2++;
}
}
t1 = flutes_LMD(p+1, x1, ys, s1, newacc);
t2 = flutes_LMD(d-p, x2, ys+p, s2, newacc);
ll = t1.length + t2.length;
coord1 = t1.branch[t1.branch[p].n].x;
coord2 = t2.branch[t2.branch[0].n].x;
if (t2.branch[0].x > flute_max(coord1, coord2))
ll -= t2.branch[0].x - flute_max(coord1, coord2);
else if (t2.branch[0].x < flute_min(coord1, coord2))
ll -= flute_min(coord1, coord2) - t2.branch[0].x;
}
if (minl > ll) {
minl = ll;
free(bestt1.branch);
free(bestt2.branch);
bestt1 = t1;
bestt2 = t2;
bestbp = maxbp;
}
else {
free(t1.branch);
free(t2.branch);
}
}
#if FLUTE_LOCAL_REFINEMENT==1
if (BreakInX(bestbp)) {
t = hmergetree(bestt1, bestt2, s);
local_refinement(&t, si[BreakPt(bestbp)]);
} else {
t = vmergetree(bestt1, bestt2);
local_refinement(&t, BreakPt(bestbp));
}
#else
if (BreakInX(bestbp)) {
t = hmergetree(bestt1, bestt2, s);
} else {
t = vmergetree(bestt1, bestt2);
}
#endif
free(bestt1.branch);
free(bestt2.branch);
return t;
}
Tree dmergetree(Tree t1, Tree t2)
{
int i, d, prev, curr, next, offset1, offset2;
Tree t;
t.deg = d = t1.deg + t2.deg - 2;
t.length = t1.length + t2.length;
t.branch = (Branch *) malloc((2*d-2)*sizeof(Branch));
offset1 = t2.deg-2;
offset2 = 2*t1.deg-4;
for (i=0; i<=t1.deg-2; i++) {
t.branch[i].x = t1.branch[i].x;
t.branch[i].y = t1.branch[i].y;
t.branch[i].n = t1.branch[i].n + offset1;
}
for (i=t1.deg-1; i<=d-1; i++) {
t.branch[i].x = t2.branch[i-t1.deg+2].x;
t.branch[i].y = t2.branch[i-t1.deg+2].y;
t.branch[i].n = t2.branch[i-t1.deg+2].n + offset2;
}
for (i=d; i<=d+t1.deg-3; i++) {
t.branch[i].x = t1.branch[i-offset1].x;
t.branch[i].y = t1.branch[i-offset1].y;
t.branch[i].n = t1.branch[i-offset1].n + offset1;
}
for (i=d+t1.deg-2; i<=2*d-3; i++) {
t.branch[i].x = t2.branch[i-offset2].x;
t.branch[i].y = t2.branch[i-offset2].y;
t.branch[i].n = t2.branch[i-offset2].n + offset2;
}
prev = t2.branch[0].n + offset2;
curr = t1.branch[t1.deg-1].n + offset1;
next = t.branch[curr].n;
while (curr != next) {
t.branch[curr].n = prev;
prev = curr;
curr = next;
next = t.branch[curr].n;
}
t.branch[curr].n = prev;
return t;
}
Tree hmergetree(Tree t1, Tree t2, int s[])
{
int i, prev, curr, next, extra, offset1, offset2;
int p, ii, n1, n2, nn1, nn2;
DTYPE coord1, coord2;
Tree t;
t.deg = t1.deg + t2.deg - 1;
t.length = t1.length + t2.length;
t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch));
offset1 = t2.deg-1;
offset2 = 2*t1.deg-3;
p = t1.deg - 1;
n1 = n2 = 0;
for (i=0; i<t.deg; i++) {
if (s[i] < p) {
t.branch[i].x = t1.branch[n1].x;
t.branch[i].y = t1.branch[n1].y;
t.branch[i].n = t1.branch[n1].n + offset1;
n1++;
}
else if (s[i] > p) {
t.branch[i].x = t2.branch[n2].x;
t.branch[i].y = t2.branch[n2].y;
t.branch[i].n = t2.branch[n2].n + offset2;
n2++;
}
else {
t.branch[i].x = t2.branch[n2].x;
t.branch[i].y = t2.branch[n2].y;
t.branch[i].n = t2.branch[n2].n + offset2;
nn1 = n1; nn2 = n2; ii = i;
n1++; n2++;
}
}
for (i=t.deg; i<=t.deg+t1.deg-3; i++) {
t.branch[i].x = t1.branch[i-offset1].x;
t.branch[i].y = t1.branch[i-offset1].y;
t.branch[i].n = t1.branch[i-offset1].n + offset1;
}
for (i=t.deg+t1.deg-2; i<=2*t.deg-4; i++) {
t.branch[i].x = t2.branch[i-offset2].x;
t.branch[i].y = t2.branch[i-offset2].y;
t.branch[i].n = t2.branch[i-offset2].n + offset2;
}
extra = 2*t.deg-3;
coord1 = t1.branch[t1.branch[nn1].n].y;
coord2 = t2.branch[t2.branch[nn2].n].y;
if (t2.branch[nn2].y > flute_max(coord1, coord2)) {
t.branch[extra].y = flute_max(coord1, coord2);
t.length -= t2.branch[nn2].y - t.branch[extra].y;
}
else if (t2.branch[nn2].y < flute_min(coord1, coord2)) {
t.branch[extra].y = flute_min(coord1, coord2);
t.length -= t.branch[extra].y - t2.branch[nn2].y;
}
else t.branch[extra].y = t2.branch[nn2].y;
t.branch[extra].x = t2.branch[nn2].x;
t.branch[extra].n = t.branch[ii].n;
t.branch[ii].n = extra;
prev = extra;
curr = t1.branch[nn1].n + offset1;
next = t.branch[curr].n;
while (curr != next) {
t.branch[curr].n = prev;
prev = curr;
curr = next;
next = t.branch[curr].n;
}
t.branch[curr].n = prev;
return t;
}
Tree vmergetree(Tree t1, Tree t2)
{
int i, prev, curr, next, extra, offset1, offset2;
DTYPE coord1, coord2;
Tree t;
t.deg = t1.deg + t2.deg - 1;
t.length = t1.length + t2.length;
t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch));
offset1 = t2.deg-1;
offset2 = 2*t1.deg-3;
for (i=0; i<=t1.deg-2; i++) {
t.branch[i].x = t1.branch[i].x;
t.branch[i].y = t1.branch[i].y;
t.branch[i].n = t1.branch[i].n + offset1;
}
for (i=t1.deg-1; i<=t.deg-1; i++) {
t.branch[i].x = t2.branch[i-t1.deg+1].x;
t.branch[i].y = t2.branch[i-t1.deg+1].y;
t.branch[i].n = t2.branch[i-t1.deg+1].n + offset2;
}
for (i=t.deg; i<=t.deg+t1.deg-3; i++) {
t.branch[i].x = t1.branch[i-offset1].x;
t.branch[i].y = t1.branch[i-offset1].y;
t.branch[i].n = t1.branch[i-offset1].n + offset1;
}
for (i=t.deg+t1.deg-2; i<=2*t.deg-4; i++) {
t.branch[i].x = t2.branch[i-offset2].x;
t.branch[i].y = t2.branch[i-offset2].y;
t.branch[i].n = t2.branch[i-offset2].n + offset2;
}
extra = 2*t.deg-3;
coord1 = t1.branch[t1.branch[t1.deg-1].n].x;
coord2 = t2.branch[t2.branch[0].n].x;
if (t2.branch[0].x > flute_max(coord1, coord2)) {
t.branch[extra].x = flute_max(coord1, coord2);
t.length -= t2.branch[0].x - t.branch[extra].x;
}
else if (t2.branch[0].x < flute_min(coord1, coord2)) {
t.branch[extra].x = flute_min(coord1, coord2);
t.length -= t.branch[extra].x - t2.branch[0].x;
}
else t.branch[extra].x = t2.branch[0].x;
t.branch[extra].y = t2.branch[0].y;
t.branch[extra].n = t.branch[t1.deg-1].n;
t.branch[t1.deg-1].n = extra;
prev = extra;
curr = t1.branch[t1.deg-1].n + offset1;
next = t.branch[curr].n;
while (curr != next) {
t.branch[curr].n = prev;
prev = curr;
curr = next;
next = t.branch[curr].n;
}
t.branch[curr].n = prev;
return t;
}
void local_refinement(Tree *tp, int p)
{
int d, dd, i, ii, j, prev, curr, next, root;
int SteinerPin[2*FLUTE_MAXD], index[2*FLUTE_MAXD];
DTYPE x[FLUTE_MAXD], xs[D], ys[D];
int ss[D];
Tree tt;
d = tp->deg;
root = tp->branch[p].n;
// Reverse edges to point to root
prev = root;
curr = tp->branch[prev].n;
next = tp->branch[curr].n;
while (curr != next) {
tp->branch[curr].n = prev;
prev = curr;
curr = next;
next = tp->branch[curr].n;
}
tp->branch[curr].n = prev;
tp->branch[root].n = root;
// Find Steiner nodes that are at pins
for (i=d; i<=2*d-3; i++)
SteinerPin[i] = -1;
for (i=0; i<d; i++) {
next = tp->branch[i].n;
if (tp->branch[i].x == tp->branch[next].x &&
tp->branch[i].y == tp->branch[next].y)
SteinerPin[next] = i; // Steiner 'next' at Pin 'i'
}
SteinerPin[root] = p;
// Find pins that are directly connected to root
dd = 0;
for (i=0; i<d; i++) {
curr = tp->branch[i].n;
if (SteinerPin[curr] == i)
curr = tp->branch[curr].n;
while (SteinerPin[curr] < 0)
curr = tp->branch[curr].n;
if (curr == root) {
x[dd] = tp->branch[i].x;
if (SteinerPin[tp->branch[i].n] == i && tp->branch[i].n != root)
index[dd++] = tp->branch[i].n; // Steiner node
else index[dd++] = i; // Pin
}
}
if (4 <= dd && dd <= D) {
// Find Steiner nodes that are directly connected to root
ii=dd;
for (i=0; i<dd; i++) {
curr = tp->branch[index[i]].n;
while (SteinerPin[curr] < 0) {
index[ii++] = curr;
SteinerPin[curr] = INT_MAX;
curr = tp->branch[curr].n;
}
}
index[ii] = root;
for (ii=0; ii<dd; ii++) {
ss[ii] = 0;
for (j=0; j<ii; j++)
if (x[j] < x[ii])
ss[ii]++;
for (j=ii+1; j<dd; j++)
if (x[j] <= x[ii])
ss[ii]++;
xs[ss[ii]] = x[ii];
ys[ii] = tp->branch[index[ii]].y;
}
tt = flutes_LD(dd, xs, ys, ss);
// Find new wirelength
tp->length += tt.length;
for (ii=0; ii<2*dd-3; ii++) {
i = index[ii];
j = tp->branch[i].n;
tp->length -= ADIFF(tp->branch[i].x, tp->branch[j].x)
+ ADIFF(tp->branch[i].y, tp->branch[j].y);
}
// Copy tt into t
for (ii=0; ii<dd; ii++) {
tp->branch[index[ii]].n = index[tt.branch[ii].n];
}
for (; ii<=2*dd-3; ii++) {
tp->branch[index[ii]].x = tt.branch[ii].x;
tp->branch[index[ii]].y = tt.branch[ii].y;
tp->branch[index[ii]].n = index[tt.branch[ii].n];
}
free(tt.branch);
}
return;
}
DTYPE wirelength(Tree t)
{
int i, j;
DTYPE l=0;
for (i=0; i<2*t.deg-2; i++) {
j = t.branch[i].n;
l += ADIFF(t.branch[i].x, t.branch[j].x)
+ ADIFF(t.branch[i].y, t.branch[j].y);
}
return l;
}
void printtree(Tree t)
{
int i;
for (i=0; i<t.deg; i++)
printf(" %-2d: x=%4g y=%4g e=%d\n",
i, (float) t.branch[i].x, (float) t.branch[i].y, t.branch[i].n);
for (i=t.deg; i<2*t.deg-2; i++)
printf("s%-2d: x=%4g y=%4g e=%d\n",
i, (float) t.branch[i].x, (float) t.branch[i].y, t.branch[i].n);
printf("\n");
}
// Output in a format that can be plotted by gnuplot
void plottree(Tree t)
{
int i;
for (i=0; i<2*t.deg-2; i++) {
printf("%d %d\n", t.branch[i].x, t.branch[i].y);
printf("%d %d\n\n", t.branch[t.branch[i].n].x,
t.branch[t.branch[i].n].y);
}
}
} // namespace Flute