⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rfst.c

📁 生成直角Steiner树的程序包
💻 C
📖 第 1 页 / 共 4 页
字号:
						hookp = &(ibp -> next);						bufp = &(ibp -> buf [0]);						bleft = n;					}					*bufp++ = j;					++(ibp -> count);					--bleft;					++index;				}			}		}		*op++ = index;	}	/* Copy list data into nice contiguous memory. */	ip = NEWA (index, int);	ip1 = ip;	for (ibp = root; ibp NE NULL; ibp = ibp -> next) {		bufp = &(ibp -> buf [0]);		for (i = 0; i < ibp -> count; i++) {			*ip1++ = *bufp++;		}	}	if (ip1 NE ip + index) {		fatal ("compute_zt: Bug 1.");	}	/* Allocate arrays of pointers into the lists. */	rip -> zt [0]	= NEWA (4 * (n + 1), int *);	rip -> zt [1]	= rip -> zt [0] + (n + 1);	rip -> zt [2]	= rip -> zt [1] + (n + 1);	rip -> zt [3]	= rip -> zt [2] + (n + 1);	rip -> zt [4]	= rip -> zt [0];	rip -> zt [5]	= rip -> zt [1];	rip -> zt [6]	= rip -> zt [2];	op = offset;	for (dir = 0; dir < 4; dir++) {		zt = rip -> zt [dir];		for (i = 0; i <= n; i++, p1++) {			zt [i] = &(ip [*op++]);		}	}	if (rip -> zt [0] [0] + index NE rip -> zt [3] [n]) {		fatal ("compute_zt: Bug 2.");	}	while (root NE NULL) {		ibp = root;		root = ibp -> next;		free ((char *) ibp);	}	free ((char *) offset);}/* * Compute the upper bounds UB1. */	static	voidcompute_ub1 (struct rinfo *		rip		/* IN/OUT - global RFST info */){int			i;int			j;int			n;int			dir;int			lr;int			last;struct pset *		pts;struct point *		p1;struct point *		p2;struct point *		p3;int *			succ;int *			ip1;int *			ip2;int **			zt;dstdiroff_t		dir_off;dstdiroff_t		dirp_off;lrdiroff_t		lrdir_off;dist_t *		array;dist_t *		ub1;dist_t			d1, d2, d3, d4;dist_t			bound;struct point		s;static int		lr_table [] = {0, 1, 1, 0};	pts = rip -> pts;	n = pts -> n;	array = NEWA (4 * n, dist_t);	rip -> ub1 [0]	= array;	array += n;	rip -> ub1 [1]	= array;	array += n;	rip -> ub1 [2]	= array;	array += n;	rip -> ub1 [3]	= array;	rip -> ub1 [4]	= rip -> ub1 [0];	rip -> ub1 [5]	= rip -> ub1 [1];	rip -> ub1 [6]	= rip -> ub1 [2];	for (dir = 0; dir < 4; dir++) {		lr	= lr_table [dir];		ub1 = rip -> ub1 [dir];		zt = rip -> zt [dir];		succ = rip -> succ [dir];		dir_off = DSTDIR_GETOFFSET (dir);		dirp_off = DSTDIR_GETOFFSET (dir + 1);		lrdir_off = LRINDEX_GETOFFSET (dir);		p1 = &(pts -> a [0]);		for (i = 0; i < n; i++, p1++) {			ip1 = zt [i];			ip2 = zt [i + 1];			if (ip1 >= ip2) {				/* No short leg candidates.  UB1 is zero! */				ub1 [i] = 0.0;				continue;			}			/* Get last short leg candidate in this direction. */			last = ip2 [-1];			bound = INF_DISTANCE;			p3 = &(pts -> a [last]);			/* Get Steiner point for this last terminal. */			SPOINT (&s, p1, p3, dir);			d3 = DSTDIR_OFFSET (p1, p3, dirp_off);			for (j = succ [last]; j >= 0; j = succ [j]) {				p2 = &(pts -> a [j]);				d1 = DSTDIR_OFFSET (&s, p2, dir_off);				if (d1 > bound) break;				d2 = DSTDIR_OFFSET (&s, p2, dirp_off);				if ((LRINDEX_OFFSET (p1, p2, lrdir_off) EQ lr)				    AND				    (d3 > d2)) {					bound = d1;					break;				}				if (d1 > d2) {					d4 = d1 + d2; /* RDIST(&s, p2) */					if (d4 < bound) {						bound = d4;					}				}			}			ub1 [i] = DSTDIR_OFFSET (p1, p3, dir_off) + bound;		}	}}/* * Recursively grow a rectilinear FST. */	static	voidgrow_RFST (struct rinfo *	rip,		/* IN/OUT - The global RFST info */int		size,		/* IN - number of terms in partial tree */dist_t		length,		/* IN - length of partial tree */int		dir,		/* IN - growth direction from root */dist_t		ub_length,	/* IN - upper bound on partial tree length */dist_t *	ub_shortleg,	/* IN - left/right short leg upper bounds */int		longindex	/* IN - current long leg terminal */){int			i, j, k, l, j2;int			lr;int			r;int			lastlr;int			dirp;int			lp;bool			pass_bsd;bool			need_to_restore;struct pset *		pts;struct point *		p;struct point *		q;struct point *		root;struct point *		last;int *			terms;int *			succ;int *			ip1;int *			ip2;dist_t			dstdir, dstdirp;dist_t			d1, d2, d3;dist_t			ub1;dist_t			b;dist_t			max_backbone;dist_t			min_bsd;dist_t			new_ub_length;dist_t			new_ub_shortleg [2];dist_t			lastdstdirp;dist_t			long_leg_max;#define LONGTERMS	rip -> longterms	terms		= rip -> terms;	r		= terms [0];	l		= terms [size - 1];	lastlr		= rip -> lrindex [l];	succ		= rip -> succ [dir];	pts		= rip -> pts;	root = &(pts -> a [r]);	last = &(pts -> a [l]);	max_backbone = INF_DISTANCE;	lastdstdirp = DSTDIRP (root, last, dir);	/* We set this flag whenever we change one of the "maxedges" values. */	need_to_restore = FALSE;	for (;;) {		i = LONGTERMS [++longindex];		if (i < -1) {			/* No more candidates, and we have already	*/			/* determined that no more can be found.	*/			break;		}		if (i EQ -1) {			/* Dynamically add next candidate to longterms. */			for (i = succ [LONGTERMS [longindex - 1]];			     i >= 0;			     i = succ [i]) {				p = &(pts -> a [i]);				dstdirp = DSTDIRP (root, p, dir);				if (dstdirp EQ 0.0) {					lr = 2;					rip -> lrindex [i] = 2;					rip -> shortterm [i] = 0;					LONGTERMS [longindex] = i;					LONGTERMS [longindex + 1] = -2;					break;				}				lr = LRINDEX (root, p, dir);				if (lr EQ 0) {					dirp = (dir - 1) & 0x03;				}				else {					dirp = (dir + 1) & 0x03;				}				/* Find short leg candidate (if it exists) */				j = -1;				ip1 = rip -> zt [dirp] [i];				ip2 = rip -> zt [dirp] [i + 1];				while (ip1 < ip2) {					k = *--ip2;					if (LRINDEX (root, &(pts -> a [k]), dir)					    EQ lr) {						j = k;						break;					}				}				rip -> shortterm [i] = j;				/* Check upper bounds */				ub1 = 0.0;				if (j >= 0) {					ub1 = rip -> ub1 [dirp] [i];				}				d1 = rip -> ub0 [dirp] [i];				if (d1 < ub1) {					d1 = ub1;				}				if (dstdirp > d1) continue;				rip -> lrindex [i] = lr;				LONGTERMS [longindex]	  = i;				LONGTERMS [longindex + 1] = -1;				break;			}			if (i < 0) {				/* This long leg has no further candidates! */				/* Mark it so we never try to do find any   */				/* more candidates! */				LONGTERMS [longindex] = -2;				break;			}		}		else {			/* Next long leg candidate available in longterms! */			p = &(pts -> a [i]);			lr = rip -> lrindex [i];			dstdirp = DSTDIRP (root, p, dir);		}		dstdir	 = DSTDIR (last, p, dir);		/* Check if consecutive terminals share Steiner point. */		if ((size >= 3) AND (dstdir EQ 0.0)) continue;		/* Update maximum backbone length using empty diamond */		/* property. */		if (dstdirp < dstdir) {			d1 = dstdir + dstdirp;			if (d1 < max_backbone) {				max_backbone = d1;			}		}		/* Update maximum backbone length using empty corner	*/		/* rectangle property.					*/		if ((size >= 2) AND (lr EQ lastlr) AND (dstdirp < lastdstdirp)) {			if (dstdir < max_backbone) {				max_backbone = dstdir;			}		}		/* Check length of new backbone segment */		if (dstdir > max_backbone) break;		if (lr EQ 2) {			/* Terminal is ON the backbone!	 Save	*/			/* immediately as type (i) and break.	*/			if (size >= 2) {				terms [size] = i;				test_and_save_fst (rip,						   size + 1,						   length + dstdir + dstdirp,						   dir,						   TYPE_1);			}			break;		}		/* Terminal on the wrong side of the long leg? */		if ((size >= 2) AND (lr EQ lastlr)) continue;		/* Empty rectangle with last terminal? */		if (NOT is_empty_rectangle (rip -> empty_rect, l, i)) continue;		/* Check if new backbone segment is longer than any BSD. */		pass_bsd = TRUE;		min_bsd	 = INF_DISTANCE;		for (j = 0; j < size; j++) {			k = terms [j];			d1 = rip -> maxedges [k];			if (dstdir > d1) {				d1 = dstdir;				rip -> maxedges [k] = d1;				need_to_restore = TRUE;			}			b = bsd (rip -> bsd, i, k);			if (d1 > b) {				pass_bsd = FALSE;				break;			}			if (b < min_bsd) {				min_bsd = b;			}		}		if (NOT pass_bsd) continue;		new_ub_length = ub_length + min_bsd;		/* dirp = (lr EQ 0) ? dir+3 : dir+1; */		dirp = (dir + (lr + lr - 1)) & 3;		/* Try to make a type (ii) FST */		j = rip -> shortterm [i];		if (j < 0) goto try_typeI;	/* no short leg candidate! */		/* Is backbone rectangle empty? */		if (NOT is_empty_rectangle (rip -> empty_rect, r, j)) goto try_typeI;		/* Check UB1. */		if (dstdirp > rip -> ub1 [dirp] [i]) goto try_typeI;		/* Check BSD for each terminal in current tree */		q = &(pts -> a [j]);		for (j2 = 0; j2 < size; j2++) {			k = terms [j2];			d1 = rip -> maxedges [k];			d2 = DSTDIRP (root, q, dir);			d3 = DSTDIRP (p, q, dir);			if (d2 > d1) {				d1 = d2;			}			/* d1 = MAX (maxedges [k], DSTDIRP (root, q, dir)) */			if (d1 > d3) {				d3 = d1;			}			/* d3 = MAX (d1, DSTDIRP (p, q, dir)) */			if (d3 > bsd (rip -> bsd, i, k)) goto try_typeI;			d3 = DSTDIR (p, q, dir);			if (d1 > d3) {				d3 = d1;			}			/* d3 = MAX (d1, DSTDIR (p, q, dir)) */			if (d3 > bsd (rip -> bsd, j, k)) goto try_typeI;		}#if UB_SHORTLEG		/* Check short leg upper bound */		if (DSTDIRP (root, q, dir) > ub_shortleg [lr]) goto try_growing;#endif		/* Perform FST specific tests and save type (ii) tree */		terms [size]		= i;		terms [size + 1]	= j;		test_and_save_fst (rip,				   size + 2,				   length + DSTDIR (last, q, dir)					  + DSTDIRP (root, p, dir),				   dir,				   TYPE_2);		/* Try to make a type (i) FST */try_typeI:		/* Check UB0 */		if (dstdirp > rip -> ub0 [dirp] [i]) continue;		/* Check BSD to each terminal in previous tree */		pass_bsd = TRUE;		for (j2 = 0; j2 < size; j2++) {			k = terms [j2];			d1 = rip -> maxedges [k];			if (dstdirp > d1) {				d1 = dstdirp;			}			if (d1 > bsd (rip -> bsd, k, i)) {				pass_bsd = FALSE;				break;			}		}		if (NOT pass_bsd) continue;		/* Check if BSD upper bound is shorter than partial tree */		/* (including connecting Steiner point).		 */		if (length + dstdir > new_ub_length) continue;		/* Check if BSD upper bound is shorter than partial tree */		if (length + dstdir + dstdirp > new_ub_length) goto try_growing;		/* Do not make 2-terminal FSTs (MST edges). */		if (size <= 1) goto try_growing;		/* Is backbone rectangle empty? */		if (NOT is_empty_rectangle (rip -> empty_rect, r, i)) goto try_growing;#if UB_SHORTLEG		/* Check short leg upper bound */		if (dstdirp > ub_shortleg [lr]) goto try_growing;#endif		/* Perform FST specific tests and save type (i) tree */		terms [size] = i;		new_ub_length = test_and_save_fst (rip,						   size + 1,						   length + dstdir + dstdirp,						   dir,						   TYPE_1);		/* Try to grow the current tree. */try_growing:		/* Should we generate larger FSTs? */		if (size >= MaxFSTSize) continue;		/* Upper bound (A). */		d1 = ub_shortleg [lr];		if (dstdirp < d1) {			d1 = dstdirp;		}		new_ub_shortleg [lr] = d1;		d1 = ub_shortleg [1-lr];		if (size >= 2) {			/* Upper bound (B). */			d2 = rip -> ub0 [dirp] [i];			if (min_bsd < d2) {				d2 = min_bsd;			}			d2 -= dstdirp;			if (d2 < d1) {				d1 = d2;			}			/* Upper bound (C). */			if (dstdir < d1) {				d1 = dstdir;			}			if (size >= 3) {				/* Upper bound (D). */				lp = terms [size - 2];				d2 = DSTDIRP (root, &(pts -> a [lp]), dir);				if (dstdirp < d2) {					d2 = dstdirp;				}				d2 = DSTDIR (&(pts -> a [lp]), p, dir) - d2;				if (d2 < d1) {					d1 = d2;				}			}		}		new_ub_shortleg [1-lr] = d1;		terms [size] = i;		rip -> maxedges [i] = dstdirp;		grow_RFST (rip,			   size + 1,			   length + dstdir + dstdirp,			   dir,			   new_ub_length,			   new_ub_shortleg,			   longindex);	}	if (need_to_restore) {		/* Restore caller's maxedges values.  We do this by	*/		/* recomputing them from scratch in a scan back toward	*/		/* the root.						*/		long_leg_max = 0.0;		for (i = size - 1; i > 0; i--) {			k = terms [i];			p = &(pts -> a [k]);			d1 = DSTDIRP (root, p, dir);			if (long_leg_max > d1) {				d1 = long_leg_max;			}			rip -> maxedges [k] = d1;			j = terms [i - 1];			q = &(pts -> a [j]);			d1 = DSTDIR (q, p, dir);			if (d1 > long_leg_max) {				long_leg_max = d1;			}		}		rip -> maxedges [r] = long_leg_max;	}}/* * This routine performs all of the FST specific screening tests. * If all are passed, the FST is saved. */	static	dist_ttest_and_save_fst (struct rinfo *	rip,		/* IN/OUT - The global RFST info */int		size,		/* IN - number of terminals in RFST */dist_t		length,		/* IN - length of RFST */int		dir,		/* IN - backbone growth direction from root */int		type		/* IN - type of tree */){int			i, j, k;int			z12, z13, z23;int			nstein;int			nedges;int			last;int *			terms;struct pset *		pts;struct point *		p1;struct point *		p2;struct point *		p3;struct point *		p4;struct rlist *		rp;struct rlist **		hookp;struct rlist *		rp1;struct rlist *		rp2;struct pset *		new_terms;struct pset *		new_steiners;dist_t			b;dist_t			d1;struct full_set *	fsp;struct edge *		edges;struct point		s1;struct point		s2;	++(rip -> fsts_checked);	terms = rip -> terms;	/* Is this FST too large? */	if (size > MaxFSTSize) return (length);	if (size > 2) {		b = bmst_terms_length (terms, size, rip -> bsd);		if (length >= b) return (b);	}	/* Simple duplicate tests for size 3 and 4 */	if (dir EQ 1) {		if (size EQ 3) return (length);		if ((size EQ 4) AND (type NE TYPE_1)) return (length);	}	pts = rip -> pts;	if (size > 4) {		/* No two terminals on the long leg should share a	*/		/* Steiner point.					*/		for (i = 1; i < size; i++) {			d1 = DSTDIR (&(pts -> a [terms [i-1]]),				     &(pts -> a [terms [i]]),				     dir);			if (d1 EQ 0.0) return (length);		}	}	else if (size EQ 4) {		p1 = &(pts -> a [terms [0]]);		p2 = &(pts -> a [terms [1]]);		if (DSTDIR (p1, p2, dir) EQ 0.0) return (length);		p3 = &(pts -> a [terms [2]]);		p4 = &(pts -> a [terms [3]]);		if (DSTDIR (p3, p4, dir) EQ 0.0) return (length);		if (DSTDIR (p2, p3, dir) EQ 0.0) {			if (DSTDIRP (p1, p4, dir) NE 0.0) {				return (length);			}			type = CROSS;		}	}	else if (size EQ 3) {		/* Make sure that 3-terminal FST is not degenerate */		p1 = &(pts -> a [terms [0]]);		p2 = &(pts -> a [terms [1]]);		p3 = &(pts -> a [terms [2]]);		z12 = (DSTDIR  (p1, p2, dir) EQ 0.0) + (DSTDIRP (p1, p2, dir) EQ 0.0);		z13 = (DSTDIR  (p1, p3, dir) EQ 0.0) + (DSTDIRP (p1, p3, dir) EQ 0.0);		z23 = (DSTDIR  (p2, p3, dir) EQ 0.0) + (DSTDIRP (p2, p3, dir) EQ 0.0);		if (z12 + z13 > 1) return (length);		if (z12 + z23 > 1) return (length);		if (z13 + z23 > 1) return (length);	}#if EMPTY_DIAMOND_PROPERTY	/* Check empty diamond property for transformed FST */	i = 0;	last = size - 1;	if (type EQ TYPE_2) {		last = size - 2;		if ((size & 1) EQ 0) {			i = 1;		/* type (ii), even */		}	}	else if ((size & 1) NE 0) {		i = 1;			/* type (i), odd */	}	p1 = &(pts -> a [terms [0]]);	p2 = &(pts -> a [terms [size-1]]);	while (i < last) {		/* Check skew diamond... */		SPOINT (&s1, p1, &(pts -> a [terms [i]]), dir);		SPOINT (&s2, p2, &(pts -> a [terms [i+1]]), dir);		if (NOT diamond_empty (rip, &s1, &s2, terms [i], dir)) {			return (length);		}		++i;		if (i >= last) break;		/* Check diamond for flat segment... */		SPOINT (&s1, p2, &(pts -> a [terms [i]]), dir);		SPOINT (&s2, p2, &(pts -> a [terms [i+1]]), dir);		if (NOT diamond_empty (rip, &s1, &s2, terms [i], dir)) {			return (length);		}		++i;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -