www.pudn.com > geosteiner-3.1.zip > kr.c


/***********************************************************************

	File:	kr.c
	Rev:	b-1
	Date:	02/28/2001

	Copyright (c) 1993, 2001 by David M. Warme

************************************************************************

	Utility program to compute Kahng-Robins Steiner heuristic.

************************************************************************

	Modification Log:

	a-1:	05/21/96	warme
		: Created.
	b-1:	02/28/2001	warme
		: Changes for 3.1 release.
		: Fix Intel floating point precision problems.
		: Changes for new input scaling stuff.

************************************************************************/

#include "genps.h"
#include "steiner.h"


/*
 * Global Routines
 */

int			main (int, char **);


/*
 * External References
 */

	/* none */


/*
 * Local Routines
 */

static void		decode_params (int, char **);
static void		do_kahng_robins (struct pset *, struct scale_info *);
static void		do_minimum_spanning_tree (struct pset *,
						  struct scale_info *);
static void		usage (void);


/*
 * Local Variables
 */

static int32u		cpu_time_limit;
static char *		me;
static bool		Skip_Kahng_Robins		= FALSE;
static bool		Skip_Minimum_Spanning_Tree	= FALSE;

/*
 * Utility program to compute Minimum Spanning Tree and
 * 1-Steiner heuristic without doing a full Steiner tree.
 */

	int
main (

int		argc,
char **		argv
)
{
int			i;
int			fpsave;
cpu_time_t		T1;
struct pset *		pts;
struct scale_info	scale;

	fpsave = set_floating_point_double_precision ();

	setbuf (stdout, NULL);

	decode_params (argc, argv);

	pts = get_points (stdin, &scale);

	init_output_conversion (pts, RECTILINEAR, &scale);

	/* Enable CPU time limitation, if any. */
	start_limiting_cpu_time (cpu_time_limit);

	/* Prepare for plotting all terminals. */
	define_Plot_Terminals (pts, &scale);

	if (NOT Skip_Minimum_Spanning_Tree) {
		do_minimum_spanning_tree (pts, &scale);
	}
	if (NOT Skip_Kahng_Robins) {
		do_kahng_robins (pts, &scale);
	}

	free ((char *) pts);

	restore_floating_point_precision (fpsave);

	exit (0);
}

/*
 * This routine decodes the various command-line arguments.
 */

	static
	void
decode_params (

int		argc,
char **		argv
)
{
char *		ap;
char		c;

	--argc;
	me = *argv++;
	while (argc > 0) {
		ap = *argv++;
		if (*ap NE '-') {
			usage ();
		}
		++ap;
		while ((c = *ap++) NE '\0') {
			switch (c) {
			case 'k':
				Skip_Kahng_Robins = TRUE;
				break;

			case 'l':
				if (*ap EQ '\0') {
					if (argc <= 0) {
						usage ();
					}
					ap = *argv++;
					--argc;
				}
				if (NOT decode_cpu_time_limit (ap, &cpu_time_limit)) {
					usage ();
				}
				ap = "";
				break;

			case 'm':
				Skip_Minimum_Spanning_Tree = TRUE;
				break;

			default:
				usage ();
				break;
			}
		}
		--argc;
	}
}

/*
 * This routine prints out the proper usage and exits.
 */

static char *	arg_doc [] = {
	"",
	"\t-k\tDisables computation of Kahng-Robins Tree.",
	"\t-m\tDisables computation of Minimum Spanning Tree.",
	"",
	"\tExample CPU times are:",
	"\t\t-l 3days2hours30minutes15seconds",
	"\t\t-l1000seconds -l1000 -l 2h30m",
	"",
	NULL
};

	static
	void
usage (void)

{
char **		pp;
char *		p;

	(void) fprintf (stderr,
			"\nUsage: %s [-km] [-l cpu-time-limit]\n",
			me);
	pp = &arg_doc [0];
	while ((p = *pp++) NE NULL) {
		(void) fprintf (stderr, "%s\n", p);
	}
	exit (1);
}

/*
 * This routine computes and plots the Minimum Spanning Tree for the
 * given point set.
 */

	static
	void
do_minimum_spanning_tree (

struct pset *		pts,		/* IN - the set of terminals */
struct scale_info *	sip		/* IN - problem scaling info */
)
{
int			i;
int			n;
int			nedges;
cpu_time_t		T0;
cpu_time_t		T1;
struct edge *		ep;
struct point *		p1;
struct point *		p2;
dist_t			mst_len;
char			tbuf [20];
char			title [80];
struct edge *		m;
char			buf1 [32];

	n = pts -> n;

	m = NEWA (n - 1, struct edge);

	T0 = get_cpu_time ();
	nedges = rect_mst (pts, &m [0], NULL);

	T1 = get_cpu_time ();

	if (nedges NE n - 1) {
		fatal ("do_minimum_spanning_tree: Bug 1.");
	}

	(void) printf ("\n  %%  Minimum Spanning Tree\n");

	begin_plot (BIG_PLOT);
	(void) printf ("\tPlot_Terminals\n");
	mst_len = 0;
	for (i = 0; i < nedges; i++) {
		ep = &m [i];
		p1 = &(pts -> a [ep -> p1]);
		p2 = &(pts -> a [ep -> p2]);
		draw_segment (p1, p2, sip);
		mst_len += ep -> len;
	}
	convert_cpu_time (T1 - T0, tbuf);
	dist_to_string (buf1, mst_len, sip);
	(void) sprintf (title, "Minimum Spanning Tree:  %lu points,  length = %s,  %s seconds",
			(int32u) n, buf1, tbuf);
	end_plot (title);

	free ((char *) m);
}

/*
 * This routine computes an approximate Steiner Minimal Tree using
 * the Kahng-Robins heuristic, and plots the result.
 */

	static
	void
do_kahng_robins (

struct pset *		pts,		/* IN - the set of terminals */
struct scale_info *	sip		/* IN - problem scaling info */
)
{
int			i;
int			n;
int			nedges;
cpu_time_t		T0;
cpu_time_t		T1;
struct pset *		newpts;
struct edge *		ep;
struct point *		p1;
struct point *		p2;
dist_t			kr_len;
char			tbuf [20];
char			title [80];
struct edge *		m;
char			buf1 [32];

	n = pts -> n;

	/* Make a temporary copy, big enough to hold the Steiner points too. */
	newpts = NEW_PSET (n + n - 2);
	COPY_PSET (newpts, pts);

	m = NEWA (n + n - 3, struct edge);

	T0 = get_cpu_time ();

	nedges = kahng_robins (newpts, 0, &m [0]);

	T1 = get_cpu_time ();

	(void) printf ("\n  %%  Kahng Robins\n");

	begin_plot (BIG_PLOT);
	(void) printf ("\tPlot_Terminals\n");
	kr_len = 0;
	for (i = 0; i < nedges; i++) {
		ep = &m [i];
		p1 = &(newpts -> a [ep -> p1]);
		p2 = &(newpts -> a [ep -> p2]);
		draw_segment (p1, p2, sip);
		kr_len += ep -> len;
	}
	convert_cpu_time (T1 - T0, tbuf);
	dist_to_string (buf1, kr_len, sip);
	(void) sprintf (title, "1-Steiner Heuristic:  %lu points,  length = %s,  %s seconds",
			(int32u) n, buf1, tbuf);
	end_plot (title);

	free ((char *) m);
	free ((char *) newpts);
}