|
Packit |
67cb25 |
/* siman/siman_tsp.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 1996, 1997, 1998, 1999, 2000 Mark Galassi
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <math.h>
|
|
Packit |
67cb25 |
#include <string.h>
|
|
Packit |
67cb25 |
#include <stdio.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_rng.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_siman.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_ieee_utils.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* set up parameters for this simulated annealing run */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define N_TRIES 200 /* how many points do we try before stepping */
|
|
Packit |
67cb25 |
#define ITERS_FIXED_T 2000 /* how many iterations for each T? */
|
|
Packit |
67cb25 |
#define STEP_SIZE 1.0 /* max step size in random walk */
|
|
Packit |
67cb25 |
#define K 1.0 /* Boltzmann constant */
|
|
Packit |
67cb25 |
#define T_INITIAL 5000.0 /* initial temperature */
|
|
Packit |
67cb25 |
#define MU_T 1.002 /* damping factor for temperature */
|
|
Packit |
67cb25 |
#define T_MIN 5.0e-1
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_siman_params_t params = {N_TRIES, ITERS_FIXED_T, STEP_SIZE,
|
|
Packit |
67cb25 |
K, T_INITIAL, MU_T, T_MIN};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
struct s_tsp_city {
|
|
Packit |
67cb25 |
const char * name;
|
|
Packit |
67cb25 |
double lat, longitude; /* coordinates */
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
typedef struct s_tsp_city Stsp_city;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void prepare_distance_matrix(void);
|
|
Packit |
67cb25 |
void exhaustive_search(void);
|
|
Packit |
67cb25 |
void print_distance_matrix(void);
|
|
Packit |
67cb25 |
double city_distance(Stsp_city c1, Stsp_city c2);
|
|
Packit |
67cb25 |
double Etsp(void *xp);
|
|
Packit |
67cb25 |
double Mtsp(void *xp, void *yp);
|
|
Packit |
67cb25 |
void Stsp(const gsl_rng * r, void *xp, double step_size);
|
|
Packit |
67cb25 |
void Ptsp(void *xp);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* in this table, latitude and longitude are obtained from the US
|
|
Packit |
67cb25 |
Census Bureau, at http://www.census.gov/cgi-bin/gazetteer */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Stsp_city cities[] = {{"Santa Fe", 35.68, 105.95},
|
|
Packit |
67cb25 |
{"Phoenix", 33.54, 112.07},
|
|
Packit |
67cb25 |
{"Albuquerque", 35.12, 106.62},
|
|
Packit |
67cb25 |
{"Clovis", 34.41, 103.20},
|
|
Packit |
67cb25 |
{"Durango", 37.29, 107.87},
|
|
Packit |
67cb25 |
{"Dallas", 32.79, 96.77},
|
|
Packit |
67cb25 |
{"Tesuque", 35.77, 105.92},
|
|
Packit |
67cb25 |
{"Grants", 35.15, 107.84},
|
|
Packit |
67cb25 |
{"Los Alamos", 35.89, 106.28},
|
|
Packit |
67cb25 |
{"Las Cruces", 32.34, 106.76},
|
|
Packit |
67cb25 |
{"Cortez", 37.35, 108.58},
|
|
Packit |
67cb25 |
{"Gallup", 35.52, 108.74}};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define N_CITIES (sizeof(cities)/sizeof(Stsp_city))
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double distance_matrix[N_CITIES][N_CITIES];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* distance between two cities */
|
|
Packit |
67cb25 |
double city_distance(Stsp_city c1, Stsp_city c2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double earth_radius = 6375.000; /* 6000KM approximately */
|
|
Packit |
67cb25 |
/* sin and cos of lat and long; must convert to radians */
|
|
Packit |
67cb25 |
double sla1 = sin(c1.lat*M_PI/180), cla1 = cos(c1.lat*M_PI/180),
|
|
Packit |
67cb25 |
slo1 = sin(c1.longitude*M_PI/180), clo1 = cos(c1.longitude*M_PI/180);
|
|
Packit |
67cb25 |
double sla2 = sin(c2.lat*M_PI/180), cla2 = cos(c2.lat*M_PI/180),
|
|
Packit |
67cb25 |
slo2 = sin(c2.longitude*M_PI/180), clo2 = cos(c2.longitude*M_PI/180);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double x1 = cla1*clo1;
|
|
Packit |
67cb25 |
double x2 = cla2*clo2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double y1 = cla1*slo1;
|
|
Packit |
67cb25 |
double y2 = cla2*slo2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double z1 = sla1;
|
|
Packit |
67cb25 |
double z2 = sla2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double dot_product = x1*x2 + y1*y2 + z1*z2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double angle = acos(dot_product);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* distance is the angle (in radians) times the earth radius */
|
|
Packit |
67cb25 |
return angle*earth_radius;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* energy for the travelling salesman problem */
|
|
Packit |
67cb25 |
double Etsp(void *xp)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* an array of N_CITIES integers describing the order */
|
|
Packit |
67cb25 |
int *route = (int *) xp;
|
|
Packit |
67cb25 |
double E = 0;
|
|
Packit |
67cb25 |
unsigned int i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
/* use the distance_matrix to optimize this calculation; it had
|
|
Packit |
67cb25 |
better be allocated!! */
|
|
Packit |
67cb25 |
E += distance_matrix[route[i]][route[(i + 1) % N_CITIES]];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return E;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double Mtsp(void *xp, void *yp)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int *route1 = (int *) xp, *route2 = (int *) yp;
|
|
Packit |
67cb25 |
double distance = 0;
|
|
Packit |
67cb25 |
unsigned int i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
distance += ((route1[i] == route2[i]) ? 0 : 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return distance;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* take a step through the TSP space */
|
|
Packit |
67cb25 |
void Stsp(const gsl_rng * r, void *xp, double step_size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int x1, x2, dummy;
|
|
Packit |
67cb25 |
int *route = (int *) xp;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
step_size = 0 ; /* prevent warnings about unused parameter */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* pick the two cities to swap in the matrix; we leave the first
|
|
Packit |
67cb25 |
city fixed */
|
|
Packit |
67cb25 |
x1 = (gsl_rng_get (r) % (N_CITIES-1)) + 1;
|
|
Packit |
67cb25 |
do {
|
|
Packit |
67cb25 |
x2 = (gsl_rng_get (r) % (N_CITIES-1)) + 1;
|
|
Packit |
67cb25 |
} while (x2 == x1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dummy = route[x1];
|
|
Packit |
67cb25 |
route[x1] = route[x2];
|
|
Packit |
67cb25 |
route[x2] = dummy;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void Ptsp(void *xp)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
unsigned int i;
|
|
Packit |
67cb25 |
int *route = (int *) xp;
|
|
Packit |
67cb25 |
printf(" [");
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
printf(" %d ", route[i]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
printf("] ");
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int main(void)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int x_initial[N_CITIES];
|
|
Packit |
67cb25 |
unsigned int i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
const gsl_rng * r = gsl_rng_alloc (gsl_rng_env_setup()) ;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_ieee_env_setup ();
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
prepare_distance_matrix();
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* set up a trivial initial route */
|
|
Packit |
67cb25 |
printf("# initial order of cities:\n");
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
printf("# \"%s\"\n", cities[i].name);
|
|
Packit |
67cb25 |
x_initial[i] = i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# distance matrix is:\n");
|
|
Packit |
67cb25 |
print_distance_matrix();
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# initial coordinates of cities (longitude and latitude)\n");
|
|
Packit |
67cb25 |
/* this can be plotted with */
|
|
Packit |
67cb25 |
/* ./siman_tsp > hhh ; grep city_coord hhh | awk '{print $2 " " $3}' | xyplot -ps -d "xy" > c.eps */
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES+1; ++i) {
|
|
Packit |
67cb25 |
printf("###initial_city_coord: %g %g \"%s\"\n",
|
|
Packit |
67cb25 |
-cities[x_initial[i % N_CITIES]].longitude,
|
|
Packit |
67cb25 |
cities[x_initial[i % N_CITIES]].lat,
|
|
Packit |
67cb25 |
cities[x_initial[i % N_CITIES]].name);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* exhaustive_search(); */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_siman_solve(r, x_initial, Etsp, Stsp, Mtsp, Ptsp, NULL, NULL, NULL,
|
|
Packit |
67cb25 |
N_CITIES*sizeof(int), params);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# final order of cities:\n");
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
printf("# \"%s\"\n", cities[x_initial[i]].name);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# final coordinates of cities (longitude and latitude)\n");
|
|
Packit |
67cb25 |
/* this can be plotted with */
|
|
Packit |
67cb25 |
/* ./siman_tsp > hhh ; grep city_coord hhh | awk '{print $2 " " $3}' | xyplot -ps -d "xy" > c.eps */
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES+1; ++i) {
|
|
Packit |
67cb25 |
printf("###final_city_coord: %g %g %s\n",
|
|
Packit |
67cb25 |
-cities[x_initial[i % N_CITIES]].longitude,
|
|
Packit |
67cb25 |
cities[x_initial[i % N_CITIES]].lat,
|
|
Packit |
67cb25 |
cities[x_initial[i % N_CITIES]].name);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# ");
|
|
Packit |
67cb25 |
fflush(stdout);
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
system("date");
|
|
Packit |
67cb25 |
#endif /* 0 */
|
|
Packit |
67cb25 |
fflush(stdout);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return 0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void prepare_distance_matrix()
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
unsigned int i, j;
|
|
Packit |
67cb25 |
double dist;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
for (j = 0; j < N_CITIES; ++j) {
|
|
Packit |
67cb25 |
if (i == j) {
|
|
Packit |
67cb25 |
dist = 0;
|
|
Packit |
67cb25 |
} else {
|
|
Packit |
67cb25 |
dist = city_distance(cities[i], cities[j]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
distance_matrix[i][j] = dist;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void print_distance_matrix()
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
unsigned int i, j;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < N_CITIES; ++i) {
|
|
Packit |
67cb25 |
printf("# ");
|
|
Packit |
67cb25 |
for (j = 0; j < N_CITIES; ++j) {
|
|
Packit |
67cb25 |
printf("%15.8f ", distance_matrix[i][j]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
printf("\n");
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* [only works for 12] search the entire space for solutions */
|
|
Packit |
67cb25 |
static double best_E = 1.0e100, second_E = 1.0e100, third_E = 1.0e100;
|
|
Packit |
67cb25 |
static int best_route[N_CITIES];
|
|
Packit |
67cb25 |
static int second_route[N_CITIES];
|
|
Packit |
67cb25 |
static int third_route[N_CITIES];
|
|
Packit |
67cb25 |
static void do_all_perms(int *route, int n);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void exhaustive_search()
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
static int initial_route[N_CITIES] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
|
Packit |
67cb25 |
printf("\n# ");
|
|
Packit |
67cb25 |
fflush(stdout);
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
system("date");
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
fflush(stdout);
|
|
Packit |
67cb25 |
do_all_perms(initial_route, 1);
|
|
Packit |
67cb25 |
printf("\n# ");
|
|
Packit |
67cb25 |
fflush(stdout);
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
system("date");
|
|
Packit |
67cb25 |
#endif /* 0 */
|
|
Packit |
67cb25 |
fflush(stdout);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# exhaustive best route: ");
|
|
Packit |
67cb25 |
Ptsp(best_route);
|
|
Packit |
67cb25 |
printf("\n# its energy is: %g\n", best_E);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# exhaustive second_best route: ");
|
|
Packit |
67cb25 |
Ptsp(second_route);
|
|
Packit |
67cb25 |
printf("\n# its energy is: %g\n", second_E);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
printf("# exhaustive third_best route: ");
|
|
Packit |
67cb25 |
Ptsp(third_route);
|
|
Packit |
67cb25 |
printf("\n# its energy is: %g\n", third_E);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* James Theiler's recursive algorithm for generating all routes */
|
|
Packit |
67cb25 |
static void do_all_perms(int *route, int n)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (n == (N_CITIES-1)) {
|
|
Packit |
67cb25 |
/* do it! calculate the energy/cost for that route */
|
|
Packit |
67cb25 |
double E;
|
|
Packit |
67cb25 |
E = Etsp(route); /* TSP energy function */
|
|
Packit |
67cb25 |
/* now save the best 3 energies and routes */
|
|
Packit |
67cb25 |
if (E < best_E) {
|
|
Packit |
67cb25 |
third_E = second_E;
|
|
Packit |
67cb25 |
memcpy(third_route, second_route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
second_E = best_E;
|
|
Packit |
67cb25 |
memcpy(second_route, best_route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
best_E = E;
|
|
Packit |
67cb25 |
memcpy(best_route, route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
} else if (E < second_E) {
|
|
Packit |
67cb25 |
third_E = second_E;
|
|
Packit |
67cb25 |
memcpy(third_route, second_route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
second_E = E;
|
|
Packit |
67cb25 |
memcpy(second_route, route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
} else if (E < third_E) {
|
|
Packit |
67cb25 |
third_E = E;
|
|
Packit |
67cb25 |
memcpy(route, third_route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} else {
|
|
Packit |
67cb25 |
int new_route[N_CITIES];
|
|
Packit |
67cb25 |
unsigned int j;
|
|
Packit |
67cb25 |
int swap_tmp;
|
|
Packit |
67cb25 |
memcpy(new_route, route, N_CITIES*sizeof(*route));
|
|
Packit |
67cb25 |
for (j = n; j < N_CITIES; ++j) {
|
|
Packit |
67cb25 |
swap_tmp = new_route[j];
|
|
Packit |
67cb25 |
new_route[j] = new_route[n];
|
|
Packit |
67cb25 |
new_route[n] = swap_tmp;
|
|
Packit |
67cb25 |
do_all_perms(new_route, n+1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|