[GRASS-SVN] r51609 - grass/branches/develbranch_6/vector/v.net.salesman

svn_grass at osgeo.org svn_grass at osgeo.org
Wed May 9 08:34:37 EDT 2012


Author: mmetz
Date: 2012-05-09 05:34:37 -0700 (Wed, 09 May 2012)
New Revision: 51609

Modified:
   grass/branches/develbranch_6/vector/v.net.salesman/main.c
Log:
v.net.salesman: backport enhancements from trunk

Modified: grass/branches/develbranch_6/vector/v.net.salesman/main.c
===================================================================
--- grass/branches/develbranch_6/vector/v.net.salesman/main.c	2012-05-09 12:33:08 UTC (rev 51608)
+++ grass/branches/develbranch_6/vector/v.net.salesman/main.c	2012-05-09 12:34:37 UTC (rev 51609)
@@ -74,14 +74,35 @@
 
 }
 
+/* like Vect_list_append(), but allows duplicates */
+int tsp_list_append(struct ilist *list, int val)
+{
+    size_t size;
 
+    if (list == NULL)
+	return 1;
+
+    if (list->n_values == list->alloc_values) {
+	size = (list->n_values + 1000) * sizeof(int);
+	list->value = (int *)G_realloc((void *)list->value, size);
+	list->alloc_values = list->n_values + 1000;
+    }
+
+    list->value[list->n_values] = val;
+    list->n_values++;
+
+    return 0;
+}
+
+
 int main(int argc, char **argv)
 {
     int i, j, k, ret, city, city1;
     int nlines, type, ltype, afield, tfield, geo, cat;
     int node, node1, node2, line;
+    double **cost_cache;			/* pointer to array of pointers to arrays of cached costs */
     struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *abcol,
-	*type_opt, *term_opt;
+	*seq, *type_opt, *term_opt;
     struct Flag *geo_f;
     struct GModule *module;
     char *mapset;
@@ -95,6 +116,9 @@
     struct line_cats *Cats;
     struct line_pnts *Points;
     const char *dstr;
+    const char *seqname;
+    int seq2stdout;
+    FILE *fp;
 
     /* Initialize the GIS calls */
     G_gisinit(argv[0]);
@@ -137,6 +161,12 @@
     abcol->required = NO;
     abcol->description = _("EXPERIMENTAL: Arc backward direction cost column (number)");
 
+    seq = G_define_standard_option(G_OPT_F_OUTPUT);
+    seq->key = "sequence";
+    seq->type = TYPE_STRING;
+    seq->required = NO;
+    seq->description = _("Name for output file holding node sequence (\"-\" for stdout)");
+
     term_opt = G_define_standard_option(G_OPT_V_CATS);
     term_opt->key = "ccats";
     term_opt->required = YES;
@@ -207,7 +237,7 @@
 	    if (!(Vect_cat_get(Cats, tfield, &cat)))
 		continue;
 	    if (Vect_cat_in_cat_list(cat, Clist)) {
-		Vect_list_append(TList, i);
+		tsp_list_append(TList, i);
 	    }
 	}
     }
@@ -229,6 +259,10 @@
     for (i = 0; i < ncities; i++) {
 	costs[i] = (COST *) G_malloc(ncities * sizeof(COST));
     }
+    cost_cache = (double **) G_malloc(ncities * sizeof(double *));
+    for (i = 0; i < ncities; i++) {
+	cost_cache[i] = (double *) G_malloc(ncities * sizeof(double));
+    }
     if (abcol->answer) {
 	bcosts = (COST **) G_malloc(ncities * sizeof(COST *));
 	for (i = 0; i < ncities; i++) {
@@ -246,11 +280,15 @@
 
     /* Create sorted lists of costs */
     /* for a large number of cities this will become very slow, can not be fixed */
+    G_message(_("Creating cost cache..."));
     for (i = 0; i < ncities; i++) {
+	G_percent(i, ncities, 2);
 	k = 0;
 	for (j = 0; j < ncities; j++) {
+	    cost_cache[i][j] = 0.0;
 	    if (i == j)
 		continue;
+
 	    ret =
 		Vect_net_shortest_path(&Map, cities[i], cities[j], NULL,
 				       &cost);
@@ -259,35 +297,29 @@
 		G_fatal_error(_("Destination node [%d] is unreachable "
 				"from node [%d]"), cities[i], cities[j]);
 
-	    /* TODO: add to directional cost cache: from, to, cost */
+	    /* add to directional cost cache: from, to, cost */
 	    costs[i][k].city = j;
 	    costs[i][k].cost = cost;
+	    cost_cache[i][j] = cost;
 
 	    k++;
 	}
 	qsort((void *)costs[i], k, sizeof(COST), cmp);
     }
+    G_percent(1, 1, 2);
     
     if (bcosts) {
 	for (i = 0; i < ncities; i++) {
+	    /* this should be fast, no need for G_percent() */
 	    k = 0;
 	    for (j = 0; j < ncities; j++) {
 		if (i == j)
 		    continue;
 		    
-		/* TODO: get cost from directional cost cache */
-		/* from = cities[j], to = cities[i] */
-		ret =
-		    Vect_net_shortest_path(&Map, cities[j], cities[i], NULL,
-					   &cost);
-		if (ret == -1)
-		    G_fatal_error(_("Destination node [%d] is unreachable "
-				    "from node [%d]"), cities[j], cities[i]);
-		
-		if (bcosts[i][k].cost > cost) {
-		    bcosts[i][k].cost = cost;
-		}
-		    k++;
+		bcosts[i][k].city = j;
+		bcosts[i][k].cost = cost_cache[j][i];
+
+		k++;
 	    }
 	    qsort((void *)bcosts[i], k, sizeof(COST), cmp);
 	}
@@ -304,6 +336,7 @@
 	}
     }
 
+    G_message(_("Searching for the shortest cycle..."));
     /* find 2 cities with largest distance */
     cost = city = -1;
     for (i = 0; i < ncities; i++) {
@@ -324,6 +357,7 @@
      *  into cycle between 2 nearest nodes */
     /* for a large number of cities this will become very slow, can be fixed */
     for (i = 0; i < ncities - 2; i++) {
+	G_percent(i, ncities - 3, 1);
 	cost = -1;
 	G_debug(2, "---- city %d ----", i);
 	for (j = 0; j < ncities; j++) {
@@ -331,7 +365,7 @@
 		continue;
 	    tmpcost = 0;
 	    for (k = 0; k < ncities - 1; k++) {
-		G_debug(2, "? %d (%d) - %d (%d)", j, cnode(j),
+		G_debug(2, "forward? %d (%d) - %d (%d)", j, cnode(j),
 			costs[j][k].city, cnode(costs[j][k].city));
 		if (!cused[costs[j][k].city])
 		    continue;	/* only used */
@@ -342,11 +376,11 @@
 	    /* forward/backward: tmpcost = min(fcost) + min(bcost) */
 	    if (bcosts) {
 		for (k = 0; k < ncities - 1; k++) {
-		    G_debug(2, "? %d (%d) - %d (%d)", j, cnode(j),
+		    G_debug(2, "backward? %d (%d) - %d (%d)", j, cnode(j),
 			    bcosts[j][k].city, cnode(bcosts[j][k].city));
 		    if (!cused[bcosts[j][k].city])
 			continue;	/* only used */
-		    /* directional costs j -> k */
+		    /* directional costs k -> j */
 		    tmpcost += bcosts[j][k].cost;
 		    break;		/* first nearest */
 		}
@@ -366,24 +400,19 @@
 	city1 = 0;
 	for (j = 0; j < ncyc; j++) {
 	    /* cost from j to j + 1 (directional) */
-	    node1 = cities[cycle[j]];
-	    node2 = cities[cycle[j + 1]];
-	    /* TODO: get cost from directional cost cache */
-	    /* from = cities[cycle[j]], to = cities[cycle[j + 1]] */
-	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost);
+	    /* get cost from directional cost cache */
+	    tcost = cost_cache[cycle[j]][cycle[j + 1]];
 	    tmpcost = -tcost;
+
 	    /* check insertion of city between j and j + 1 */
+
 	    /* cost from j to city (directional) */
-	    node1 = cities[cycle[j]];
-	    node2 = cities[city];
-	    /* TODO: get cost from directional cost cache */
-	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost);
+	    /* get cost from directional cost cache */
+	    tcost = cost_cache[cycle[j]][city];
 	    tmpcost += tcost;
 	    /* cost from city to j + 1 (directional) */
-	    node1 = cities[city];
-	    node2 = cities[cycle[j + 1]];
-	    /* TODO: get cost from directional cost cache */
-	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost);
+	    /* get cost from directional cost cache */
+	    tcost = cost_cache[city][cycle[j + 1]];
 	    tmpcost += tcost;
 	    
 	    /* tmpcost must always be > 0 */
@@ -396,10 +425,10 @@
 		cost = tmpcost;
 	    }
 	}
-
 	add_city(city, city1);
-
     }
+    
+    /* TODO: optimize tour (some Lin–Kernighan method) */
 
     if (debug_level >= 2) {
 	/* debug print */
@@ -411,61 +440,88 @@
 
     /* Create list of arcs */
     cycle[ncities] = cycle[0];  /* close the cycle */
+    cost = 0.0;
     for (i = 0; i < ncities; i++) {
 	node1 = cities[cycle[i]];
 	node2 = cities[cycle[i + 1]];
 	G_debug(2, " %d -> %d", node1, node2);
 	ret = Vect_net_shortest_path(&Map, node1, node2, List, NULL);
+	cost += cost_cache[cycle[i]][cycle[i + 1]];
 	for (j = 0; j < List->n_values; j++) {
 	    line = abs(List->value[j]);
-	    Vect_list_append(StArcs, line);
+	    /* Vect_list_append() appends only if value not yet present !!! 
+	     * this breaks the correct sequence */
+	    tsp_list_append(StArcs, line);
 	    Vect_get_line_nodes(&Map, line, &node1, &node2);
-	    Vect_list_append(StNodes, node1);
-	    Vect_list_append(StNodes, node2);
+	    tsp_list_append(StNodes, node1);
+	    tsp_list_append(StNodes, node2);
 	}
     }
 
-
-
     /* Write arcs to new map */
     Vect_open_new(&Out, output->answer, Vect_is_3d(&Map));
     Vect_hist_command(&Out);
 
-    fprintf(stdout, "\nCycle:\n");
-    fprintf(stdout, "Arcs' categories (layer %d, %d arcs):\n", afield,
+    G_verbose_message(_("Cycle with total cost %.3f"), cost);
+    G_debug(2, "Arcs' categories (layer %d, %d arcs):", afield,
 	    StArcs->n_values);
+
     for (i = 0; i < StArcs->n_values; i++) {
 	line = StArcs->value[i];
 	ltype = Vect_read_line(&Map, Points, Cats, line);
 	Vect_write_line(&Out, ltype, Points, Cats);
 	Vect_cat_get(Cats, afield, &cat);
-	if (i > 0)
-	    printf(",");
-	fprintf(stdout, "%d", cat);
+	G_debug(2, "%d. arc: cat %d", i + 1, cat);
     }
-    fprintf(stdout, "\n\n");
+    
+    seq2stdout = 0;
+    seqname = NULL;
+    if (seq->answer) {
+	if (strcmp(seq->answer, "-")) {
+	    seqname = seq->answer;
+	}
+	else {
+	    seqname = G_tempfile();
+	    seq2stdout = 1;
+	}
 
-    fprintf(stdout, "Nodes' categories (layer %d, %d nodes):\n", tfield,
-	    StNodes->n_values);
+	fp = fopen(seqname, "w");
+	if (!fp)
+	    G_fatal_error(_("Unable to open file '%s' for writing"),
+			  seqname);
+
+	fprintf(fp, "sequence;category;cost_to_next\n");
+    }
+    else
+	fp = NULL;
+
     k = 0;
-    for (i = 0; i < StNodes->n_values; i++) {
-	node = StNodes->value[i];
-	nlines = Vect_get_node_n_lines(&Map, node);
-	for (j = 0; j < nlines; j++) {
-	    line = abs(Vect_get_node_line(&Map, node, j));
-	    ltype = Vect_read_line(&Map, Points, Cats, line);
-	    if (!(ltype & GV_POINT))
-		continue;
-	    if (!(Vect_cat_get(Cats, tfield, &cat)))
-		continue;
-	    Vect_write_line(&Out, ltype, Points, Cats);
-	    if (k > 0)
-		fprintf(stdout, ",");
-	    fprintf(stdout, "%d", cat);
-	    k++;
+    /* this writes out only user-selected nodes, not all visited nodes */
+    G_debug(2, "Nodes' categories (layer %d, %d nodes):", tfield,
+	    ncities);
+    for (i = 0; i < ncities; i++) {
+	double coor_x, coor_y, coor_z;
+	
+	node = cities[cycle[i]];
+	Vect_get_node_coor(&Map, node, &coor_x, &coor_y, &coor_z);
+	line = Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0, 0, 0);
+	
+	if (!line)
+	    continue;
+
+	ltype = Vect_read_line(&Map, Points, Cats, line);
+	if (!(ltype & GV_POINT))
+	    continue;
+	if (!(Vect_cat_get(Cats, tfield, &cat)))
+	    continue;
+	Vect_write_line(&Out, ltype, Points, Cats);
+	k++;
+	if (fp) {
+	    fprintf(fp, "%d;%d;%.3f\n", k, cat, cost_cache[cycle[i]][cycle[i + 1]]);
 	}
+
+	G_debug(2, "%d. node: cat %d", k, cat);
     }
-    fprintf(stdout, "\n\n");
 
     Vect_build(&Out);
 
@@ -475,6 +531,23 @@
     Vect_close(&Map);
     Vect_close(&Out);
 
+    if (fp) {
+	fclose(fp);
+	if (seq2stdout) {
+	    char buf[2000];
+
+	    /* spacer to previous output to stderr */
+	    G_message(" ");
+
+	    fp = fopen(seqname, "r");
+	    while (G_getl2(buf, 2000, fp) != 0)
+		fprintf(stdout, "%s\n", buf);
+
+	    fclose(fp);
+	    remove(seqname);
+	}
+    }
+
     exit(EXIT_SUCCESS);
 }
 



More information about the grass-commit mailing list