Blame siman/siman_tsp.c

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
}