src/glpapi15.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
alpar@1
     1
/* glpapi15.c (basic graph and network routines) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpapi.h"
alpar@1
    26
alpar@1
    27
/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
alpar@1
    28
alpar@1
    29
#define NV_MAX 100000000 /* = 100*10^6 */
alpar@1
    30
/* maximal number of vertices in the graph */
alpar@1
    31
alpar@1
    32
#define NA_MAX 500000000 /* = 500*10^6 */
alpar@1
    33
/* maximal number of arcs in the graph */
alpar@1
    34
alpar@1
    35
/***********************************************************************
alpar@1
    36
*  NAME
alpar@1
    37
*
alpar@1
    38
*  glp_create_graph - create graph
alpar@1
    39
*
alpar@1
    40
*  SYNOPSIS
alpar@1
    41
*
alpar@1
    42
*  glp_graph *glp_create_graph(int v_size, int a_size);
alpar@1
    43
*
alpar@1
    44
*  DESCRIPTION
alpar@1
    45
*
alpar@1
    46
*  The routine creates a new graph, which initially is empty, i.e. has
alpar@1
    47
*  no vertices and arcs.
alpar@1
    48
*
alpar@1
    49
*  The parameter v_size specifies the size of data associated with each
alpar@1
    50
*  vertex of the graph (0 to 256 bytes).
alpar@1
    51
*
alpar@1
    52
*  The parameter a_size specifies the size of data associated with each
alpar@1
    53
*  arc of the graph (0 to 256 bytes).
alpar@1
    54
*
alpar@1
    55
*  RETURNS
alpar@1
    56
*
alpar@1
    57
*  The routine returns a pointer to the graph created. */
alpar@1
    58
alpar@1
    59
static void create_graph(glp_graph *G, int v_size, int a_size)
alpar@1
    60
{     G->pool = dmp_create_pool();
alpar@1
    61
      G->name = NULL;
alpar@1
    62
      G->nv_max = 50;
alpar@1
    63
      G->nv = G->na = 0;
alpar@1
    64
      G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
alpar@1
    65
      G->index = NULL;
alpar@1
    66
      G->v_size = v_size;
alpar@1
    67
      G->a_size = a_size;
alpar@1
    68
      return;
alpar@1
    69
}
alpar@1
    70
alpar@1
    71
glp_graph *glp_create_graph(int v_size, int a_size)
alpar@1
    72
{     glp_graph *G;
alpar@1
    73
      if (!(0 <= v_size && v_size <= 256))
alpar@1
    74
         xerror("glp_create_graph: v_size = %d; invalid size of vertex "
alpar@1
    75
            "data\n", v_size);
alpar@1
    76
      if (!(0 <= a_size && a_size <= 256))
alpar@1
    77
         xerror("glp_create_graph: a_size = %d; invalid size of arc dat"
alpar@1
    78
            "a\n", a_size);
alpar@1
    79
      G = xmalloc(sizeof(glp_graph));
alpar@1
    80
      create_graph(G, v_size, a_size);
alpar@1
    81
      return G;
alpar@1
    82
}
alpar@1
    83
alpar@1
    84
/***********************************************************************
alpar@1
    85
*  NAME
alpar@1
    86
*
alpar@1
    87
*  glp_set_graph_name - assign (change) graph name
alpar@1
    88
*
alpar@1
    89
*  SYNOPSIS
alpar@1
    90
*
alpar@1
    91
*  void glp_set_graph_name(glp_graph *G, const char *name);
alpar@1
    92
*
alpar@1
    93
*  DESCRIPTION
alpar@1
    94
*
alpar@1
    95
*  The routine glp_set_graph_name assigns a symbolic name specified by
alpar@1
    96
*  the character string name (1 to 255 chars) to the graph.
alpar@1
    97
*
alpar@1
    98
*  If the parameter name is NULL or an empty string, the routine erases
alpar@1
    99
*  the existing symbolic name of the graph. */
alpar@1
   100
alpar@1
   101
void glp_set_graph_name(glp_graph *G, const char *name)
alpar@1
   102
{     if (G->name != NULL)
alpar@1
   103
      {  dmp_free_atom(G->pool, G->name, strlen(G->name)+1);
alpar@1
   104
         G->name = NULL;
alpar@1
   105
      }
alpar@1
   106
      if (!(name == NULL || name[0] == '\0'))
alpar@1
   107
      {  int j;
alpar@1
   108
         for (j = 0; name[j] != '\0'; j++)
alpar@1
   109
         {  if (j == 256)
alpar@1
   110
               xerror("glp_set_graph_name: graph name too long\n");
alpar@1
   111
            if (iscntrl((unsigned char)name[j]))
alpar@1
   112
               xerror("glp_set_graph_name: graph name contains invalid "
alpar@1
   113
                  "character(s)\n");
alpar@1
   114
         }
alpar@1
   115
         G->name = dmp_get_atom(G->pool, strlen(name)+1);
alpar@1
   116
         strcpy(G->name, name);
alpar@1
   117
      }
alpar@1
   118
      return;
alpar@1
   119
}
alpar@1
   120
alpar@1
   121
/***********************************************************************
alpar@1
   122
*  NAME
alpar@1
   123
*
alpar@1
   124
*  glp_add_vertices - add new vertices to graph
alpar@1
   125
*
alpar@1
   126
*  SYNOPSIS
alpar@1
   127
*
alpar@1
   128
*  int glp_add_vertices(glp_graph *G, int nadd);
alpar@1
   129
*
alpar@1
   130
*  DESCRIPTION
alpar@1
   131
*
alpar@1
   132
*  The routine glp_add_vertices adds nadd vertices to the specified
alpar@1
   133
*  graph. New vertices are always added to the end of the vertex list,
alpar@1
   134
*  so ordinal numbers of existing vertices remain unchanged.
alpar@1
   135
*
alpar@1
   136
*  Being added each new vertex is isolated (has no incident arcs).
alpar@1
   137
*
alpar@1
   138
*  RETURNS
alpar@1
   139
*
alpar@1
   140
*  The routine glp_add_vertices returns an ordinal number of the first
alpar@1
   141
*  new vertex added to the graph. */
alpar@1
   142
alpar@1
   143
int glp_add_vertices(glp_graph *G, int nadd)
alpar@1
   144
{     int i, nv_new;
alpar@1
   145
      if (nadd < 1)
alpar@1
   146
         xerror("glp_add_vertices: nadd = %d; invalid number of vertice"
alpar@1
   147
            "s\n", nadd);
alpar@1
   148
      if (nadd > NV_MAX - G->nv)
alpar@1
   149
         xerror("glp_add_vertices: nadd = %d; too many vertices\n",
alpar@1
   150
            nadd);
alpar@1
   151
      /* determine new number of vertices */
alpar@1
   152
      nv_new = G->nv + nadd;
alpar@1
   153
      /* increase the room, if necessary */
alpar@1
   154
      if (G->nv_max < nv_new)
alpar@1
   155
      {  glp_vertex **save = G->v;
alpar@1
   156
         while (G->nv_max < nv_new)
alpar@1
   157
         {  G->nv_max += G->nv_max;
alpar@1
   158
            xassert(G->nv_max > 0);
alpar@1
   159
         }
alpar@1
   160
         G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
alpar@1
   161
         memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *));
alpar@1
   162
         xfree(save);
alpar@1
   163
      }
alpar@1
   164
      /* add new vertices to the end of the vertex list */
alpar@1
   165
      for (i = G->nv+1; i <= nv_new; i++)
alpar@1
   166
      {  glp_vertex *v;
alpar@1
   167
         G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex));
alpar@1
   168
         v->i = i;
alpar@1
   169
         v->name = NULL;
alpar@1
   170
         v->entry = NULL;
alpar@1
   171
         if (G->v_size == 0)
alpar@1
   172
            v->data = NULL;
alpar@1
   173
         else
alpar@1
   174
         {  v->data = dmp_get_atom(G->pool, G->v_size);
alpar@1
   175
            memset(v->data, 0, G->v_size);
alpar@1
   176
         }
alpar@1
   177
         v->temp = NULL;
alpar@1
   178
         v->in = v->out = NULL;
alpar@1
   179
      }
alpar@1
   180
      /* set new number of vertices */
alpar@1
   181
      G->nv = nv_new;
alpar@1
   182
      /* return the ordinal number of the first vertex added */
alpar@1
   183
      return nv_new - nadd + 1;
alpar@1
   184
}
alpar@1
   185
alpar@1
   186
/**********************************************************************/
alpar@1
   187
alpar@1
   188
void glp_set_vertex_name(glp_graph *G, int i, const char *name)
alpar@1
   189
{     /* assign (change) vertex name */
alpar@1
   190
      glp_vertex *v;
alpar@1
   191
      if (!(1 <= i && i <= G->nv))
alpar@1
   192
         xerror("glp_set_vertex_name: i = %d; vertex number out of rang"
alpar@1
   193
            "e\n", i);
alpar@1
   194
      v = G->v[i];
alpar@1
   195
      if (v->name != NULL)
alpar@1
   196
      {  if (v->entry != NULL)
alpar@1
   197
         {  xassert(G->index != NULL);
alpar@1
   198
            avl_delete_node(G->index, v->entry);
alpar@1
   199
            v->entry = NULL;
alpar@1
   200
         }
alpar@1
   201
         dmp_free_atom(G->pool, v->name, strlen(v->name)+1);
alpar@1
   202
         v->name = NULL;
alpar@1
   203
      }
alpar@1
   204
      if (!(name == NULL || name[0] == '\0'))
alpar@1
   205
      {  int k;
alpar@1
   206
         for (k = 0; name[k] != '\0'; k++)
alpar@1
   207
         {  if (k == 256)
alpar@1
   208
               xerror("glp_set_vertex_name: i = %d; vertex name too lon"
alpar@1
   209
                  "g\n", i);
alpar@1
   210
            if (iscntrl((unsigned char)name[k]))
alpar@1
   211
               xerror("glp_set_vertex_name: i = %d; vertex name contain"
alpar@1
   212
                  "s invalid character(s)\n", i);
alpar@1
   213
         }
alpar@1
   214
         v->name = dmp_get_atom(G->pool, strlen(name)+1);
alpar@1
   215
         strcpy(v->name, name);
alpar@1
   216
         if (G->index != NULL)
alpar@1
   217
         {  xassert(v->entry == NULL);
alpar@1
   218
            v->entry = avl_insert_node(G->index, v->name);
alpar@1
   219
            avl_set_node_link(v->entry, v);
alpar@1
   220
         }
alpar@1
   221
      }
alpar@1
   222
      return;
alpar@1
   223
}
alpar@1
   224
alpar@1
   225
/***********************************************************************
alpar@1
   226
*  NAME
alpar@1
   227
*
alpar@1
   228
*  glp_add_arc - add new arc to graph
alpar@1
   229
*
alpar@1
   230
*  SYNOPSIS
alpar@1
   231
*
alpar@1
   232
*  glp_arc *glp_add_arc(glp_graph *G, int i, int j);
alpar@1
   233
*
alpar@1
   234
*  DESCRIPTION
alpar@1
   235
*
alpar@1
   236
*  The routine glp_add_arc adds a new arc to the specified graph.
alpar@1
   237
*
alpar@1
   238
*  The parameters i and j specify the ordinal numbers of, resp., tail
alpar@1
   239
*  and head vertices of the arc. Note that self-loops and multiple arcs
alpar@1
   240
*  are allowed.
alpar@1
   241
*
alpar@1
   242
*  RETURNS
alpar@1
   243
*
alpar@1
   244
*  The routine glp_add_arc returns a pointer to the arc added. */
alpar@1
   245
alpar@1
   246
glp_arc *glp_add_arc(glp_graph *G, int i, int j)
alpar@1
   247
{     glp_arc *a;
alpar@1
   248
      if (!(1 <= i && i <= G->nv))
alpar@1
   249
         xerror("glp_add_arc: i = %d; tail vertex number out of range\n"
alpar@1
   250
            , i);
alpar@1
   251
      if (!(1 <= j && j <= G->nv))
alpar@1
   252
         xerror("glp_add_arc: j = %d; head vertex number out of range\n"
alpar@1
   253
            , j);
alpar@1
   254
      if (G->na == NA_MAX)
alpar@1
   255
         xerror("glp_add_arc: too many arcs\n");
alpar@1
   256
      a = dmp_get_atom(G->pool, sizeof(glp_arc));
alpar@1
   257
      a->tail = G->v[i];
alpar@1
   258
      a->head = G->v[j];
alpar@1
   259
      if (G->a_size == 0)
alpar@1
   260
         a->data = NULL;
alpar@1
   261
      else
alpar@1
   262
      {  a->data = dmp_get_atom(G->pool, G->a_size);
alpar@1
   263
         memset(a->data, 0, G->a_size);
alpar@1
   264
      }
alpar@1
   265
      a->temp = NULL;
alpar@1
   266
      a->t_prev = NULL;
alpar@1
   267
      a->t_next = G->v[i]->out;
alpar@1
   268
      if (a->t_next != NULL) a->t_next->t_prev = a;
alpar@1
   269
      a->h_prev = NULL;
alpar@1
   270
      a->h_next = G->v[j]->in;
alpar@1
   271
      if (a->h_next != NULL) a->h_next->h_prev = a;
alpar@1
   272
      G->v[i]->out = G->v[j]->in = a;
alpar@1
   273
      G->na++;
alpar@1
   274
      return a;
alpar@1
   275
}
alpar@1
   276
alpar@1
   277
/***********************************************************************
alpar@1
   278
*  NAME
alpar@1
   279
*
alpar@1
   280
*  glp_del_vertices - delete vertices from graph
alpar@1
   281
*
alpar@1
   282
*  SYNOPSIS
alpar@1
   283
*
alpar@1
   284
*  void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
alpar@1
   285
*
alpar@1
   286
*  DESCRIPTION
alpar@1
   287
*
alpar@1
   288
*  The routine glp_del_vertices deletes vertices along with all
alpar@1
   289
*  incident arcs from the specified graph. Ordinal numbers of vertices
alpar@1
   290
*  to be deleted should be placed in locations num[1], ..., num[ndel],
alpar@1
   291
*  ndel > 0.
alpar@1
   292
*
alpar@1
   293
*  Note that deleting vertices involves changing ordinal numbers of
alpar@1
   294
*  other vertices remaining in the graph. New ordinal numbers of the
alpar@1
   295
*  remaining vertices are assigned under the assumption that the
alpar@1
   296
*  original order of vertices is not changed. */
alpar@1
   297
alpar@1
   298
void glp_del_vertices(glp_graph *G, int ndel, const int num[])
alpar@1
   299
{     glp_vertex *v;
alpar@1
   300
      int i, k, nv_new;
alpar@1
   301
      /* scan the list of vertices to be deleted */
alpar@1
   302
      if (!(1 <= ndel && ndel <= G->nv))
alpar@1
   303
         xerror("glp_del_vertices: ndel = %d; invalid number of vertice"
alpar@1
   304
            "s\n", ndel);
alpar@1
   305
      for (k = 1; k <= ndel; k++)
alpar@1
   306
      {  /* take the number of vertex to be deleted */
alpar@1
   307
         i = num[k];
alpar@1
   308
         /* obtain pointer to i-th vertex */
alpar@1
   309
         if (!(1 <= i && i <= G->nv))
alpar@1
   310
            xerror("glp_del_vertices: num[%d] = %d; vertex number out o"
alpar@1
   311
               "f range\n", k, i);
alpar@1
   312
         v = G->v[i];
alpar@1
   313
         /* check that the vertex is not marked yet */
alpar@1
   314
         if (v->i == 0)
alpar@1
   315
            xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu"
alpar@1
   316
               "mbers not allowed\n", k, i);
alpar@1
   317
         /* erase symbolic name assigned to the vertex */
alpar@1
   318
         glp_set_vertex_name(G, i, NULL);
alpar@1
   319
         xassert(v->name == NULL);
alpar@1
   320
         xassert(v->entry == NULL);
alpar@1
   321
         /* free vertex data, if allocated */
alpar@1
   322
         if (v->data != NULL)
alpar@1
   323
            dmp_free_atom(G->pool, v->data, G->v_size);
alpar@1
   324
         /* delete all incoming arcs */
alpar@1
   325
         while (v->in != NULL)
alpar@1
   326
            glp_del_arc(G, v->in);
alpar@1
   327
         /* delete all outgoing arcs */
alpar@1
   328
         while (v->out != NULL)
alpar@1
   329
            glp_del_arc(G, v->out);
alpar@1
   330
         /* mark the vertex to be deleted */
alpar@1
   331
         v->i = 0;
alpar@1
   332
      }
alpar@1
   333
      /* delete all marked vertices from the vertex list */
alpar@1
   334
      nv_new = 0;
alpar@1
   335
      for (i = 1; i <= G->nv; i++)
alpar@1
   336
      {  /* obtain pointer to i-th vertex */
alpar@1
   337
         v = G->v[i];
alpar@1
   338
         /* check if the vertex is marked */
alpar@1
   339
         if (v->i == 0)
alpar@1
   340
         {  /* it is marked, delete it */
alpar@1
   341
            dmp_free_atom(G->pool, v, sizeof(glp_vertex));
alpar@1
   342
         }
alpar@1
   343
         else
alpar@1
   344
         {  /* it is not marked, keep it */
alpar@1
   345
            v->i = ++nv_new;
alpar@1
   346
            G->v[v->i] = v;
alpar@1
   347
         }
alpar@1
   348
      }
alpar@1
   349
      /* set new number of vertices in the graph */
alpar@1
   350
      G->nv = nv_new;
alpar@1
   351
      return;
alpar@1
   352
}
alpar@1
   353
alpar@1
   354
/***********************************************************************
alpar@1
   355
*  NAME
alpar@1
   356
*
alpar@1
   357
*  glp_del_arc - delete arc from graph
alpar@1
   358
*
alpar@1
   359
*  SYNOPSIS
alpar@1
   360
*
alpar@1
   361
*  void glp_del_arc(glp_graph *G, glp_arc *a);
alpar@1
   362
*
alpar@1
   363
*  DESCRIPTION
alpar@1
   364
*
alpar@1
   365
*  The routine glp_del_arc deletes an arc from the specified graph.
alpar@1
   366
*  The arc to be deleted must exist. */
alpar@1
   367
alpar@1
   368
void glp_del_arc(glp_graph *G, glp_arc *a)
alpar@1
   369
{     /* some sanity checks */
alpar@1
   370
      xassert(G->na > 0);
alpar@1
   371
      xassert(1 <= a->tail->i && a->tail->i <= G->nv);
alpar@1
   372
      xassert(a->tail == G->v[a->tail->i]);
alpar@1
   373
      xassert(1 <= a->head->i && a->head->i <= G->nv);
alpar@1
   374
      xassert(a->head == G->v[a->head->i]);
alpar@1
   375
      /* remove the arc from the list of incoming arcs */
alpar@1
   376
      if (a->h_prev == NULL)
alpar@1
   377
         a->head->in = a->h_next;
alpar@1
   378
      else
alpar@1
   379
         a->h_prev->h_next = a->h_next;
alpar@1
   380
      if (a->h_next == NULL)
alpar@1
   381
         ;
alpar@1
   382
      else
alpar@1
   383
         a->h_next->h_prev = a->h_prev;
alpar@1
   384
      /* remove the arc from the list of outgoing arcs */
alpar@1
   385
      if (a->t_prev == NULL)
alpar@1
   386
         a->tail->out = a->t_next;
alpar@1
   387
      else
alpar@1
   388
         a->t_prev->t_next = a->t_next;
alpar@1
   389
      if (a->t_next == NULL)
alpar@1
   390
         ;
alpar@1
   391
      else
alpar@1
   392
         a->t_next->t_prev = a->t_prev;
alpar@1
   393
      /* free arc data, if allocated */
alpar@1
   394
      if (a->data != NULL)
alpar@1
   395
         dmp_free_atom(G->pool, a->data, G->a_size);
alpar@1
   396
      /* delete the arc from the graph */
alpar@1
   397
      dmp_free_atom(G->pool, a, sizeof(glp_arc));
alpar@1
   398
      G->na--;
alpar@1
   399
      return;
alpar@1
   400
}
alpar@1
   401
alpar@1
   402
/***********************************************************************
alpar@1
   403
*  NAME
alpar@1
   404
*
alpar@1
   405
*  glp_erase_graph - erase graph content
alpar@1
   406
*
alpar@1
   407
*  SYNOPSIS
alpar@1
   408
*
alpar@1
   409
*  void glp_erase_graph(glp_graph *G, int v_size, int a_size);
alpar@1
   410
*
alpar@1
   411
*  DESCRIPTION
alpar@1
   412
*
alpar@1
   413
*  The routine glp_erase_graph erases the content of the specified
alpar@1
   414
*  graph. The effect of this operation is the same as if the graph
alpar@1
   415
*  would be deleted with the routine glp_delete_graph and then created
alpar@1
   416
*  anew with the routine glp_create_graph, with exception that the
alpar@1
   417
*  handle (pointer) to the graph remains valid. */
alpar@1
   418
alpar@1
   419
static void delete_graph(glp_graph *G)
alpar@1
   420
{     dmp_delete_pool(G->pool);
alpar@1
   421
      xfree(G->v);
alpar@1
   422
      if (G->index != NULL) avl_delete_tree(G->index);
alpar@1
   423
      return;
alpar@1
   424
}
alpar@1
   425
alpar@1
   426
void glp_erase_graph(glp_graph *G, int v_size, int a_size)
alpar@1
   427
{     if (!(0 <= v_size && v_size <= 256))
alpar@1
   428
         xerror("glp_erase_graph: v_size = %d; invalid size of vertex d"
alpar@1
   429
            "ata\n", v_size);
alpar@1
   430
      if (!(0 <= a_size && a_size <= 256))
alpar@1
   431
         xerror("glp_erase_graph: a_size = %d; invalid size of arc data"
alpar@1
   432
            "\n", a_size);
alpar@1
   433
      delete_graph(G);
alpar@1
   434
      create_graph(G, v_size, a_size);
alpar@1
   435
      return;
alpar@1
   436
}
alpar@1
   437
alpar@1
   438
/***********************************************************************
alpar@1
   439
*  NAME
alpar@1
   440
*
alpar@1
   441
*  glp_delete_graph - delete graph
alpar@1
   442
*
alpar@1
   443
*  SYNOPSIS
alpar@1
   444
*
alpar@1
   445
*  void glp_delete_graph(glp_graph *G);
alpar@1
   446
*
alpar@1
   447
*  DESCRIPTION
alpar@1
   448
*
alpar@1
   449
*  The routine glp_delete_graph deletes the specified graph and frees
alpar@1
   450
*  all the memory allocated to this program object. */
alpar@1
   451
alpar@1
   452
void glp_delete_graph(glp_graph *G)
alpar@1
   453
{     delete_graph(G);
alpar@1
   454
      xfree(G);
alpar@1
   455
      return;
alpar@1
   456
}
alpar@1
   457
alpar@1
   458
/**********************************************************************/
alpar@1
   459
alpar@1
   460
void glp_create_v_index(glp_graph *G)
alpar@1
   461
{     /* create vertex name index */
alpar@1
   462
      glp_vertex *v;
alpar@1
   463
      int i;
alpar@1
   464
      if (G->index == NULL)
alpar@1
   465
      {  G->index = avl_create_tree(avl_strcmp, NULL);
alpar@1
   466
         for (i = 1; i <= G->nv; i++)
alpar@1
   467
         {  v = G->v[i];
alpar@1
   468
            xassert(v->entry == NULL);
alpar@1
   469
            if (v->name != NULL)
alpar@1
   470
            {  v->entry = avl_insert_node(G->index, v->name);
alpar@1
   471
               avl_set_node_link(v->entry, v);
alpar@1
   472
            }
alpar@1
   473
         }
alpar@1
   474
      }
alpar@1
   475
      return;
alpar@1
   476
}
alpar@1
   477
alpar@1
   478
int glp_find_vertex(glp_graph *G, const char *name)
alpar@1
   479
{     /* find vertex by its name */
alpar@1
   480
      AVLNODE *node;
alpar@1
   481
      int i = 0;
alpar@1
   482
      if (G->index == NULL)
alpar@1
   483
         xerror("glp_find_vertex: vertex name index does not exist\n");
alpar@1
   484
      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
alpar@1
   485
      {  node = avl_find_node(G->index, name);
alpar@1
   486
         if (node != NULL)
alpar@1
   487
            i = ((glp_vertex *)avl_get_node_link(node))->i;
alpar@1
   488
      }
alpar@1
   489
      return i;
alpar@1
   490
}
alpar@1
   491
alpar@1
   492
void glp_delete_v_index(glp_graph *G)
alpar@1
   493
{     /* delete vertex name index */
alpar@1
   494
      int i;
alpar@1
   495
      if (G->index != NULL)
alpar@1
   496
      {  avl_delete_tree(G->index), G->index = NULL;
alpar@1
   497
         for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL;
alpar@1
   498
      }
alpar@1
   499
      return;
alpar@1
   500
}
alpar@1
   501
alpar@1
   502
/***********************************************************************
alpar@1
   503
*  NAME
alpar@1
   504
*
alpar@1
   505
*  glp_read_graph - read graph from plain text file
alpar@1
   506
*
alpar@1
   507
*  SYNOPSIS
alpar@1
   508
*
alpar@1
   509
*  int glp_read_graph(glp_graph *G, const char *fname);
alpar@1
   510
*
alpar@1
   511
*  DESCRIPTION
alpar@1
   512
*
alpar@1
   513
*  The routine glp_read_graph reads a graph from a plain text file.
alpar@1
   514
*
alpar@1
   515
*  RETURNS
alpar@1
   516
*
alpar@1
   517
*  If the operation was successful, the routine returns zero. Otherwise
alpar@1
   518
*  it prints an error message and returns non-zero. */
alpar@1
   519
alpar@1
   520
int glp_read_graph(glp_graph *G, const char *fname)
alpar@1
   521
{     glp_data *data;
alpar@1
   522
      jmp_buf jump;
alpar@1
   523
      int nv, na, i, j, k, ret;
alpar@1
   524
      glp_erase_graph(G, G->v_size, G->a_size);
alpar@1
   525
      xprintf("Reading graph from `%s'...\n", fname);
alpar@1
   526
      data = glp_sdf_open_file(fname);
alpar@1
   527
      if (data == NULL)
alpar@1
   528
      {  ret = 1;
alpar@1
   529
         goto done;
alpar@1
   530
      }
alpar@1
   531
      if (setjmp(jump))
alpar@1
   532
      {  ret = 1;
alpar@1
   533
         goto done;
alpar@1
   534
      }
alpar@1
   535
      glp_sdf_set_jump(data, jump);
alpar@1
   536
      nv = glp_sdf_read_int(data);
alpar@1
   537
      if (nv < 0)
alpar@1
   538
         glp_sdf_error(data, "invalid number of vertices\n");
alpar@1
   539
      na = glp_sdf_read_int(data);
alpar@1
   540
      if (na < 0)
alpar@1
   541
         glp_sdf_error(data, "invalid number of arcs\n");
alpar@1
   542
      xprintf("Graph has %d vert%s and %d arc%s\n",
alpar@1
   543
         nv, nv == 1 ? "ex" : "ices", na, na == 1 ? "" : "s");
alpar@1
   544
      if (nv > 0) glp_add_vertices(G, nv);
alpar@1
   545
      for (k = 1; k <= na; k++)
alpar@1
   546
      {  i = glp_sdf_read_int(data);
alpar@1
   547
         if (!(1 <= i && i <= nv))
alpar@1
   548
            glp_sdf_error(data, "tail vertex number out of range\n");
alpar@1
   549
         j = glp_sdf_read_int(data);
alpar@1
   550
         if (!(1 <= j && j <= nv))
alpar@1
   551
            glp_sdf_error(data, "head vertex number out of range\n");
alpar@1
   552
         glp_add_arc(G, i, j);
alpar@1
   553
      }
alpar@1
   554
      xprintf("%d lines were read\n", glp_sdf_line(data));
alpar@1
   555
      ret = 0;
alpar@1
   556
done: if (data != NULL) glp_sdf_close_file(data);
alpar@1
   557
      return ret;
alpar@1
   558
}
alpar@1
   559
alpar@1
   560
/***********************************************************************
alpar@1
   561
*  NAME
alpar@1
   562
*
alpar@1
   563
*  glp_write_graph - write graph to plain text file
alpar@1
   564
*
alpar@1
   565
*  SYNOPSIS
alpar@1
   566
*
alpar@1
   567
*  int glp_write_graph(glp_graph *G, const char *fname).
alpar@1
   568
*
alpar@1
   569
*  DESCRIPTION
alpar@1
   570
*
alpar@1
   571
*  The routine glp_write_graph writes the specified graph to a plain
alpar@1
   572
*  text file.
alpar@1
   573
*
alpar@1
   574
*  RETURNS
alpar@1
   575
*
alpar@1
   576
*  If the operation was successful, the routine returns zero. Otherwise
alpar@1
   577
*  it prints an error message and returns non-zero. */
alpar@1
   578
alpar@1
   579
int glp_write_graph(glp_graph *G, const char *fname)
alpar@1
   580
{     XFILE *fp;
alpar@1
   581
      glp_vertex *v;
alpar@1
   582
      glp_arc *a;
alpar@1
   583
      int i, count, ret;
alpar@1
   584
      xprintf("Writing graph to `%s'...\n", fname);
alpar@1
   585
      fp = xfopen(fname, "w"), count = 0;
alpar@1
   586
      if (fp == NULL)
alpar@1
   587
      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
alpar@1
   588
         ret = 1;
alpar@1
   589
         goto done;
alpar@1
   590
      }
alpar@1
   591
      xfprintf(fp, "%d %d\n", G->nv, G->na), count++;
alpar@1
   592
      for (i = 1; i <= G->nv; i++)
alpar@1
   593
      {  v = G->v[i];
alpar@1
   594
         for (a = v->out; a != NULL; a = a->t_next)
alpar@1
   595
            xfprintf(fp, "%d %d\n", a->tail->i, a->head->i), count++;
alpar@1
   596
      }
alpar@1
   597
      xfflush(fp);
alpar@1
   598
      if (xferror(fp))
alpar@1
   599
      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
alpar@1
   600
         ret = 1;
alpar@1
   601
         goto done;
alpar@1
   602
      }
alpar@1
   603
      xprintf("%d lines were written\n", count);
alpar@1
   604
      ret = 0;
alpar@1
   605
done: if (fp != NULL) xfclose(fp);
alpar@1
   606
      return ret;
alpar@1
   607
}
alpar@1
   608
alpar@1
   609
/* eof */