src/glptsp.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     1 /* glptsp.c */
     2 
     3 /***********************************************************************
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
     5 *
     6 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
     7 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
     8 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
     9 *  E-mail: <mao@gnu.org>.
    10 *
    11 *  GLPK is free software: you can redistribute it and/or modify it
    12 *  under the terms of the GNU General Public License as published by
    13 *  the Free Software Foundation, either version 3 of the License, or
    14 *  (at your option) any later version.
    15 *
    16 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
    17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    18 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    19 *  License for more details.
    20 *
    21 *  You should have received a copy of the GNU General Public License
    22 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    23 ***********************************************************************/
    24 
    25 #define _GLPSTD_ERRNO
    26 #define _GLPSTD_STDIO
    27 #include "glpenv.h"
    28 #include "glptsp.h"
    29 #define xfault xerror
    30 
    31 /*----------------------------------------------------------------------
    32 -- tsp_read_data - read TSP instance data.
    33 --
    34 -- *Synopsis*
    35 --
    36 -- #include "glptsp.h"
    37 -- TSP *tsp_read_data(char *fname);
    38 --
    39 -- *Description*
    40 --
    41 -- The routine tsp_read_data reads a TSP (or related problem) instance
    42 -- data from the text file, whose name is the character string fname.
    43 --
    44 -- For detailed description of the format recognized by the routine see
    45 -- the report: G.Reinelt, TSPLIB 95.
    46 --
    47 -- *Returns*
    48 --
    49 -- If no error occurred, the routine tsp_read_data returns a pointer to
    50 -- the TSP instance data block, which contains loaded data. In the case
    51 -- of error the routine prints an error message and returns NULL. */
    52 
    53 struct dsa
    54 {     /* dynamic storage area used by the routine tsp_read_data */
    55       char *fname;
    56       /* name of the input text file */
    57       FILE *fp;
    58       /* stream assigned to the input text file */
    59       int seqn;
    60       /* line sequential number */
    61       int c;
    62       /* current character */
    63       char token[255+1];
    64       /* current token */
    65 };
    66 
    67 static int get_char(struct dsa *dsa)
    68 {     dsa->c = fgetc(dsa->fp);
    69       if (ferror(dsa->fp))
    70       {  xprintf("%s:%d: read error - %s\n",
    71             dsa->fname, dsa->seqn, strerror(errno));
    72          return 1;
    73       }
    74       if (feof(dsa->fp))
    75          dsa->c = EOF;
    76       else if (dsa->c == '\n')
    77          dsa->seqn++;
    78       else if (isspace(dsa->c))
    79          dsa->c = ' ';
    80       else if (iscntrl(dsa->c))
    81       {  xprintf("%s:%d: invalid control character 0x%02X\n",
    82             dsa->fname, dsa->seqn, dsa->c);
    83          return 1;
    84       }
    85       return 0;
    86 }
    87 
    88 static int skip_spaces(struct dsa *dsa, int across)
    89 {     while (dsa->c == ' ' || (across && dsa->c == '\n'))
    90          if (get_char(dsa)) return 1;
    91       return 0;
    92 }
    93 
    94 static int scan_keyword(struct dsa *dsa)
    95 {     int len = 0;
    96       if (skip_spaces(dsa, 0)) return 1;
    97       dsa->token[0] = '\0';
    98       while (isalnum(dsa->c) || dsa->c == '_')
    99       {  if (len == 31)
   100          {  xprintf("%s:%d: keyword `%s...' too long\n", dsa->fname,
   101                dsa->seqn, dsa->token);
   102             return 1;
   103          }
   104          dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
   105          if (get_char(dsa)) return 1;
   106       }
   107       if (len == 0)
   108       {  xprintf("%s:%d: missing keyword\n", dsa->fname, dsa->seqn);
   109          return 1;
   110       }
   111       return 0;
   112 }
   113 
   114 static int check_colon(struct dsa *dsa)
   115 {     if (skip_spaces(dsa, 0)) return 1;
   116       if (dsa->c != ':')
   117       {  xprintf("%s:%d: missing colon after `%s'\n", dsa->fname,
   118             dsa->seqn, dsa->token);
   119          return 1;
   120       }
   121       if (get_char(dsa)) return 1;
   122       return 0;
   123 }
   124 
   125 static int scan_token(struct dsa *dsa, int across)
   126 {     int len = 0;
   127       if (skip_spaces(dsa, across)) return 1;
   128       dsa->token[0] = '\0';
   129       while (!(dsa->c == EOF || dsa->c == '\n' || dsa->c == ' '))
   130       {  if (len == 255)
   131          {  dsa->token[31] = '\0';
   132             xprintf("%s:%d: token `%s...' too long\n", dsa->fname,
   133                dsa->seqn, dsa->token);
   134             return 1;
   135          }
   136          dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
   137          if (get_char(dsa)) return 1;
   138       }
   139       return 0;
   140 }
   141 
   142 static int check_newline(struct dsa *dsa)
   143 {     if (skip_spaces(dsa, 0)) return 1;
   144       if (!(dsa->c == EOF || dsa->c == '\n'))
   145       {  xprintf("%s:%d: extra symbols detected\n", dsa->fname,
   146             dsa->seqn);
   147          return 1;
   148       }
   149       if (get_char(dsa)) return 1;
   150       return 0;
   151 }
   152 
   153 static int scan_comment(struct dsa *dsa)
   154 {     int len = 0;
   155       if (skip_spaces(dsa, 0)) return 1;
   156       dsa->token[0] = '\0';
   157       while (!(dsa->c == EOF || dsa->c == '\n'))
   158       {  if (len == 255)
   159          {  xprintf("%s:%d: comment too long\n", dsa->fname, dsa->seqn)
   160                ;
   161             return 1;
   162          }
   163          dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
   164          if (get_char(dsa)) return 1;
   165       }
   166       return 0;
   167 }
   168 
   169 static int scan_integer(struct dsa *dsa, int across, int *val)
   170 {     if (scan_token(dsa, across)) return 1;
   171       if (strlen(dsa->token) == 0)
   172       {  xprintf("%s:%d: missing integer\n", dsa->fname, dsa->seqn);
   173          return 1;
   174       }
   175       if (str2int(dsa->token, val))
   176       {  xprintf("%s:%d: integer `%s' invalid\n", dsa->fname, dsa->seqn
   177             , dsa->token);
   178          return 1;
   179       }
   180       return 0;
   181 }
   182 
   183 static int scan_number(struct dsa *dsa, int across, double *val)
   184 {     if (scan_token(dsa, across)) return 1;
   185       if (strlen(dsa->token) == 0)
   186       {  xprintf("%s:%d: missing number\n", dsa->fname, dsa->seqn);
   187          return 1;
   188       }
   189       if (str2num(dsa->token, val))
   190       {  xprintf("%s:%d: number `%s' invalid\n", dsa->fname, dsa->seqn,
   191             dsa->token);
   192          return 1;
   193       }
   194       return 0;
   195 }
   196 
   197 TSP *tsp_read_data(char *fname)
   198 {     struct dsa _dsa, *dsa = &_dsa;
   199       TSP *tsp = NULL;
   200       dsa->fname = fname;
   201       xprintf("tsp_read_data: reading TSP data from `%s'...\n",
   202          dsa->fname);
   203       dsa->fp = fopen(dsa->fname, "r");
   204       if (dsa->fp == NULL)
   205       {  xprintf("tsp_read_data: unable to open `%s' - %s\n",
   206             dsa->fname, strerror(errno));
   207          goto fail;
   208       }
   209       tsp = xmalloc(sizeof(TSP));
   210       tsp->name = NULL;
   211       tsp->type = TSP_UNDEF;
   212       tsp->comment = NULL;
   213       tsp->dimension = 0;
   214       tsp->edge_weight_type = TSP_UNDEF;
   215       tsp->edge_weight_format = TSP_UNDEF;
   216       tsp->display_data_type = TSP_UNDEF;
   217       tsp->node_x_coord = NULL;
   218       tsp->node_y_coord = NULL;
   219       tsp->dply_x_coord = NULL;
   220       tsp->dply_y_coord = NULL;
   221       tsp->tour = NULL;
   222       tsp->edge_weight = NULL;
   223       dsa->seqn = 1;
   224       if (get_char(dsa)) goto fail;
   225 loop: if (scan_keyword(dsa)) goto fail;
   226       if (strcmp(dsa->token, "NAME") == 0)
   227       {  if (tsp->name != NULL)
   228          {  xprintf("%s:%d: NAME entry multiply defined\n", dsa->fname,
   229                dsa->seqn);
   230             goto fail;
   231          }
   232          if (check_colon(dsa)) goto fail;
   233          if (scan_token(dsa, 0)) goto fail;
   234          if (strlen(dsa->token) == 0)
   235          {  xprintf("%s:%d: NAME entry incomplete\n", dsa->fname,
   236                dsa->seqn);
   237             goto fail;
   238          }
   239          tsp->name = xmalloc(strlen(dsa->token) + 1);
   240          strcpy(tsp->name, dsa->token);
   241          xprintf("tsp_read_data: NAME: %s\n", tsp->name);
   242          if (check_newline(dsa)) goto fail;
   243       }
   244       else if (strcmp(dsa->token, "TYPE") == 0)
   245       {  if (tsp->type != TSP_UNDEF)
   246          {  xprintf("%s:%d: TYPE entry multiply defined\n", dsa->fname,
   247                dsa->seqn);
   248             goto fail;
   249          }
   250          if (check_colon(dsa)) goto fail;
   251          if (scan_keyword(dsa)) goto fail;
   252          if (strcmp(dsa->token, "TSP") == 0)
   253             tsp->type = TSP_TSP;
   254          else if (strcmp(dsa->token, "ATSP") == 0)
   255             tsp->type = TSP_ATSP;
   256          else if (strcmp(dsa->token, "TOUR") == 0)
   257             tsp->type = TSP_TOUR;
   258          else
   259          {  xprintf("%s:%d: data type `%s' not recognized\n",
   260                dsa->fname, dsa->seqn, dsa->token);
   261             goto fail;
   262          }
   263          xprintf("tsp_read_data: TYPE: %s\n", dsa->token);
   264          if (check_newline(dsa)) goto fail;
   265       }
   266       else if (strcmp(dsa->token, "COMMENT") == 0)
   267       {  if (tsp->comment != NULL)
   268          {  xprintf("%s:%d: COMMENT entry multiply defined\n",
   269                dsa->fname, dsa->seqn);
   270             goto fail;
   271          }
   272          if (check_colon(dsa)) goto fail;
   273          if (scan_comment(dsa)) goto fail;
   274          tsp->comment = xmalloc(strlen(dsa->token) + 1);
   275          strcpy(tsp->comment, dsa->token);
   276          xprintf("tsp_read_data: COMMENT: %s\n", tsp->comment);
   277          if (check_newline(dsa)) goto fail;
   278       }
   279       else if (strcmp(dsa->token, "DIMENSION") == 0)
   280       {  if (tsp->dimension != 0)
   281          {  xprintf("%s:%d: DIMENSION entry multiply defined\n",
   282                dsa->fname, dsa->seqn);
   283             goto fail;
   284          }
   285          if (check_colon(dsa)) goto fail;
   286          if (scan_integer(dsa, 0, &tsp->dimension)) goto fail;
   287          if (tsp->dimension < 1)
   288          {  xprintf("%s:%d: invalid dimension\n", dsa->fname,
   289                dsa->seqn);
   290             goto fail;
   291          }
   292          xprintf("tsp_read_data: DIMENSION: %d\n", tsp->dimension);
   293          if (check_newline(dsa)) goto fail;
   294       }
   295       else if (strcmp(dsa->token, "EDGE_WEIGHT_TYPE") == 0)
   296       {  if (tsp->edge_weight_type != TSP_UNDEF)
   297          {  xprintf("%s:%d: EDGE_WEIGHT_TYPE entry multiply defined\n",
   298                dsa->fname, dsa->seqn);
   299             goto fail;
   300          }
   301          if (check_colon(dsa)) goto fail;
   302          if (scan_keyword(dsa)) goto fail;
   303          if (strcmp(dsa->token, "GEO") == 0)
   304             tsp->edge_weight_type = TSP_GEO;
   305          else if (strcmp(dsa->token, "EUC_2D") == 0)
   306             tsp->edge_weight_type = TSP_EUC_2D;
   307          else if (strcmp(dsa->token, "ATT") == 0)
   308             tsp->edge_weight_type = TSP_ATT;
   309          else if (strcmp(dsa->token, "EXPLICIT") == 0)
   310             tsp->edge_weight_type = TSP_EXPLICIT;
   311          else if (strcmp(dsa->token, "CEIL_2D") == 0)
   312             tsp->edge_weight_type = TSP_CEIL_2D;
   313          else
   314          {  xprintf("%s:%d: edge weight type `%s' not recognized\n",
   315                dsa->fname, dsa->seqn, dsa->token);
   316             goto fail;
   317          }
   318          xprintf("tsp_read_data: EDGE_WEIGHT_TYPE: %s\n", dsa->token);
   319          if (check_newline(dsa)) goto fail;
   320       }
   321       else if (strcmp(dsa->token, "EDGE_WEIGHT_FORMAT") == 0)
   322       {  if (tsp->edge_weight_format != TSP_UNDEF)
   323          {  xprintf(
   324                "%s:%d: EDGE_WEIGHT_FORMAT entry multiply defined\n",
   325                dsa->fname, dsa->seqn);
   326             goto fail;
   327          }
   328          if (check_colon(dsa)) goto fail;
   329          if (scan_keyword(dsa)) goto fail;
   330          if (strcmp(dsa->token, "UPPER_ROW") == 0)
   331             tsp->edge_weight_format = TSP_UPPER_ROW;
   332          else if (strcmp(dsa->token, "FULL_MATRIX") == 0)
   333             tsp->edge_weight_format = TSP_FULL_MATRIX;
   334          else if (strcmp(dsa->token, "FUNCTION") == 0)
   335             tsp->edge_weight_format = TSP_FUNCTION;
   336          else if (strcmp(dsa->token, "LOWER_DIAG_ROW") == 0)
   337             tsp->edge_weight_format = TSP_LOWER_DIAG_ROW;
   338          else
   339          {  xprintf("%s:%d: edge weight format `%s' not recognized\n",
   340                dsa->fname, dsa->seqn, dsa->token);
   341             goto fail;
   342          }
   343          xprintf("tsp_read_data: EDGE_WEIGHT_FORMAT: %s\n", dsa->token);
   344          if (check_newline(dsa)) goto fail;
   345       }
   346       else if (strcmp(dsa->token, "DISPLAY_DATA_TYPE") == 0)
   347       {  if (tsp->display_data_type != TSP_UNDEF)
   348          {  xprintf("%s:%d: DISPLAY_DATA_TYPE entry multiply defined\n",
   349                dsa->fname, dsa->seqn);
   350             goto fail;
   351          }
   352          if (check_colon(dsa)) goto fail;
   353          if (scan_keyword(dsa)) goto fail;
   354          if (strcmp(dsa->token, "COORD_DISPLAY") == 0)
   355             tsp->display_data_type = TSP_COORD_DISPLAY;
   356          else if (strcmp(dsa->token, "TWOD_DISPLAY") == 0)
   357             tsp->display_data_type = TSP_TWOD_DISPLAY;
   358          else
   359          {  xprintf("%s:%d: display data type `%s' not recognized\n",
   360                dsa->fname, dsa->seqn, dsa->token);
   361             goto fail;
   362          }
   363          xprintf("tsp_read_data: DISPLAY_DATA_TYPE: %s\n", dsa->token);
   364          if (check_newline(dsa)) goto fail;
   365       }
   366       else if (strcmp(dsa->token, "NODE_COORD_SECTION") == 0)
   367       {  int n = tsp->dimension, k, node;
   368          if (n == 0)
   369          {  xprintf("%s:%d: DIMENSION entry not specified\n",
   370                dsa->fname, dsa->seqn);
   371             goto fail;
   372          }
   373          if (tsp->node_x_coord != NULL)
   374          {  xprintf("%s:%d: NODE_COORD_SECTION multiply specified\n",
   375                dsa->fname, dsa->seqn);
   376             goto fail;
   377          }
   378          if (check_newline(dsa)) goto fail;
   379          tsp->node_x_coord = xcalloc(1+n, sizeof(double));
   380          tsp->node_y_coord = xcalloc(1+n, sizeof(double));
   381          for (node = 1; node <= n; node++)
   382             tsp->node_x_coord[node] = tsp->node_y_coord[node] = DBL_MAX;
   383          for (k = 1; k <= n; k++)
   384          {  if (scan_integer(dsa, 0, &node)) goto fail;
   385             if (!(1 <= node && node <= n))
   386             {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
   387                   dsa->seqn, node);
   388                goto fail;
   389             }
   390             if (tsp->node_x_coord[node] != DBL_MAX)
   391             {  xprintf("%s:%d: node number %d multiply specified\n",
   392                   dsa->fname, dsa->seqn, node);
   393                goto fail;
   394             }
   395             if (scan_number(dsa, 0, &tsp->node_x_coord[node]))
   396                goto fail;
   397             if (scan_number(dsa, 0, &tsp->node_y_coord[node]))
   398                goto fail;
   399             if (check_newline(dsa)) goto fail;
   400          }
   401       }
   402       else if (strcmp(dsa->token, "DISPLAY_DATA_SECTION") == 0)
   403       {  int n = tsp->dimension, k, node;
   404          if (n == 0)
   405          {  xprintf("%s:%d: DIMENSION entry not specified\n",
   406                dsa->fname, dsa->seqn);
   407             goto fail;
   408          }
   409          if (tsp->dply_x_coord != NULL)
   410          {  xprintf("%s:%d: DISPLAY_DATA_SECTION multiply specified\n",
   411                dsa->fname, dsa->seqn);
   412             goto fail;
   413          }
   414          if (check_newline(dsa)) goto fail;
   415          tsp->dply_x_coord = xcalloc(1+n, sizeof(double));
   416          tsp->dply_y_coord = xcalloc(1+n, sizeof(double));
   417          for (node = 1; node <= n; node++)
   418             tsp->dply_x_coord[node] = tsp->dply_y_coord[node] = DBL_MAX;
   419          for (k = 1; k <= n; k++)
   420          {  if (scan_integer(dsa, 0, &node)) goto fail;
   421             if (!(1 <= node && node <= n))
   422             {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
   423                   dsa->seqn, node);
   424                goto fail;
   425             }
   426             if (tsp->dply_x_coord[node] != DBL_MAX)
   427             {  xprintf("%s:%d: node number %d multiply specified\n",
   428                   dsa->fname, dsa->seqn, node);
   429                goto fail;
   430             }
   431             if (scan_number(dsa, 0, &tsp->dply_x_coord[node]))
   432                goto fail;
   433             if (scan_number(dsa, 0, &tsp->dply_y_coord[node]))
   434                goto fail;
   435             if (check_newline(dsa)) goto fail;
   436          }
   437       }
   438       else if (strcmp(dsa->token, "TOUR_SECTION") == 0)
   439       {  int n = tsp->dimension, k, node;
   440          if (n == 0)
   441          {  xprintf("%s:%d: DIMENSION entry not specified\n",
   442                dsa->fname, dsa->seqn);
   443             goto fail;
   444          }
   445          if (tsp->tour != NULL)
   446          {  xprintf("%s:%d: TOUR_SECTION multiply specified\n",
   447                dsa->fname, dsa->seqn);
   448             goto fail;
   449          }
   450          if (check_newline(dsa)) goto fail;
   451          tsp->tour = xcalloc(1+n, sizeof(int));
   452          for (k = 1; k <= n; k++)
   453          {  if (scan_integer(dsa, 1, &node)) goto fail;
   454             if (!(1 <= node && node <= n))
   455             {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
   456                   dsa->seqn, node);
   457                goto fail;
   458             }
   459             tsp->tour[k] = node;
   460          }
   461          if (scan_integer(dsa, 1, &node)) goto fail;
   462          if (node != -1)
   463          {  xprintf("%s:%d: extra node(s) detected\n", dsa->fname,
   464                dsa->seqn);
   465             goto fail;
   466          }
   467          if (check_newline(dsa)) goto fail;
   468       }
   469       else if (strcmp(dsa->token, "EDGE_WEIGHT_SECTION") == 0)
   470       {  int n = tsp->dimension, i, j, temp;
   471          if (n == 0)
   472          {  xprintf("%s:%d: DIMENSION entry not specified\n",
   473                dsa->fname, dsa->seqn);
   474             goto fail;
   475          }
   476          if (tsp->edge_weight_format == TSP_UNDEF)
   477          {  xprintf("%s:%d: EDGE_WEIGHT_FORMAT entry not specified\n",
   478                dsa->fname, dsa->seqn);
   479             goto fail;
   480          }
   481          if (tsp->edge_weight != NULL)
   482          {  xprintf("%s:%d: EDGE_WEIGHT_SECTION multiply specified\n",
   483                dsa->fname, dsa->seqn);
   484             goto fail;
   485          }
   486          if (check_newline(dsa)) goto fail;
   487          tsp->edge_weight = xcalloc(1+n*n, sizeof(int));
   488          switch (tsp->edge_weight_format)
   489          {  case TSP_FULL_MATRIX:
   490                for (i = 1; i <= n; i++)
   491                {  for (j = 1; j <= n; j++)
   492                   {  if (scan_integer(dsa, 1, &temp)) goto fail;
   493                      tsp->edge_weight[(i - 1) * n + j] = temp;
   494                   }
   495                }
   496                break;
   497             case TSP_UPPER_ROW:
   498                for (i = 1; i <= n; i++)
   499                {  tsp->edge_weight[(i - 1) * n + i] = 0;
   500                   for (j = i + 1; j <= n; j++)
   501                   {  if (scan_integer(dsa, 1, &temp)) goto fail;
   502                      tsp->edge_weight[(i - 1) * n + j] = temp;
   503                      tsp->edge_weight[(j - 1) * n + i] = temp;
   504                   }
   505                }
   506                break;
   507             case TSP_LOWER_DIAG_ROW:
   508                for (i = 1; i <= n; i++)
   509                {  for (j = 1; j <= i; j++)
   510                   {  if (scan_integer(dsa, 1, &temp)) goto fail;
   511                      tsp->edge_weight[(i - 1) * n + j] = temp;
   512                      tsp->edge_weight[(j - 1) * n + i] = temp;
   513                   }
   514                }
   515                break;
   516             default:
   517                goto fail;
   518          }
   519          if (check_newline(dsa)) goto fail;
   520       }
   521       else if (strcmp(dsa->token, "EOF") == 0)
   522       {  if (check_newline(dsa)) goto fail;
   523          goto done;
   524       }
   525       else
   526       {  xprintf("%s:%d: keyword `%s' not recognized\n", dsa->fname,
   527             dsa->seqn, dsa->token);
   528          goto fail;
   529       }
   530       goto loop;
   531 done: xprintf("tsp_read_data: %d lines were read\n", dsa->seqn-1);
   532       fclose(dsa->fp);
   533       return tsp;
   534 fail: if (tsp != NULL)
   535       {  if (tsp->name != NULL) xfree(tsp->name);
   536          if (tsp->comment != NULL) xfree(tsp->comment);
   537          if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
   538          if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
   539          if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
   540          if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
   541          if (tsp->tour != NULL) xfree(tsp->tour);
   542          if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
   543          xfree(tsp);
   544       }
   545       if (dsa->fp != NULL) fclose(dsa->fp);
   546       return NULL;
   547 }
   548 
   549 /*----------------------------------------------------------------------
   550 -- tsp_free_data - free TSP instance data.
   551 --
   552 -- *Synopsis*
   553 --
   554 -- #include "glptsp.h"
   555 -- void tsp_free_data(TSP *tsp);
   556 --
   557 -- *Description*
   558 --
   559 -- The routine tsp_free_data frees all the memory allocated to the TSP
   560 -- instance data block, which the parameter tsp points to. */
   561 
   562 void tsp_free_data(TSP *tsp)
   563 {     if (tsp->name != NULL) xfree(tsp->name);
   564       if (tsp->comment != NULL) xfree(tsp->comment);
   565       if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
   566       if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
   567       if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
   568       if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
   569       if (tsp->tour != NULL) xfree(tsp->tour);
   570       if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
   571       xfree(tsp);
   572       return;
   573 }
   574 
   575 /*----------------------------------------------------------------------
   576 -- tsp_distance - compute distance between two nodes.
   577 --
   578 -- *Synopsis*
   579 --
   580 -- #include "glptsp.h"
   581 -- int tsp_distance(TSP *tsp, int i, int j);
   582 --
   583 -- *Description*
   584 --
   585 -- The routine tsp_distance computes the distance between i-th and j-th
   586 -- nodes for the TSP instance, which tsp points to.
   587 --
   588 -- *Returns*
   589 --
   590 -- The routine tsp_distance returns the computed distance. */
   591 
   592 #define nint(x) ((int)((x) + 0.5))
   593 
   594 static double rad(double x)
   595 {     /* convert input coordinate to longitude/latitude, in radians */
   596       double pi = 3.141592, deg, min;
   597       deg = (int)x;
   598       min = x - deg;
   599       return pi * (deg + 5.0 * min / 3.0) / 180.0;
   600 }
   601 
   602 int tsp_distance(TSP *tsp, int i, int j)
   603 {     int n = tsp->dimension, dij;
   604       if (!(tsp->type == TSP_TSP || tsp->type == TSP_ATSP))
   605          xfault("tsp_distance: invalid TSP instance\n");
   606       if (!(1 <= i && i <= n && 1 <= j && j <= n))
   607          xfault("tsp_distance: node number out of range\n");
   608       switch (tsp->edge_weight_type)
   609       {  case TSP_UNDEF:
   610             xfault("tsp_distance: edge weight type not specified\n");
   611          case TSP_EXPLICIT:
   612             if (tsp->edge_weight == NULL)
   613                xfault("tsp_distance: edge weights not specified\n");
   614             dij = tsp->edge_weight[(i - 1) * n + j];
   615             break;
   616          case TSP_EUC_2D:
   617             if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
   618                xfault("tsp_distance: node coordinates not specified\n");
   619             {  double xd, yd;
   620                xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
   621                yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
   622                dij = nint(sqrt(xd * xd + yd * yd));
   623             }
   624             break;
   625          case TSP_CEIL_2D:
   626             if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
   627                xfault("tsp_distance: node coordinates not specified\n");
   628             {  double xd, yd;
   629                xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
   630                yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
   631                dij = (int)ceil(sqrt(xd * xd + yd * yd));
   632             }
   633             break;
   634          case TSP_GEO:
   635             if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
   636                xfault("tsp_distance: node coordinates not specified\n");
   637             {  double rrr = 6378.388;
   638                double latitude_i = rad(tsp->node_x_coord[i]);
   639                double latitude_j = rad(tsp->node_x_coord[j]);
   640                double longitude_i = rad(tsp->node_y_coord[i]);
   641                double longitude_j = rad(tsp->node_y_coord[j]);
   642                double q1 = cos(longitude_i - longitude_j);
   643                double q2 = cos(latitude_i - latitude_j);
   644                double q3 = cos(latitude_i + latitude_j);
   645                dij = (int)(rrr * acos(0.5 * ((1.0 + q1) * q2 -
   646                   (1.0 - q1) *q3)) + 1.0);
   647             }
   648             break;
   649          case TSP_ATT:
   650             if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
   651                xfault("tsp_distance: node coordinates not specified\n");
   652             {  int tij;
   653                double xd, yd, rij;
   654                xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
   655                yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
   656                rij = sqrt((xd * xd + yd * yd) / 10.0);
   657                tij = nint(rij);
   658                if (tij < rij) dij = tij + 1; else dij = tij;
   659             }
   660             break;
   661          default:
   662             xassert(tsp->edge_weight_type != tsp->edge_weight_type);
   663       }
   664       return dij;
   665 }
   666 
   667 /* eof */