generators/netgen/netgen.c
author Alpar Juttner <alpar@cs.elte.hu>
Fri, 26 Nov 2010 19:23:47 +0100
changeset 6 a3ef33a8694a
child 7 79d9c9f6c446
permissions -rw-r--r--
Add netgen generator
alpar@6
     1
/*** Copyright 1989 Norbert Schlenker.  All rights reserved.
alpar@6
     2
alpar@6
     3
 *** This software is distributed subject to the following provisions:
alpar@6
     4
 ***    - this notice may not be removed;
alpar@6
     5
 ***    - you may modify the source code, as long as redistributed
alpar@6
     6
 ***      versions have their modifications clearly marked;
alpar@6
     7
 ***    - no charge, other than a nominal copying fee, may be made
alpar@6
     8
 ***      when providing copies of this source code to others;
alpar@6
     9
 ***    - if this source code is used as part of a product which is
alpar@6
    10
 ***      distributed only as a binary, a copy of this source code
alpar@6
    11
 ***      must be included in the distribution.
alpar@6
    12
 ***
alpar@6
    13
 *** Unlike the GNU GPL, use of this code does not obligate you to
alpar@6
    14
 *** disclose your own proprietary source code.
alpar@6
    15
alpar@6
    16
 *** The author of this software provides no warranty, express or
alpar@6
    17
 *** implied, as to its utility or correctness.  That said, reports
alpar@6
    18
 *** of bugs or compatibility problems will be gladly received by
alpar@6
    19
 *** nfs@princeton.edu, and fixes will be attempted.
alpar@6
    20
 ***/
alpar@6
    21
alpar@6
    22
alpar@6
    23
/*** netgen - C version of the standard NETGEN network generator 
alpar@6
    24
 ***          This program is a functional equivalent of the
alpar@6
    25
 ***          standard network generator NETGEN described in:
alpar@6
    26
 ***		Klingman, D., A. Napier, and J. Stutz, "NETGEN:  A Program
alpar@6
    27
 ***		  for Generating Large Scale Capacitated Assignment,
alpar@6
    28
 ***		  Transportation, and Minimum Cost Flow Network Problems",
alpar@6
    29
 ***		  Management Science 20, 5, 814-821 (1974)
alpar@6
    30
 ***
alpar@6
    31
 ***	      This software provides a number of interfaces for use by
alpar@6
    32
 ***	      network solvers.  Standard call interfaces are supplied for
alpar@6
    33
 ***	      use by (Unix) C and Fortran solvers, with generation parameters
alpar@6
    34
 ***	      passed into the generator and the flow network passed back to
alpar@6
    35
 ***	      the solver via large external (COMMON in Fortran) arrays.
alpar@6
    36
 ***	      For the DIMACS challenge, this code will produce output files
alpar@6
    37
 ***	      in the appropriate format for later reading by solvers.
alpar@6
    38
 ***          Undefine the symbol DIMACS when using the call interface.
alpar@6
    39
 ***
alpar@6
    40
 ***          The generator produces exact duplicates of the networks
alpar@6
    41
 ***          made by the Fortran code (even though that means bugs
alpar@6
    42
 ***          are being perpetuated). It is faster by orders of magnitude
alpar@6
    43
 ***          in generating large networks, primarily by imposing the
alpar@6
    44
 ***          notion of the abstract data type INDEX_LIST and implementing
alpar@6
    45
 ***          the type operations in a reasonably efficient fashion.
alpar@6
    46
 ***/
alpar@6
    47
alpar@6
    48
/*** Generates transportation problems if:
alpar@6
    49
 ***	SOURCES+SINKS == NODES && TSOURCES == TSINKS == 0
alpar@6
    50
 ***
alpar@6
    51
 *** Generates assignment problems if above conditions are satisfied, and:
alpar@6
    52
 ***	SOURCES == SINKS && SUPPLY == SOURCES
alpar@6
    53
 ***
alpar@6
    54
 *** Generates maximum flow problems if not an assignment problem and:
alpar@6
    55
 ***	MINCOST == MAXCOST == 1
alpar@6
    56
alpar@6
    57
 *** Implementation notes:
alpar@6
    58
 ***
alpar@6
    59
 ***	This file contains both a Fortran and a C interface. The
alpar@6
    60
 ***	Fortran interface is suffixed with an underscore to make it
alpar@6
    61
 ***	callable in the normal fashion from Fortran (a Unix convention).
alpar@6
    62
 ***
alpar@6
    63
 ***    Because Fortran has no facility for pointers, the common arrays
alpar@6
    64
 ***    are statically allocated.  Static allocation has nothing to recommend
alpar@6
    65
 ***    it except for the need for a Fortran interface.
alpar@6
    66
 ***
alpar@6
    67
 ***    This software expects input parameters to be long integers
alpar@6
    68
 ***    (in the sense of C); that means no INTEGER*2 from Fortran callers.
alpar@6
    69
 ***
alpar@6
    70
 ***	Compiling with -DDIMACS produces a program that reads problem
alpar@6
    71
 ***	parameters, generates the appropriate problem, and prints it.
alpar@6
    72
 ***
alpar@6
    73
 ***	Compiling with -DDEBUG produces code with externally visible
alpar@6
    74
 ***	procedure names, useful for debugging and profiling.
alpar@6
    75
 ***/
alpar@6
    76
alpar@6
    77
alpar@6
    78
/*** System interfaces */
alpar@6
    79
alpar@6
    80
#include <stdio.h>
alpar@6
    81
alpar@6
    82
alpar@6
    83
/*** Public interfaces */
alpar@6
    84
alpar@6
    85
#define ALLOCATE_NETWORK
alpar@6
    86
#include "netgen.h"
alpar@6
    87
alpar@6
    88
#define PROBLEM_PARMS 13		/* aliases for generation parameters */
alpar@6
    89
#define NODES	    parms[0]		/* number of nodes */
alpar@6
    90
#define SOURCES     parms[1]		/* number of sources (including transshipment) */
alpar@6
    91
#define SINKS	    parms[2]		/* number of sinks (including transshipment) */
alpar@6
    92
#define DENSITY     parms[3]		/* number of (requested) arcs */
alpar@6
    93
#define MINCOST     parms[4]		/* minimum cost of arcs */
alpar@6
    94
#define MAXCOST     parms[5]		/* maximum cost of arcs */
alpar@6
    95
#define SUPPLY	    parms[6]		/* total supply */
alpar@6
    96
#define TSOURCES    parms[7]		/* transshipment sources */
alpar@6
    97
#define TSINKS	    parms[8]		/* transshipment sinks */
alpar@6
    98
#define HICOST	    parms[9]		/* percent of skeleton arcs given maximum cost */
alpar@6
    99
#define CAPACITATED parms[10]		/* percent of arcs to be capacitated */
alpar@6
   100
#define MINCAP	    parms[11]		/* minimum capacity for capacitated arcs */
alpar@6
   101
#define MAXCAP	    parms[12]		/* maximum capacity for capacitated arcs */
alpar@6
   102
alpar@6
   103
alpar@6
   104
/*** Private interfaces */
alpar@6
   105
alpar@6
   106
#ifdef DEBUG
alpar@6
   107
#define PRIVATE
alpar@6
   108
#else
alpar@6
   109
#define PRIVATE static
alpar@6
   110
#endif
alpar@6
   111
alpar@6
   112
#ifdef __STDC__
alpar@6
   113
PRIVATE void create_supply(NODE, CAPACITY); /* create supply nodes */
alpar@6
   114
PRIVATE void create_assignment(long*);	/* create assignment problem */
alpar@6
   115
PRIVATE void sort_skeleton(int);	/* sorts skeleton chains */
alpar@6
   116
PRIVATE void pick_head(long*, int, NODE); /* choose destination nodes for rubbish arcs */
alpar@6
   117
PRIVATE void error_exit(long);		/* print error message and exit */
alpar@6
   118
#else
alpar@6
   119
PRIVATE void create_supply();		/* create supply nodes */
alpar@6
   120
PRIVATE void create_assignment();	/* create assignment problem */
alpar@6
   121
PRIVATE void sort_skeleton();		/* sorts skeleton chains */
alpar@6
   122
PRIVATE void pick_head();		/* chooses destination nodes for rubbish arcs */
alpar@6
   123
PRIVATE void error_exit();		/* print error message and exit */
alpar@6
   124
#endif
alpar@6
   125
alpar@6
   126
/*** Private variables */
alpar@6
   127
alpar@6
   128
static NODE nodes_left;
alpar@6
   129
static ARC arc_count;
alpar@6
   130
static NODE pred[MAXARCS];
alpar@6
   131
static NODE head[MAXARCS];
alpar@6
   132
static NODE tail[MAXARCS];
alpar@6
   133
alpar@6
   134
alpar@6
   135
/*** Local macros */
alpar@6
   136
alpar@6
   137
#define MIN(x, y) ((x) < (y) ? (x) : (y))
alpar@6
   138
#define MAX(x, y) ((x) > (y) ? (x) : (y))
alpar@6
   139
#define SAVE_ARC(tail, head, cost, capacity)	/* records an arc where our caller can get it */ \
alpar@6
   140
  {				\
alpar@6
   141
    FROM[arc_count] = tail;	\
alpar@6
   142
    TO  [arc_count] = head;	\
alpar@6
   143
    C   [arc_count] = cost;	\
alpar@6
   144
    U   [arc_count] = capacity; \
alpar@6
   145
    arc_count++;		\
alpar@6
   146
  }
alpar@6
   147
alpar@6
   148
alpar@6
   149
/*** Fortran callable interface routine */
alpar@6
   150
alpar@6
   151
void netgen_(seed, parms, generated_nodes, generated_arcs)
alpar@6
   152
long* seed;			/* pointer to random seed */
alpar@6
   153
long parms[PROBLEM_PARMS];	/* problem parameters */
alpar@6
   154
long* generated_nodes;		/* number of generated nodes */
alpar@6
   155
long* generated_arcs;		/* number of generated arcs */
alpar@6
   156
{
alpar@6
   157
  *generated_nodes = NODES;
alpar@6
   158
  if ((*generated_arcs = netgen(*seed, parms)) < 0)
alpar@6
   159
    error_exit(*generated_arcs);
alpar@6
   160
}
alpar@6
   161
alpar@6
   162
alpar@6
   163
/*** C callable interface routine */
alpar@6
   164
alpar@6
   165
ARC netgen(seed, parms)
alpar@6
   166
long seed;			/* random seed */
alpar@6
   167
long parms[];			/* problem parameters */
alpar@6
   168
{
alpar@6
   169
  register NODE i,j,k;
alpar@6
   170
  NODE source;
alpar@6
   171
  NODE node;
alpar@6
   172
  NODE sinks_per_source;
alpar@6
   173
  NODE* sinks;
alpar@6
   174
  NODE it;
alpar@6
   175
  int chain_length;
alpar@6
   176
  COST cost;
alpar@6
   177
  CAPACITY cap;
alpar@6
   178
  INDEX_LIST handle;
alpar@6
   179
  int supply_per_sink;
alpar@6
   180
  int partial_supply;
alpar@6
   181
  int sort_count;
alpar@6
   182
alpar@6
   183
alpar@6
   184
/*** Perform sanity checks on the input */
alpar@6
   185
alpar@6
   186
  if (seed <= 0)
alpar@6
   187
    return BAD_SEED;
alpar@6
   188
  if (NODES > MAXNODES || DENSITY > MAXARCS)
alpar@6
   189
    return TOO_BIG;
alpar@6
   190
  if ((NODES <= 0) ||
alpar@6
   191
      (NODES > DENSITY) ||
alpar@6
   192
      (SOURCES <= 0) ||
alpar@6
   193
      (SINKS <= 0) ||
alpar@6
   194
      (SOURCES + SINKS > NODES) ||
alpar@6
   195
      (MINCOST > MAXCOST) ||
alpar@6
   196
      (SUPPLY < SOURCES) ||
alpar@6
   197
      (TSOURCES > SOURCES) ||
alpar@6
   198
      (TSINKS > SINKS) ||
alpar@6
   199
      (HICOST < 0 || HICOST > 100) ||
alpar@6
   200
      (CAPACITATED < 0 || CAPACITATED > 100) ||
alpar@6
   201
      (MINCAP > MAXCAP))
alpar@6
   202
    return BAD_PARMS;
alpar@6
   203
alpar@6
   204
alpar@6
   205
/*** Do a little bit of setting up. */
alpar@6
   206
alpar@6
   207
  set_random(seed);
alpar@6
   208
alpar@6
   209
  arc_count = 0;
alpar@6
   210
  nodes_left = NODES - SINKS + TSINKS;
alpar@6
   211
alpar@6
   212
  if ((SOURCES-TSOURCES)+(SINKS-TSINKS) == NODES &&
alpar@6
   213
      (SOURCES-TSOURCES) == (SINKS-TSINKS) &&
alpar@6
   214
       SOURCES == SUPPLY) {
alpar@6
   215
    create_assignment(parms);
alpar@6
   216
    return arc_count;
alpar@6
   217
  }
alpar@6
   218
alpar@6
   219
  (void)memset((void *)B, 0, sizeof(B));/* set supplies and demands to zero */
alpar@6
   220
alpar@6
   221
  create_supply((NODE)SOURCES, (CAPACITY)SUPPLY);
alpar@6
   222
alpar@6
   223
alpar@6
   224
/*** Form most of the network skeleton.  First, 60% of the transshipment
alpar@6
   225
 *** nodes are divided evenly among the various sources; the remainder
alpar@6
   226
 *** are chained onto the end of the chains belonging to random sources.
alpar@6
   227
 ***/
alpar@6
   228
alpar@6
   229
  for (i = 1; i <= SOURCES; i++)	/* point SOURCES at themselves */
alpar@6
   230
    pred[i] = i;
alpar@6
   231
  handle = make_index_list((INDEX)(SOURCES + 1), (INDEX)(NODES - SINKS));
alpar@6
   232
  source = 1;
alpar@6
   233
  for (i = NODES-SOURCES-SINKS; i > (4*(NODES-SOURCES-SINKS)+9)/10; i--) {
alpar@6
   234
    node = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
alpar@6
   235
    pred[node] = pred[source];
alpar@6
   236
    pred[source] = node;
alpar@6
   237
    if (++source > SOURCES)
alpar@6
   238
      source = 1;
alpar@6
   239
  }
alpar@6
   240
  for ( ; i > 0; --i) {
alpar@6
   241
    node = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
alpar@6
   242
    source = ng_random(1L, SOURCES);
alpar@6
   243
    pred[node] = pred[source];
alpar@6
   244
    pred[source] = node;
alpar@6
   245
  }
alpar@6
   246
  free_index_list(handle);
alpar@6
   247
alpar@6
   248
alpar@6
   249
/*** For each source chain, hook it to an "appropriate" number of sinks,
alpar@6
   250
 *** place capacities and costs on the skeleton edges, and then call
alpar@6
   251
 *** pick_head to add a bunch of rubbish edges at each node on the chain.
alpar@6
   252
 ***/
alpar@6
   253
alpar@6
   254
  for (source = 1; source <= SOURCES; source++) {
alpar@6
   255
    sort_count = 0;
alpar@6
   256
    node = pred[source];
alpar@6
   257
    while (node != source) {
alpar@6
   258
      sort_count++;
alpar@6
   259
      head[sort_count] = node;
alpar@6
   260
      node = tail[sort_count] = pred[node];
alpar@6
   261
    }
alpar@6
   262
    if ((NODES-SOURCES-SINKS) == 0)
alpar@6
   263
      sinks_per_source = SINKS/SOURCES + 1;
alpar@6
   264
    else
alpar@6
   265
/* changing to handle overflows with large n; Mar 18 -- jc */
alpar@6
   266
      sinks_per_source = ((double) 2*sort_count*SINKS) / ((double) NODES-SOURCES-SINKS);
alpar@6
   267
    sinks_per_source = MAX(2, MIN(sinks_per_source, SINKS));
alpar@6
   268
    sinks = (NODE*) malloc(sinks_per_source * sizeof(NODE));
alpar@6
   269
    handle = make_index_list((INDEX)(NODES - SINKS), (INDEX)(NODES - 1));
alpar@6
   270
    for (i = 0; i < sinks_per_source; i++) {
alpar@6
   271
      sinks[i] = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
alpar@6
   272
    }
alpar@6
   273
    if (source == SOURCES && index_size(handle) > 0) {
alpar@6
   274
      sinks = (NODE*) realloc((void *)sinks, (sinks_per_source + index_size(handle)) * sizeof(NODE));
alpar@6
   275
      while (index_size(handle) > 0) {
alpar@6
   276
	j = choose_index(handle, 1);
alpar@6
   277
	if (B[j] == 0)
alpar@6
   278
	  sinks[sinks_per_source++] = j;
alpar@6
   279
      }
alpar@6
   280
    }
alpar@6
   281
    free_index_list(handle);
alpar@6
   282
alpar@6
   283
    chain_length = sort_count;
alpar@6
   284
    supply_per_sink = B[source-1] / sinks_per_source;
alpar@6
   285
    k = pred[source];
alpar@6
   286
    for (i = 0; i < sinks_per_source; i++) {
alpar@6
   287
      sort_count++;
alpar@6
   288
      partial_supply = ng_random(1L, (long)supply_per_sink);
alpar@6
   289
      j = ng_random(0L, (long)sinks_per_source - 1);
alpar@6
   290
      tail[sort_count] = k;
alpar@6
   291
      head[sort_count] = sinks[i] + 1;
alpar@6
   292
      B[sinks[i]] -= partial_supply;
alpar@6
   293
      B[sinks[j]] -= (supply_per_sink - partial_supply);
alpar@6
   294
      k = source;
alpar@6
   295
      for (j = ng_random(1L, (long)chain_length); j > 0; j--)
alpar@6
   296
	k = pred[k];
alpar@6
   297
    }
alpar@6
   298
    B[sinks[0]] -= (B[source-1] % sinks_per_source);
alpar@6
   299
    free((void *)sinks);
alpar@6
   300
alpar@6
   301
    sort_skeleton(sort_count);
alpar@6
   302
    tail[sort_count+1] = 0;
alpar@6
   303
    for (i = 1; i <= sort_count; ) {
alpar@6
   304
      handle = make_index_list((INDEX)(SOURCES - TSOURCES + 1), (INDEX)NODES);
alpar@6
   305
      remove_index(handle, (INDEX)tail[i]);
alpar@6
   306
      it = tail[i];
alpar@6
   307
      while (it == tail[i]) {
alpar@6
   308
	remove_index(handle, (INDEX)head[i]);
alpar@6
   309
	cap = SUPPLY;
alpar@6
   310
	if (ng_random(1L, 100L) <= CAPACITATED)
alpar@6
   311
	  cap = MAX(B[source-1], MINCAP);
alpar@6
   312
	cost = MAXCOST;
alpar@6
   313
	if (ng_random(1L, 100L) > HICOST)
alpar@6
   314
	  cost = ng_random(MINCOST, MAXCOST);
alpar@6
   315
	SAVE_ARC(it,head[i],cost,cap);
alpar@6
   316
	i++;
alpar@6
   317
      }
alpar@6
   318
      pick_head(parms, handle, it);
alpar@6
   319
      free_index_list(handle);
alpar@6
   320
    }
alpar@6
   321
  }
alpar@6
   322
alpar@6
   323
alpar@6
   324
/*** Add more rubbish edges out of the transshipment sinks. */
alpar@6
   325
alpar@6
   326
  for (i = NODES - SINKS + 1; i <= NODES - SINKS + TSINKS; i++) {
alpar@6
   327
    handle = make_index_list((INDEX)(SOURCES - TSOURCES + 1), (INDEX)NODES);
alpar@6
   328
    remove_index(handle, (INDEX)i);
alpar@6
   329
    pick_head(parms, handle, i);
alpar@6
   330
    free_index_list(handle);
alpar@6
   331
  }
alpar@6
   332
alpar@6
   333
  return arc_count;
alpar@6
   334
}
alpar@6
   335
alpar@6
   336
alpar@6
   337
PRIVATE void create_supply(sources, supply)
alpar@6
   338
NODE sources;
alpar@6
   339
CAPACITY supply;
alpar@6
   340
{
alpar@6
   341
  CAPACITY supply_per_source = supply / sources;
alpar@6
   342
  CAPACITY partial_supply;
alpar@6
   343
  NODE i;
alpar@6
   344
alpar@6
   345
  for (i = 0; i < sources; i++) {
alpar@6
   346
    B[i] += (partial_supply = ng_random(1L, (long)supply_per_source));
alpar@6
   347
    B[ng_random(0L, (long)(sources - 1))] += supply_per_source - partial_supply;
alpar@6
   348
  }
alpar@6
   349
  B[ng_random(0L, (long)(sources - 1))] += supply % sources;
alpar@6
   350
}
alpar@6
   351
alpar@6
   352
alpar@6
   353
PRIVATE void create_assignment(parms)
alpar@6
   354
long parms[];
alpar@6
   355
{
alpar@6
   356
  INDEX_LIST skeleton, handle;
alpar@6
   357
  INDEX index;
alpar@6
   358
  NODE source;
alpar@6
   359
alpar@6
   360
  for (source = 0; source < NODES/2; source++)
alpar@6
   361
    B[source] = 1;
alpar@6
   362
  for ( ; source < NODES; source++)
alpar@6
   363
    B[source] = -1;
alpar@6
   364
alpar@6
   365
  skeleton = make_index_list((INDEX)(SOURCES + 1), (INDEX)NODES);
alpar@6
   366
  for (source = 1; source <= NODES/2; source++) {
alpar@6
   367
    index = choose_index(skeleton, (INDEX)ng_random(1L, (long)index_size(skeleton)));
alpar@6
   368
    SAVE_ARC(source, index, ng_random(MINCOST, MAXCOST), 1);
alpar@6
   369
    handle = make_index_list((INDEX)(SOURCES + 1), (INDEX)NODES);
alpar@6
   370
    remove_index(handle, index);
alpar@6
   371
    pick_head(parms, handle, source);
alpar@6
   372
    free_index_list(handle);
alpar@6
   373
  }
alpar@6
   374
  free_index_list(skeleton);
alpar@6
   375
}
alpar@6
   376
alpar@6
   377
alpar@6
   378
PRIVATE void sort_skeleton(sort_count) 		/* Shell sort */
alpar@6
   379
int sort_count;
alpar@6
   380
{
alpar@6
   381
  int m,i,j,k;
alpar@6
   382
  int temp;
alpar@6
   383
alpar@6
   384
  m = sort_count;
alpar@6
   385
  while ((m /= 2) != 0) {
alpar@6
   386
    k = sort_count - m;
alpar@6
   387
    for (j = 1; j <= k; j++) {
alpar@6
   388
      i = j;
alpar@6
   389
      while (i >= 1 && tail[i] > tail[i+m]) {
alpar@6
   390
	temp = tail[i];
alpar@6
   391
	tail[i] = tail[i+m];
alpar@6
   392
	tail[i+m] = temp;
alpar@6
   393
	temp = head[i];
alpar@6
   394
	head[i] = head[i+m];
alpar@6
   395
	head[i+m] = temp;
alpar@6
   396
	i -= m;
alpar@6
   397
      }
alpar@6
   398
    }
alpar@6
   399
  }
alpar@6
   400
}
alpar@6
   401
alpar@6
   402
alpar@6
   403
PRIVATE void pick_head(parms, handle, desired_tail)
alpar@6
   404
long parms[];
alpar@6
   405
INDEX_LIST handle;
alpar@6
   406
NODE desired_tail;
alpar@6
   407
{
alpar@6
   408
  NODE non_sources = NODES - SOURCES + TSOURCES;
alpar@6
   409
alpar@6
   410
/* changing Aug 29 -- jc
alpar@6
   411
  ARC remaining_arcs = DENSITY - arc_count;
alpar@6
   412
*/
alpar@6
   413
  int  remaining_arcs = (int) DENSITY - (int) arc_count;
alpar@6
   414
alpar@6
   415
  INDEX index;
alpar@6
   416
  int limit;
alpar@6
   417
  long upper_bound;
alpar@6
   418
  CAPACITY cap;
alpar@6
   419
alpar@6
   420
/* changing Aug 29 -- jc
alpar@6
   421
*/
alpar@6
   422
  nodes_left--;
alpar@6
   423
  if ((2 * (int) nodes_left) >= (int) remaining_arcs)
alpar@6
   424
    return;
alpar@6
   425
alpar@6
   426
  if ((remaining_arcs + non_sources - pseudo_size(handle) - 1) / (nodes_left + 1) >= non_sources - 1) {
alpar@6
   427
    limit = non_sources;
alpar@6
   428
  } else {
alpar@6
   429
    upper_bound = 2 * (remaining_arcs / (nodes_left + 1) - 1);
alpar@6
   430
    do {
alpar@6
   431
      limit = ng_random(1L, upper_bound);
alpar@6
   432
      if (nodes_left == 0)
alpar@6
   433
	limit = remaining_arcs;
alpar@6
   434
/* changing to handle overflows with large n; Mar 18 -- jc */
alpar@6
   435
    } while ( ((double) nodes_left * (non_sources - 1)) < ((double) remaining_arcs - limit));
alpar@6
   436
  }
alpar@6
   437
alpar@6
   438
  for ( ; limit > 0; limit--) {
alpar@6
   439
    index = choose_index(handle, (INDEX)ng_random(1L, (long)pseudo_size(handle)));
alpar@6
   440
    cap = SUPPLY;
alpar@6
   441
    if (ng_random(1L, 100L) <= CAPACITATED)
alpar@6
   442
      cap = ng_random(MINCAP, MAXCAP);
alpar@6
   443
alpar@6
   444
/* adding Aug 29 -- jc */
alpar@6
   445
if ((1 <= index) && (index <= NODES)) {
alpar@6
   446
    SAVE_ARC(desired_tail, index, ng_random(MINCOST, MAXCOST), cap);
alpar@6
   447
    }
alpar@6
   448
alpar@6
   449
  }
alpar@6
   450
}
alpar@6
   451
alpar@6
   452
alpar@6
   453
/*** Print an appropriate error message and then exit with a nonzero code. */
alpar@6
   454
alpar@6
   455
PRIVATE void error_exit(rc)
alpar@6
   456
long rc;
alpar@6
   457
{
alpar@6
   458
  switch (rc) {
alpar@6
   459
    case BAD_SEED:
alpar@6
   460
      fprintf(stderr, "NETGEN requires a positive random seed\n");
alpar@6
   461
      break;
alpar@6
   462
    case TOO_BIG:
alpar@6
   463
      fprintf(stderr, "Problem too large for generator\n");
alpar@6
   464
      break;
alpar@6
   465
    case BAD_PARMS:
alpar@6
   466
      fprintf(stderr, "Inconsistent parameter settings - check the input\n");
alpar@6
   467
      break;
alpar@6
   468
    case ALLOCATION_FAILURE:
alpar@6
   469
      fprintf(stderr, "Memory allocation failure\n");
alpar@6
   470
      break;
alpar@6
   471
    default:
alpar@6
   472
      fprintf(stderr, "Internal error\n");
alpar@6
   473
      break;
alpar@6
   474
  }
alpar@6
   475
  exit(1000 - (int)rc);
alpar@6
   476
}
alpar@6
   477
alpar@6
   478
#ifdef DIMACS			/* generates network on standard output */
alpar@6
   479
alpar@6
   480
#define READ(v) 		     	/* read one variable using scanf */	\
alpar@6
   481
	switch( scanf("%ld", &v) ) {						\
alpar@6
   482
		case 1:								\
alpar@6
   483
			break;							\
alpar@6
   484
		default:							\
alpar@6
   485
			exit(0);						\
alpar@6
   486
		}
alpar@6
   487
alpar@6
   488
int main()
alpar@6
   489
{
alpar@6
   490
  long seed;
alpar@6
   491
  long problem;
alpar@6
   492
  long parms[PROBLEM_PARMS];
alpar@6
   493
  long arcs;
alpar@6
   494
  int i;
alpar@6
   495
alpar@6
   496
/*** Read problem parameters and generate networks */
alpar@6
   497
alpar@6
   498
  while (1) {
alpar@6
   499
    READ(seed);
alpar@6
   500
    if (seed <= 0) exit(0);
alpar@6
   501
    READ(problem);
alpar@6
   502
    if (problem <= 0) exit(0);
alpar@6
   503
    for (i = 0; i < PROBLEM_PARMS; i++)
alpar@6
   504
      READ(parms[i]);
alpar@6
   505
    printf("c NETGEN flow network generator (C version)\n");
alpar@6
   506
    printf("c  Problem %2ld input parameters\n", problem);
alpar@6
   507
    printf("c  ---------------------------\n");
alpar@6
   508
    printf("c   Random seed:          %10ld\n",   seed);
alpar@6
   509
    printf("c   Number of nodes:      %10ld\n",   NODES);
alpar@6
   510
    printf("c   Source nodes:         %10ld\n",   SOURCES);
alpar@6
   511
    printf("c   Sink nodes:           %10ld\n",   SINKS);
alpar@6
   512
    printf("c   Number of arcs:       %10ld\n",   DENSITY);
alpar@6
   513
    printf("c   Minimum arc cost:     %10ld\n",   MINCOST);
alpar@6
   514
    printf("c   Maximum arc cost:     %10ld\n",   MAXCOST);
alpar@6
   515
    printf("c   Total supply:         %10ld\n",   SUPPLY);
alpar@6
   516
    printf("c   Transshipment -\n");
alpar@6
   517
    printf("c     Sources:            %10ld\n",   TSOURCES);
alpar@6
   518
    printf("c     Sinks:              %10ld\n",   TSINKS);
alpar@6
   519
    printf("c   Skeleton arcs -\n");
alpar@6
   520
    printf("c     With max cost:      %10ld%%\n", HICOST);
alpar@6
   521
    printf("c     Capacitated:        %10ld%%\n", CAPACITATED);
alpar@6
   522
    printf("c   Minimum arc capacity: %10ld\n",   MINCAP);
alpar@6
   523
    printf("c   Maximum arc capacity: %10ld\n",   MAXCAP);
alpar@6
   524
alpar@6
   525
    if ((arcs = netgen(seed, parms)) < 0)
alpar@6
   526
      error_exit(arcs);
alpar@6
   527
    if ((SOURCES-TSOURCES)+(SINKS-TSINKS) == NODES &&
alpar@6
   528
	(SOURCES-TSOURCES) == (SINKS-TSINKS) &&
alpar@6
   529
	 SOURCES == SUPPLY) {
alpar@6
   530
      printf("c\n");
alpar@6
   531
      printf("c  *** Assignment ***\n");
alpar@6
   532
      printf("c\n");
alpar@6
   533
      printf("p asn %ld %ld\n", NODES, arcs);
alpar@6
   534
      for (i = 0; i < NODES; i++) {
alpar@6
   535
	if (B[i] > 0)
alpar@6
   536
	  printf("n %ld\n", i + 1);
alpar@6
   537
      }
alpar@6
   538
      for (i = 0; i < arcs; i++) {
alpar@6
   539
	printf("a %ld %ld %ld\n", FROM[i], TO[i], C[i]);
alpar@6
   540
      }
alpar@6
   541
    } else
alpar@6
   542
    if (MINCOST == 1 && MAXCOST == 1) {
alpar@6
   543
      printf("c\n");
alpar@6
   544
      printf("c  *** Maximum flow ***\n");
alpar@6
   545
      printf("c\n");
alpar@6
   546
      printf("p max %ld %ld\n", NODES, arcs);
alpar@6
   547
      for (i = 0; i < NODES; i++) {
alpar@6
   548
	if (B[i] > 0)
alpar@6
   549
	  printf("n %ld s\n", i + 1);
alpar@6
   550
	else
alpar@6
   551
	if (B[i] < 0)
alpar@6
   552
	  printf("n %ld t\n", i + 1);
alpar@6
   553
      }
alpar@6
   554
      for (i = 0; i < arcs; i++) {
alpar@6
   555
	printf("a %ld %ld %ld\n", FROM[i], TO[i], U[i]);
alpar@6
   556
      }
alpar@6
   557
    } else {
alpar@6
   558
      printf("c\n");
alpar@6
   559
      printf("c  *** Minimum cost flow ***\n");
alpar@6
   560
      printf("c\n");
alpar@6
   561
      printf("p min %ld %ld\n", NODES, arcs);
alpar@6
   562
      for (i = 0; i < NODES; i++) {
alpar@6
   563
	if (B[i] != 0)
alpar@6
   564
	  printf("n %ld %ld\n", i + 1, B[i]);
alpar@6
   565
      }
alpar@6
   566
      for (i = 0; i < arcs; i++) {
alpar@6
   567
	printf("a %ld %ld %ld %ld %ld\n", FROM[i], TO[i], 0, U[i], C[i]);
alpar@6
   568
      }
alpar@6
   569
    }
alpar@6
   570
  }
alpar@6
   571
  return 0;
alpar@6
   572
}
alpar@6
   573
alpar@6
   574
#endif