src/glpnet03.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpnet03.c (Klingman's network problem generator) */
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
*  This code is the result of translation of the Fortran program NETGEN
alpar@1
     7
*  developed by Dr. Darwin Klingman, which is publically available from
alpar@1
     8
*  NETLIB at <http://www.netlib.org/lp/generators>.
alpar@1
     9
*
alpar@1
    10
*  The translation was made by Andrew Makhorin <mao@gnu.org>.
alpar@1
    11
*
alpar@1
    12
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    13
*  under the terms of the GNU General Public License as published by
alpar@1
    14
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    15
*  (at your option) any later version.
alpar@1
    16
*
alpar@1
    17
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    18
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    19
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    20
*  License for more details.
alpar@1
    21
*
alpar@1
    22
*  You should have received a copy of the GNU General Public License
alpar@1
    23
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    24
***********************************************************************/
alpar@1
    25
alpar@1
    26
#include "glpapi.h"
alpar@1
    27
alpar@1
    28
/***********************************************************************
alpar@1
    29
*  NAME
alpar@1
    30
*
alpar@1
    31
*  glp_netgen - Klingman's network problem generator
alpar@1
    32
*
alpar@1
    33
*  SYNOPSIS
alpar@1
    34
*
alpar@1
    35
*  int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
alpar@1
    36
*     const int parm[1+15]);
alpar@1
    37
*
alpar@1
    38
*  DESCRIPTION
alpar@1
    39
*
alpar@1
    40
*  The routine glp_netgen is a network problem generator developed by
alpar@1
    41
*  Dr. Darwin Klingman. It can create capacitated and uncapacitated
alpar@1
    42
*  minimum cost flow (or transshipment), transportation, and assignment
alpar@1
    43
*  problems.
alpar@1
    44
*
alpar@1
    45
*  The parameter G specifies the graph object, to which the generated
alpar@1
    46
*  problem data have to be stored. Note that on entry the graph object
alpar@1
    47
*  is erased with the routine glp_erase_graph.
alpar@1
    48
*
alpar@1
    49
*  The parameter v_rhs specifies an offset of the field of type double
alpar@1
    50
*  in the vertex data block, to which the routine stores the supply or
alpar@1
    51
*  demand value. If v_rhs < 0, the value is not stored.
alpar@1
    52
*
alpar@1
    53
*  The parameter a_cap specifies an offset of the field of type double
alpar@1
    54
*  in the arc data block, to which the routine stores the arc capacity.
alpar@1
    55
*  If a_cap < 0, the capacity is not stored.
alpar@1
    56
*
alpar@1
    57
*  The parameter a_cost specifies an offset of the field of type double
alpar@1
    58
*  in the arc data block, to which the routine stores the per-unit cost
alpar@1
    59
*  if the arc flow. If a_cost < 0, the cost is not stored.
alpar@1
    60
*
alpar@1
    61
*  The array parm contains description of the network to be generated:
alpar@1
    62
*
alpar@1
    63
*  parm[0]           not used
alpar@1
    64
*  parm[1]  (iseed)  8-digit positive random number seed
alpar@1
    65
*  parm[2]  (nprob)  8-digit problem id number
alpar@1
    66
*  parm[3]  (nodes)  total number of nodes
alpar@1
    67
*  parm[4]  (nsorc)  total number of source nodes (including
alpar@1
    68
*                    transshipment nodes)
alpar@1
    69
*  parm[5]  (nsink)  total number of sink nodes (including
alpar@1
    70
*                    transshipment nodes)
alpar@1
    71
*  parm[6]  (iarcs)  number of arcs
alpar@1
    72
*  parm[7]  (mincst) minimum cost for arcs
alpar@1
    73
*  parm[8]  (maxcst) maximum cost for arcs
alpar@1
    74
*  parm[9]  (itsup)  total supply
alpar@1
    75
*  parm[10] (ntsorc) number of transshipment source nodes
alpar@1
    76
*  parm[11] (ntsink) number of transshipment sink nodes
alpar@1
    77
*  parm[12] (iphic)  percentage of skeleton arcs to be given
alpar@1
    78
*                    the maximum cost
alpar@1
    79
*  parm[13] (ipcap)  percentage of arcs to be capacitated
alpar@1
    80
*  parm[14] (mincap) minimum upper bound for capacitated arcs
alpar@1
    81
*  parm[15] (maxcap) maximum upper bound for capacitated arcs
alpar@1
    82
*
alpar@1
    83
*  The routine generates a transportation problem if:
alpar@1
    84
*
alpar@1
    85
*     nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0.
alpar@1
    86
*
alpar@1
    87
*  The routine generates an assignment problem if the requirements for
alpar@1
    88
*  a transportation problem are met and:
alpar@1
    89
*
alpar@1
    90
*     nsorc = nsink and itsup = nsorc.
alpar@1
    91
*
alpar@1
    92
*  RETURNS
alpar@1
    93
*
alpar@1
    94
*  If the instance was successfully generated, the routine glp_netgen
alpar@1
    95
*  returns zero; otherwise, if specified parameters are inconsistent,
alpar@1
    96
*  the routine returns a non-zero error code.
alpar@1
    97
*
alpar@1
    98
*  REFERENCES
alpar@1
    99
*
alpar@1
   100
*  D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating
alpar@1
   101
*  large scale capacitated assignment, transportation, and minimum cost
alpar@1
   102
*  flow networks. Management Science 20 (1974), 814-20. */
alpar@1
   103
alpar@1
   104
struct csa
alpar@1
   105
{     /* common storage area */
alpar@1
   106
      glp_graph *G;
alpar@1
   107
      int v_rhs, a_cap, a_cost;
alpar@1
   108
      int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor,
alpar@1
   109
         nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl,
alpar@1
   110
         nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult,
alpar@1
   111
         modul, i15, i16, jran;
alpar@1
   112
};
alpar@1
   113
alpar@1
   114
#define G      (csa->G)
alpar@1
   115
#define v_rhs  (csa->v_rhs)
alpar@1
   116
#define a_cap  (csa->a_cap)
alpar@1
   117
#define a_cost (csa->a_cost)
alpar@1
   118
#define nodes  (csa->nodes)
alpar@1
   119
#define iarcs  (csa->iarcs)
alpar@1
   120
#define mincst (csa->mincst)
alpar@1
   121
#define maxcst (csa->maxcst)
alpar@1
   122
#define itsup  (csa->itsup)
alpar@1
   123
#define nsorc  (csa->nsorc)
alpar@1
   124
#define nsink  (csa->nsink)
alpar@1
   125
#define nonsor (csa->nonsor)
alpar@1
   126
#define nfsink (csa->nfsink)
alpar@1
   127
#define narcs  (csa->narcs)
alpar@1
   128
#define nsort  (csa->nsort)
alpar@1
   129
#define nftsor (csa->nftsor)
alpar@1
   130
#define ipcap  (csa->ipcap)
alpar@1
   131
#define mincap (csa->mincap)
alpar@1
   132
#define maxcap (csa->maxcap)
alpar@1
   133
#define ktl    (csa->ktl)
alpar@1
   134
#define nodlft (csa->nodlft)
alpar@1
   135
#if 0
alpar@1
   136
/* spent a day to find out this bug */
alpar@1
   137
#define ist    (csa->ist)
alpar@1
   138
#else
alpar@1
   139
#define ist    (ipred[0])
alpar@1
   140
#endif
alpar@1
   141
#define ipred  (csa->ipred)
alpar@1
   142
#define ihead  (csa->ihead)
alpar@1
   143
#define itail  (csa->itail)
alpar@1
   144
#define iflag  (csa->iflag)
alpar@1
   145
#define isup   (csa->isup)
alpar@1
   146
#define lsinks (csa->lsinks)
alpar@1
   147
#define mult   (csa->mult)
alpar@1
   148
#define modul  (csa->modul)
alpar@1
   149
#define i15    (csa->i15)
alpar@1
   150
#define i16    (csa->i16)
alpar@1
   151
#define jran   (csa->jran)
alpar@1
   152
alpar@1
   153
static void cresup(struct csa *csa);
alpar@1
   154
static void chain(struct csa *csa, int lpick, int lsorc);
alpar@1
   155
static void chnarc(struct csa *csa, int lsorc);
alpar@1
   156
static void sort(struct csa *csa);
alpar@1
   157
static void pickj(struct csa *csa, int it);
alpar@1
   158
static void assign(struct csa *csa);
alpar@1
   159
static void setran(struct csa *csa, int iseed);
alpar@1
   160
static int iran(struct csa *csa, int ilow, int ihigh);
alpar@1
   161
alpar@1
   162
int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
alpar@1
   163
      const int parm[1+15])
alpar@1
   164
{     struct csa _csa, *csa = &_csa;
alpar@1
   165
      int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink,
alpar@1
   166
         ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick,
alpar@1
   167
         nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap,
alpar@1
   168
         jcap, icost, jcost, ret;
alpar@1
   169
      G = G_;
alpar@1
   170
      v_rhs = _v_rhs;
alpar@1
   171
      a_cap = _a_cap;
alpar@1
   172
      a_cost = _a_cost;
alpar@1
   173
      if (G != NULL)
alpar@1
   174
      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
alpar@1
   175
            xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs);
alpar@1
   176
         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
alpar@1
   177
            xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap);
alpar@1
   178
         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
alpar@1
   179
            xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost);
alpar@1
   180
      }
alpar@1
   181
      /* Input the user's random number seed and fix it if
alpar@1
   182
         non-positive. */
alpar@1
   183
      iseed = parm[1];
alpar@1
   184
      nprob = parm[2];
alpar@1
   185
      if (iseed <= 0) iseed = 13502460;
alpar@1
   186
      setran(csa, iseed);
alpar@1
   187
      /* Input the user's problem characteristics. */
alpar@1
   188
      nodes = parm[3];
alpar@1
   189
      nsorc = parm[4];
alpar@1
   190
      nsink = parm[5];
alpar@1
   191
      iarcs = parm[6];
alpar@1
   192
      mincst = parm[7];
alpar@1
   193
      maxcst = parm[8];
alpar@1
   194
      itsup = parm[9];
alpar@1
   195
      ntsorc = parm[10];
alpar@1
   196
      ntsink = parm[11];
alpar@1
   197
      iphic = parm[12];
alpar@1
   198
      ipcap = parm[13];
alpar@1
   199
      mincap = parm[14];
alpar@1
   200
      maxcap = parm[15];
alpar@1
   201
      /* Check the size of the problem. */
alpar@1
   202
      if (!(10 <= nodes && nodes <= 100000))
alpar@1
   203
      {  ret = 1;
alpar@1
   204
         goto done;
alpar@1
   205
      }
alpar@1
   206
      /* Check user supplied parameters for consistency. */
alpar@1
   207
      if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes))
alpar@1
   208
      {  ret = 2;
alpar@1
   209
         goto done;
alpar@1
   210
      }
alpar@1
   211
      if (iarcs < 0)
alpar@1
   212
      {  ret = 3;
alpar@1
   213
         goto done;
alpar@1
   214
      }
alpar@1
   215
      if (mincst > maxcst)
alpar@1
   216
      {  ret = 4;
alpar@1
   217
         goto done;
alpar@1
   218
      }
alpar@1
   219
      if (itsup < 0)
alpar@1
   220
      {  ret = 5;
alpar@1
   221
         goto done;
alpar@1
   222
      }
alpar@1
   223
      if (!(0 <= ntsorc && ntsorc <= nsorc))
alpar@1
   224
      {  ret = 6;
alpar@1
   225
         goto done;
alpar@1
   226
      }
alpar@1
   227
      if (!(0 <= ntsink && ntsink <= nsink))
alpar@1
   228
      {  ret = 7;
alpar@1
   229
         goto done;
alpar@1
   230
      }
alpar@1
   231
      if (!(0 <= iphic && iphic <= 100))
alpar@1
   232
      {  ret = 8;
alpar@1
   233
         goto done;
alpar@1
   234
      }
alpar@1
   235
      if (!(0 <= ipcap && ipcap <= 100))
alpar@1
   236
      {  ret = 9;
alpar@1
   237
         goto done;
alpar@1
   238
      }
alpar@1
   239
      if (mincap > maxcap)
alpar@1
   240
      {  ret = 10;
alpar@1
   241
         goto done;
alpar@1
   242
      }
alpar@1
   243
      /* Initailize the graph object. */
alpar@1
   244
      if (G != NULL)
alpar@1
   245
      {  glp_erase_graph(G, G->v_size, G->a_size);
alpar@1
   246
         glp_add_vertices(G, nodes);
alpar@1
   247
         if (v_rhs >= 0)
alpar@1
   248
         {  double zero = 0.0;
alpar@1
   249
            for (i = 1; i <= nodes; i++)
alpar@1
   250
            {  glp_vertex *v = G->v[i];
alpar@1
   251
               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
alpar@1
   252
            }
alpar@1
   253
         }
alpar@1
   254
      }
alpar@1
   255
      /* Allocate working arrays. */
alpar@1
   256
      ipred = xcalloc(1+nodes, sizeof(int));
alpar@1
   257
      ihead = xcalloc(1+nodes, sizeof(int));
alpar@1
   258
      itail = xcalloc(1+nodes, sizeof(int));
alpar@1
   259
      iflag = xcalloc(1+nodes, sizeof(int));
alpar@1
   260
      isup = xcalloc(1+nodes, sizeof(int));
alpar@1
   261
      lsinks = xcalloc(1+nodes, sizeof(int));
alpar@1
   262
      /* Print the problem documentation records. */
alpar@1
   263
      if (G == NULL)
alpar@1
   264
      {  xprintf("BEGIN\n");
alpar@1
   265
         xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n",
alpar@1
   266
            nprob, "", nodes, iarcs);
alpar@1
   267
         xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%"
alpar@1
   268
            "11d%11d\n", iseed, nsorc, nsink, mincst,
alpar@1
   269
            maxcst, itsup, ntsorc, ntsink, iphic, ipcap,
alpar@1
   270
            mincap, maxcap);
alpar@1
   271
      }
alpar@1
   272
      else
alpar@1
   273
         glp_set_graph_name(G, "NETGEN");
alpar@1
   274
      /* Set various constants used in the program. */
alpar@1
   275
      narcs = 0;
alpar@1
   276
      nskel = 0;
alpar@1
   277
      nltr = nodes - nsink;
alpar@1
   278
      ltsink = nltr + ntsink;
alpar@1
   279
      ntrans = nltr - nsorc;
alpar@1
   280
      nfsink = nltr + 1;
alpar@1
   281
      nonsor = nodes - nsorc + ntsorc;
alpar@1
   282
      npsink = nsink - ntsink;
alpar@1
   283
      nodlft = nodes - nsink + ntsink;
alpar@1
   284
      nftr = nsorc + 1;
alpar@1
   285
      nftsor = nsorc - ntsorc + 1;
alpar@1
   286
      npsorc = nsorc - ntsorc;
alpar@1
   287
      /* Randomly distribute the supply among the source nodes. */
alpar@1
   288
      if (npsorc + npsink == nodes && npsorc == npsink &&
alpar@1
   289
          itsup == nsorc)
alpar@1
   290
      {  assign(csa);
alpar@1
   291
         nskel = nsorc;
alpar@1
   292
         goto L390;
alpar@1
   293
      }
alpar@1
   294
      cresup(csa);
alpar@1
   295
      /* Print the supply records. */
alpar@1
   296
      if (G == NULL)
alpar@1
   297
      {  xprintf("SUPPLY\n");
alpar@1
   298
         for (i = 1; i <= nsorc; i++)
alpar@1
   299
            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
alpar@1
   300
         xprintf("ARCS\n");
alpar@1
   301
      }
alpar@1
   302
      else
alpar@1
   303
      {  if (v_rhs >= 0)
alpar@1
   304
         {  for (i = 1; i <= nsorc; i++)
alpar@1
   305
            {  double temp = (double)isup[i];
alpar@1
   306
               glp_vertex *v = G->v[i];
alpar@1
   307
               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
alpar@1
   308
            }
alpar@1
   309
         }
alpar@1
   310
      }
alpar@1
   311
      /* Make the sources point to themselves in ipred array. */
alpar@1
   312
      for (i = 1; i <= nsorc; i++)
alpar@1
   313
         ipred[i] = i;
alpar@1
   314
      if (ntrans == 0) goto L170;
alpar@1
   315
      /* Chain the transshipment nodes together in the ipred array. */
alpar@1
   316
      ist = nftr;
alpar@1
   317
      ipred[nltr] = 0;
alpar@1
   318
      for (i = nftr; i < nltr; i++)
alpar@1
   319
         ipred[i] = i+1;
alpar@1
   320
      /* Form even length chains for 60 percent of the transshipments.*/
alpar@1
   321
      ntravl = 6 * ntrans / 10;
alpar@1
   322
      ntrrem = ntrans - ntravl;
alpar@1
   323
L140: lsorc = 1;
alpar@1
   324
      while (ntravl != 0)
alpar@1
   325
      {  lpick = iran(csa, 1, ntravl + ntrrem);
alpar@1
   326
         ntravl--;
alpar@1
   327
         chain(csa, lpick, lsorc);
alpar@1
   328
         if (lsorc == nsorc) goto L140;
alpar@1
   329
         lsorc++;
alpar@1
   330
      }
alpar@1
   331
      /* Add the remaining transshipments to the chains. */
alpar@1
   332
      while (ntrrem != 0)
alpar@1
   333
      {
alpar@1
   334
         lpick = iran(csa, 1, ntrrem);
alpar@1
   335
         ntrrem--;
alpar@1
   336
         lsorc = iran(csa, 1, nsorc);
alpar@1
   337
         chain(csa, lpick, lsorc);
alpar@1
   338
      }
alpar@1
   339
L170: /* Set all demands equal to zero. */
alpar@1
   340
      for (i = nfsink; i <= nodes; i++)
alpar@1
   341
         ipred[i] = 0;
alpar@1
   342
      /* The following loop takes one chain at a time (through the use
alpar@1
   343
         of logic contained in the loop and calls to other routines) and
alpar@1
   344
         creates the remaining network arcs. */
alpar@1
   345
      for (lsorc = 1; lsorc <= nsorc; lsorc++)
alpar@1
   346
      {  chnarc(csa, lsorc);
alpar@1
   347
         for (i = nfsink; i <= nodes; i++)
alpar@1
   348
            iflag[i] = 0;
alpar@1
   349
         /* Choose the number of sinks to be hooked up to the current
alpar@1
   350
            chain. */
alpar@1
   351
         if (ntrans != 0)
alpar@1
   352
            nsksr = (nsort * 2 * nsink) / ntrans;
alpar@1
   353
         else
alpar@1
   354
            nsksr = nsink / nsorc + 1;
alpar@1
   355
         if (nsksr < 2) nsksr = 2;
alpar@1
   356
         if (nsksr > nsink) nsksr = nsink;
alpar@1
   357
         nsrchn = nsort;
alpar@1
   358
         /* Randomly pick nsksr sinks and put their names in lsinks. */
alpar@1
   359
         ktl = nsink;
alpar@1
   360
         for (j = 1; j <= nsksr; j++)
alpar@1
   361
         {  item = iran(csa, 1, ktl);
alpar@1
   362
            ktl--;
alpar@1
   363
            for (l = nfsink; l <= nodes; l++)
alpar@1
   364
            {  if (iflag[l] != 1)
alpar@1
   365
               {  item--;
alpar@1
   366
                  if (item == 0) goto L230;
alpar@1
   367
               }
alpar@1
   368
            }
alpar@1
   369
            break;
alpar@1
   370
L230:       lsinks[j] = l;
alpar@1
   371
            iflag[l] = 1;
alpar@1
   372
         }
alpar@1
   373
         /* If last source chain, add all sinks with zero demand to
alpar@1
   374
            lsinks list. */
alpar@1
   375
         if (lsorc == nsorc)
alpar@1
   376
         {  for (j = nfsink; j <= nodes; j++)
alpar@1
   377
            {  if (ipred[j] == 0 && iflag[j] != 1)
alpar@1
   378
               {  nsksr++;
alpar@1
   379
                  lsinks[nsksr] = j;
alpar@1
   380
                  iflag[j] = 1;
alpar@1
   381
               }
alpar@1
   382
            }
alpar@1
   383
         }
alpar@1
   384
         /* Create demands for group of sinks in lsinks. */
alpar@1
   385
         ks = isup[lsorc] / nsksr;
alpar@1
   386
         k = ipred[lsorc];
alpar@1
   387
         for (i = 1; i <= nsksr; i++)
alpar@1
   388
         {  nsort++;
alpar@1
   389
            ksp = iran(csa, 1, ks);
alpar@1
   390
            j = iran(csa, 1, nsksr);
alpar@1
   391
            itail[nsort] = k;
alpar@1
   392
            li = lsinks[i];
alpar@1
   393
            ihead[nsort] = li;
alpar@1
   394
            ipred[li] += ksp;
alpar@1
   395
            li = lsinks[j];
alpar@1
   396
            ipred[li] += ks - ksp;
alpar@1
   397
            n = iran(csa, 1, nsrchn);
alpar@1
   398
            k = lsorc;
alpar@1
   399
            for (ii = 1; ii <= n; ii++)
alpar@1
   400
               k = ipred[k];
alpar@1
   401
         }
alpar@1
   402
         li = lsinks[1];
alpar@1
   403
         ipred[li] += isup[lsorc] - ks * nsksr;
alpar@1
   404
         nskel += nsort;
alpar@1
   405
         /* Sort the arcs in the chain from source lsorc using itail as
alpar@1
   406
            sort key. */
alpar@1
   407
         sort(csa);
alpar@1
   408
         /* Print this part of skeleton and create the arcs for these
alpar@1
   409
            nodes. */
alpar@1
   410
         i = 1;
alpar@1
   411
         itail[nsort+1] = 0;
alpar@1
   412
L300:    for (j = nftsor; j <= nodes; j++)
alpar@1
   413
            iflag[j] = 0;
alpar@1
   414
         ktl = nonsor - 1;
alpar@1
   415
         it = itail[i];
alpar@1
   416
         iflag[it] = 1;
alpar@1
   417
L320:    ih = ihead[i];
alpar@1
   418
         iflag[ih] = 1;
alpar@1
   419
         narcs++;
alpar@1
   420
         ktl--;
alpar@1
   421
         /* Determine if this skeleton arc should be capacitated. */
alpar@1
   422
         icap = itsup;
alpar@1
   423
         jcap = iran(csa, 1, 100);
alpar@1
   424
         if (jcap <= ipcap)
alpar@1
   425
         {  icap = isup[lsorc];
alpar@1
   426
            if (mincap > icap) icap = mincap;
alpar@1
   427
         }
alpar@1
   428
         /* Determine if this skeleton arc should have the maximum
alpar@1
   429
            cost. */
alpar@1
   430
         icost = maxcst;
alpar@1
   431
         jcost = iran(csa, 1, 100);
alpar@1
   432
         if (jcost > iphic)
alpar@1
   433
            icost = iran(csa, mincst, maxcst);
alpar@1
   434
         if (G == NULL)
alpar@1
   435
            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost,
alpar@1
   436
               icap);
alpar@1
   437
         else
alpar@1
   438
         {  glp_arc *a = glp_add_arc(G, it, ih);
alpar@1
   439
            if (a_cap >= 0)
alpar@1
   440
            {  double temp = (double)icap;
alpar@1
   441
               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
alpar@1
   442
            }
alpar@1
   443
            if (a_cost >= 0)
alpar@1
   444
            {  double temp = (double)icost;
alpar@1
   445
               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
alpar@1
   446
            }
alpar@1
   447
         }
alpar@1
   448
         i++;
alpar@1
   449
         if (itail[i] == it) goto L320;
alpar@1
   450
         pickj(csa, it);
alpar@1
   451
         if (i <= nsort) goto L300;
alpar@1
   452
      }
alpar@1
   453
      /* Create arcs from the transshipment sinks. */
alpar@1
   454
      if (ntsink != 0)
alpar@1
   455
      {  for (i = nfsink; i <= ltsink; i++)
alpar@1
   456
         {  for (j = nftsor; j <= nodes; j++)
alpar@1
   457
               iflag[j] = 0;
alpar@1
   458
            ktl = nonsor - 1;
alpar@1
   459
            iflag[i] = 1;
alpar@1
   460
            pickj(csa, i);
alpar@1
   461
         }
alpar@1
   462
      }
alpar@1
   463
L390: /* Print the demand records and end record. */
alpar@1
   464
      if (G == NULL)
alpar@1
   465
      {  xprintf("DEMAND\n");
alpar@1
   466
         for (i = nfsink; i <= nodes; i++)
alpar@1
   467
            xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]);
alpar@1
   468
         xprintf("END\n");
alpar@1
   469
      }
alpar@1
   470
      else
alpar@1
   471
      {  if (v_rhs >= 0)
alpar@1
   472
         {  for (i = nfsink; i <= nodes; i++)
alpar@1
   473
            {  double temp = - (double)ipred[i];
alpar@1
   474
               glp_vertex *v = G->v[i];
alpar@1
   475
               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
alpar@1
   476
            }
alpar@1
   477
         }
alpar@1
   478
      }
alpar@1
   479
      /* Free working arrays. */
alpar@1
   480
      xfree(ipred);
alpar@1
   481
      xfree(ihead);
alpar@1
   482
      xfree(itail);
alpar@1
   483
      xfree(iflag);
alpar@1
   484
      xfree(isup);
alpar@1
   485
      xfree(lsinks);
alpar@1
   486
      /* The instance has been successfully generated. */
alpar@1
   487
      ret = 0;
alpar@1
   488
done: return ret;
alpar@1
   489
}
alpar@1
   490
alpar@1
   491
/***********************************************************************
alpar@1
   492
*  The routine cresup randomly distributes the total supply among the
alpar@1
   493
*  source nodes. */
alpar@1
   494
alpar@1
   495
static void cresup(struct csa *csa)
alpar@1
   496
{     int i, j, ks, ksp;
alpar@1
   497
      xassert(itsup > nsorc);
alpar@1
   498
      ks = itsup / nsorc;
alpar@1
   499
      for (i = 1; i <= nsorc; i++)
alpar@1
   500
         isup[i] = 0;
alpar@1
   501
      for (i = 1; i <= nsorc; i++)
alpar@1
   502
      {  ksp = iran(csa, 1, ks);
alpar@1
   503
         j = iran(csa, 1, nsorc);
alpar@1
   504
         isup[i] += ksp;
alpar@1
   505
         isup[j] += ks - ksp;
alpar@1
   506
      }
alpar@1
   507
      j = iran(csa, 1, nsorc);
alpar@1
   508
      isup[j] += itsup - ks * nsorc;
alpar@1
   509
      return;
alpar@1
   510
}
alpar@1
   511
alpar@1
   512
/***********************************************************************
alpar@1
   513
*  The routine chain adds node lpick to the end of the chain with source
alpar@1
   514
*  node lsorc. */
alpar@1
   515
alpar@1
   516
static void chain(struct csa *csa, int lpick, int lsorc)
alpar@1
   517
{     int i, j, k, l, m;
alpar@1
   518
      k = 0;
alpar@1
   519
      m = ist;
alpar@1
   520
      for (i = 1; i <= lpick; i++)
alpar@1
   521
      {  l = k;
alpar@1
   522
         k = m;
alpar@1
   523
         m = ipred[k];
alpar@1
   524
      }
alpar@1
   525
      ipred[l] = m;
alpar@1
   526
      j = ipred[lsorc];
alpar@1
   527
      ipred[k] = j;
alpar@1
   528
      ipred[lsorc] = k;
alpar@1
   529
      return;
alpar@1
   530
}
alpar@1
   531
alpar@1
   532
/***********************************************************************
alpar@1
   533
*  The routine chnarc puts the arcs in the chain from source lsorc into
alpar@1
   534
*  the ihead and itail arrays for sorting. */
alpar@1
   535
alpar@1
   536
static void chnarc(struct csa *csa, int lsorc)
alpar@1
   537
{     int ito, ifrom;
alpar@1
   538
      nsort = 0;
alpar@1
   539
      ito = ipred[lsorc];
alpar@1
   540
L10:  if (ito == lsorc) return;
alpar@1
   541
      nsort++;
alpar@1
   542
      ifrom = ipred[ito];
alpar@1
   543
      ihead[nsort] = ito;
alpar@1
   544
      itail[nsort] = ifrom;
alpar@1
   545
      ito = ifrom;
alpar@1
   546
      goto L10;
alpar@1
   547
}
alpar@1
   548
alpar@1
   549
/***********************************************************************
alpar@1
   550
*  The routine sort sorts the nsort arcs in the ihead and itail arrays.
alpar@1
   551
*  ihead is used as the sort key (i.e. forward star sort order). */
alpar@1
   552
alpar@1
   553
static void sort(struct csa *csa)
alpar@1
   554
{     int i, j, k, l, m, n, it;
alpar@1
   555
      n = nsort;
alpar@1
   556
      m = n;
alpar@1
   557
L10:  m /= 2;
alpar@1
   558
      if (m == 0) return;
alpar@1
   559
      k = n - m;
alpar@1
   560
      j = 1;
alpar@1
   561
L20:  i = j;
alpar@1
   562
L30:  l = i + m;
alpar@1
   563
      if (itail[i] <= itail[l]) goto L40;
alpar@1
   564
      it = itail[i];
alpar@1
   565
      itail[i] = itail[l];
alpar@1
   566
      itail[l] = it;
alpar@1
   567
      it = ihead[i];
alpar@1
   568
      ihead[i] = ihead[l];
alpar@1
   569
      ihead[l] = it;
alpar@1
   570
      i -= m;
alpar@1
   571
      if (i >= 1) goto L30;
alpar@1
   572
L40:  j++;
alpar@1
   573
      if (j <= k) goto L20;
alpar@1
   574
      goto L10;
alpar@1
   575
}
alpar@1
   576
alpar@1
   577
/***********************************************************************
alpar@1
   578
*  The routine pickj creates a random number of arcs out of node 'it'.
alpar@1
   579
*  Various parameters are dynamically adjusted in an attempt to ensure
alpar@1
   580
*  that the generated network has the correct number of arcs. */
alpar@1
   581
alpar@1
   582
static void pickj(struct csa *csa, int it)
alpar@1
   583
{     int j, k, l, nn, nupbnd, icap, jcap, icost;
alpar@1
   584
      if ((nodlft - 1) * 2 > iarcs - narcs - 1)
alpar@1
   585
      {  nodlft--;
alpar@1
   586
         return;
alpar@1
   587
      }
alpar@1
   588
      if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0)
alpar@1
   589
         k = nonsor;
alpar@1
   590
      else
alpar@1
   591
      {  nupbnd = (iarcs - narcs - nodlft) / nodlft * 2;
alpar@1
   592
L40:     k = iran(csa, 1, nupbnd);
alpar@1
   593
         if (nodlft == 1) k = iarcs - narcs;
alpar@1
   594
         if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40;
alpar@1
   595
      }
alpar@1
   596
      nodlft--;
alpar@1
   597
      for (j = 1; j <= k; j++)
alpar@1
   598
      {  nn = iran(csa, 1, ktl);
alpar@1
   599
         ktl--;
alpar@1
   600
         for (l = nftsor; l <= nodes; l++)
alpar@1
   601
         {  if (iflag[l] != 1)
alpar@1
   602
            {  nn--;
alpar@1
   603
               if (nn == 0) goto L70;
alpar@1
   604
            }
alpar@1
   605
         }
alpar@1
   606
         return;
alpar@1
   607
L70:     iflag[l] = 1;
alpar@1
   608
         icap = itsup;
alpar@1
   609
         jcap = iran(csa, 1, 100);
alpar@1
   610
         if (jcap <= ipcap)
alpar@1
   611
            icap = iran(csa, mincap, maxcap);
alpar@1
   612
         icost = iran(csa, mincst, maxcst);
alpar@1
   613
         if (G == NULL)
alpar@1
   614
            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost,
alpar@1
   615
               icap);
alpar@1
   616
         else
alpar@1
   617
         {  glp_arc *a = glp_add_arc(G, it, l);
alpar@1
   618
            if (a_cap >= 0)
alpar@1
   619
            {  double temp = (double)icap;
alpar@1
   620
               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
alpar@1
   621
            }
alpar@1
   622
            if (a_cost >= 0)
alpar@1
   623
            {  double temp = (double)icost;
alpar@1
   624
               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
alpar@1
   625
            }
alpar@1
   626
         }
alpar@1
   627
         narcs++;
alpar@1
   628
      }
alpar@1
   629
      return;
alpar@1
   630
}
alpar@1
   631
alpar@1
   632
/***********************************************************************
alpar@1
   633
*  The routine assign generate assignment problems. It defines the unit
alpar@1
   634
*  supplies, builds a skeleton, then calls pickj to create the arcs. */
alpar@1
   635
alpar@1
   636
static void assign(struct csa *csa)
alpar@1
   637
{     int i, it, nn, l, ll, icost;
alpar@1
   638
      if (G == NULL)
alpar@1
   639
         xprintf("SUPPLY\n");
alpar@1
   640
      for (i = 1; i <= nsorc; i++)
alpar@1
   641
      {  isup[i] = 1;
alpar@1
   642
         iflag[i] = 0;
alpar@1
   643
         if (G == NULL)
alpar@1
   644
            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
alpar@1
   645
         else
alpar@1
   646
         {  if (v_rhs >= 0)
alpar@1
   647
            {  double temp = (double)isup[i];
alpar@1
   648
               glp_vertex *v = G->v[i];
alpar@1
   649
               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
alpar@1
   650
            }
alpar@1
   651
         }
alpar@1
   652
      }
alpar@1
   653
      if (G == NULL)
alpar@1
   654
         xprintf("ARCS\n");
alpar@1
   655
      for (i = nfsink; i <= nodes; i++)
alpar@1
   656
         ipred[i] = 1;
alpar@1
   657
      for (it = 1; it <= nsorc; it++)
alpar@1
   658
      {  for (i = nfsink; i <= nodes; i++)
alpar@1
   659
            iflag[i] = 0;
alpar@1
   660
         ktl = nsink - 1;
alpar@1
   661
         nn = iran(csa, 1, nsink - it + 1);
alpar@1
   662
         for (l = 1; l <= nsorc; l++)
alpar@1
   663
         {  if (iflag[l] != 1)
alpar@1
   664
            {  nn--;
alpar@1
   665
               if (nn == 0) break;
alpar@1
   666
            }
alpar@1
   667
         }
alpar@1
   668
         narcs++;
alpar@1
   669
         ll = nsorc + l;
alpar@1
   670
         icost = iran(csa, mincst, maxcst);
alpar@1
   671
         if (G == NULL)
alpar@1
   672
            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost,
alpar@1
   673
               isup[1]);
alpar@1
   674
         else
alpar@1
   675
         {  glp_arc *a = glp_add_arc(G, it, ll);
alpar@1
   676
            if (a_cap >= 0)
alpar@1
   677
            {  double temp = (double)isup[1];
alpar@1
   678
               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
alpar@1
   679
            }
alpar@1
   680
            if (a_cost >= 0)
alpar@1
   681
            {  double temp = (double)icost;
alpar@1
   682
               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
alpar@1
   683
            }
alpar@1
   684
         }
alpar@1
   685
         iflag[l] = 1;
alpar@1
   686
         iflag[ll] = 1;
alpar@1
   687
         pickj(csa, it);
alpar@1
   688
      }
alpar@1
   689
      return;
alpar@1
   690
}
alpar@1
   691
alpar@1
   692
/***********************************************************************
alpar@1
   693
*  Portable congruential (uniform) random number generator:
alpar@1
   694
*
alpar@1
   695
*     next_value = ((7**5) * previous_value) modulo ((2**31)-1)
alpar@1
   696
*
alpar@1
   697
*  This generator consists of three routines:
alpar@1
   698
*
alpar@1
   699
*  (1) setran - initializes constants and seed
alpar@1
   700
*  (2) iran   - generates an integer random number
alpar@1
   701
*  (3) rran   - generates a real random number
alpar@1
   702
*
alpar@1
   703
*  The generator requires a machine with at least 32 bits of precision.
alpar@1
   704
*  The seed (iseed) must be in the range [1,(2**31)-1]. */
alpar@1
   705
alpar@1
   706
static void setran(struct csa *csa, int iseed)
alpar@1
   707
{     xassert(iseed >= 1);
alpar@1
   708
      mult = 16807;
alpar@1
   709
      modul = 2147483647;
alpar@1
   710
      i15 = 1 << 15;
alpar@1
   711
      i16 = 1 << 16;
alpar@1
   712
      jran = iseed;
alpar@1
   713
      return;
alpar@1
   714
}
alpar@1
   715
alpar@1
   716
/***********************************************************************
alpar@1
   717
*  The routine iran generates an integer random number between ilow and
alpar@1
   718
*  ihigh. If ilow > ihigh then iran returns ihigh. */
alpar@1
   719
alpar@1
   720
static int iran(struct csa *csa, int ilow, int ihigh)
alpar@1
   721
{     int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover,
alpar@1
   722
         irthi, j;
alpar@1
   723
      ixhi = jran / i16;
alpar@1
   724
      ixlo = jran - ixhi * i16;
alpar@1
   725
      ixalo = ixlo * mult;
alpar@1
   726
      leftlo = ixalo / i16;
alpar@1
   727
      ixahi = ixhi * mult;
alpar@1
   728
      ifulhi = ixahi + leftlo;
alpar@1
   729
      irtlo = ixalo - leftlo * i16;
alpar@1
   730
      iover = ifulhi / i15;
alpar@1
   731
      irthi = ifulhi - iover * i15;
alpar@1
   732
      jran = ((irtlo - modul) + irthi * i16) + iover;
alpar@1
   733
      if (jran < 0) jran += modul;
alpar@1
   734
      j = ihigh - ilow + 1;
alpar@1
   735
      if (j > 0)
alpar@1
   736
         return jran % j + ilow;
alpar@1
   737
      else
alpar@1
   738
         return ihigh;
alpar@1
   739
}
alpar@1
   740
alpar@1
   741
/**********************************************************************/
alpar@1
   742
alpar@1
   743
#if 0
alpar@1
   744
static int scan(char card[80+1], int pos, int len)
alpar@1
   745
{     char buf[10+1];
alpar@1
   746
      memcpy(buf, &card[pos-1], len);
alpar@1
   747
      buf[len] = '\0';
alpar@1
   748
      return atoi(buf);
alpar@1
   749
}
alpar@1
   750
alpar@1
   751
int main(void)
alpar@1
   752
{     int parm[1+15];
alpar@1
   753
      char card[80+1];
alpar@1
   754
      xassert(fgets(card, sizeof(card), stdin) == card);
alpar@1
   755
      parm[1] = scan(card, 1, 8);
alpar@1
   756
      parm[2] = scan(card, 9, 8);
alpar@1
   757
      xassert(fgets(card, sizeof(card), stdin) == card);
alpar@1
   758
      parm[3] = scan(card, 1, 5);
alpar@1
   759
      parm[4] = scan(card, 6, 5);
alpar@1
   760
      parm[5] = scan(card, 11, 5);
alpar@1
   761
      parm[6] = scan(card, 16, 5);
alpar@1
   762
      parm[7] = scan(card, 21, 5);
alpar@1
   763
      parm[8] = scan(card, 26, 5);
alpar@1
   764
      parm[9] = scan(card, 31, 10);
alpar@1
   765
      parm[10] = scan(card, 41, 5);
alpar@1
   766
      parm[11] = scan(card, 46, 5);
alpar@1
   767
      parm[12] = scan(card, 51, 5);
alpar@1
   768
      parm[13] = scan(card, 56, 5);
alpar@1
   769
      parm[14] = scan(card, 61, 10);
alpar@1
   770
      parm[15] = scan(card, 71, 10);
alpar@1
   771
      glp_netgen(NULL, 0, 0, 0, parm);
alpar@1
   772
      return 0;
alpar@1
   773
}
alpar@1
   774
#endif
alpar@1
   775
alpar@1
   776
/* eof */