1 /*** Copyright 1989 Norbert Schlenker. All rights reserved.
3 *** This software is distributed subject to the following provisions:
4 *** - this notice may not be removed;
5 *** - you may modify the source code, as long as redistributed
6 *** versions have their modifications clearly marked;
7 *** - no charge, other than a nominal copying fee, may be made
8 *** when providing copies of this source code to others;
9 *** - if this source code is used as part of a product which is
10 *** distributed only as a binary, a copy of this source code
11 *** must be included in the distribution.
13 *** Unlike the GNU GPL, use of this code does not obligate you to
14 *** disclose your own proprietary source code.
16 *** The author of this software provides no warranty, express or
17 *** implied, as to its utility or correctness. That said, reports
18 *** of bugs or compatibility problems will be gladly received by
19 *** nfs@princeton.edu, and fixes will be attempted.
23 /*** netgen - C version of the standard NETGEN network generator
24 *** This program is a functional equivalent of the
25 *** standard network generator NETGEN described in:
26 *** Klingman, D., A. Napier, and J. Stutz, "NETGEN: A Program
27 *** for Generating Large Scale Capacitated Assignment,
28 *** Transportation, and Minimum Cost Flow Network Problems",
29 *** Management Science 20, 5, 814-821 (1974)
31 *** This software provides a number of interfaces for use by
32 *** network solvers. Standard call interfaces are supplied for
33 *** use by (Unix) C and Fortran solvers, with generation parameters
34 *** passed into the generator and the flow network passed back to
35 *** the solver via large external (COMMON in Fortran) arrays.
36 *** For the DIMACS challenge, this code will produce output files
37 *** in the appropriate format for later reading by solvers.
38 *** Undefine the symbol DIMACS when using the call interface.
40 *** The generator produces exact duplicates of the networks
41 *** made by the Fortran code (even though that means bugs
42 *** are being perpetuated). It is faster by orders of magnitude
43 *** in generating large networks, primarily by imposing the
44 *** notion of the abstract data type INDEX_LIST and implementing
45 *** the type operations in a reasonably efficient fashion.
48 /*** Generates transportation problems if:
49 *** SOURCES+SINKS == NODES && TSOURCES == TSINKS == 0
51 *** Generates assignment problems if above conditions are satisfied, and:
52 *** SOURCES == SINKS && SUPPLY == SOURCES
54 *** Generates maximum flow problems if not an assignment problem and:
55 *** MINCOST == MAXCOST == 1
57 *** Implementation notes:
59 *** This file contains both a Fortran and a C interface. The
60 *** Fortran interface is suffixed with an underscore to make it
61 *** callable in the normal fashion from Fortran (a Unix convention).
63 *** Because Fortran has no facility for pointers, the common arrays
64 *** are statically allocated. Static allocation has nothing to recommend
65 *** it except for the need for a Fortran interface.
67 *** This software expects input parameters to be long integers
68 *** (in the sense of C); that means no INTEGER*2 from Fortran callers.
70 *** Compiling with -DDIMACS produces a program that reads problem
71 *** parameters, generates the appropriate problem, and prints it.
73 *** Compiling with -DDEBUG produces code with externally visible
74 *** procedure names, useful for debugging and profiling.
78 /*** System interfaces */
83 /*** Public interfaces */
85 #define ALLOCATE_NETWORK
88 #define PROBLEM_PARMS 13 /* aliases for generation parameters */
89 #define NODES parms[0] /* number of nodes */
90 #define SOURCES parms[1] /* number of sources (including transshipment) */
91 #define SINKS parms[2] /* number of sinks (including transshipment) */
92 #define DENSITY parms[3] /* number of (requested) arcs */
93 #define MINCOST parms[4] /* minimum cost of arcs */
94 #define MAXCOST parms[5] /* maximum cost of arcs */
95 #define SUPPLY parms[6] /* total supply */
96 #define TSOURCES parms[7] /* transshipment sources */
97 #define TSINKS parms[8] /* transshipment sinks */
98 #define HICOST parms[9] /* percent of skeleton arcs given maximum cost */
99 #define CAPACITATED parms[10] /* percent of arcs to be capacitated */
100 #define MINCAP parms[11] /* minimum capacity for capacitated arcs */
101 #define MAXCAP parms[12] /* maximum capacity for capacitated arcs */
104 /*** Private interfaces */
109 #define PRIVATE static
113 PRIVATE void create_supply(NODE, CAPACITY); /* create supply nodes */
114 PRIVATE void create_assignment(long*); /* create assignment problem */
115 PRIVATE void sort_skeleton(int); /* sorts skeleton chains */
116 PRIVATE void pick_head(long*, int, NODE); /* choose destination nodes for rubbish arcs */
117 PRIVATE void error_exit(long); /* print error message and exit */
119 PRIVATE void create_supply(); /* create supply nodes */
120 PRIVATE void create_assignment(); /* create assignment problem */
121 PRIVATE void sort_skeleton(); /* sorts skeleton chains */
122 PRIVATE void pick_head(); /* chooses destination nodes for rubbish arcs */
123 PRIVATE void error_exit(); /* print error message and exit */
126 /*** Private variables */
128 static NODE nodes_left;
129 static ARC arc_count;
130 static NODE pred[MAXARCS];
131 static NODE head[MAXARCS];
132 static NODE tail[MAXARCS];
137 #define MIN(x, y) ((x) < (y) ? (x) : (y))
138 #define MAX(x, y) ((x) > (y) ? (x) : (y))
139 #define SAVE_ARC(tail, head, cost, capacity) /* records an arc where our caller can get it */ \
141 FROM[arc_count] = tail; \
142 TO [arc_count] = head; \
143 C [arc_count] = cost; \
144 U [arc_count] = capacity; \
149 /*** Fortran callable interface routine */
151 void netgen_(seed, parms, generated_nodes, generated_arcs)
152 long* seed; /* pointer to random seed */
153 long parms[PROBLEM_PARMS]; /* problem parameters */
154 long* generated_nodes; /* number of generated nodes */
155 long* generated_arcs; /* number of generated arcs */
157 *generated_nodes = NODES;
158 if ((*generated_arcs = netgen(*seed, parms)) < 0)
159 error_exit(*generated_arcs);
163 /*** C callable interface routine */
165 ARC netgen(seed, parms)
166 long seed; /* random seed */
167 long parms[]; /* problem parameters */
172 NODE sinks_per_source;
184 /*** Perform sanity checks on the input */
188 if (NODES > MAXNODES || DENSITY > MAXARCS)
194 (SOURCES + SINKS > NODES) ||
195 (MINCOST > MAXCOST) ||
196 (SUPPLY < SOURCES) ||
197 (TSOURCES > SOURCES) ||
199 (HICOST < 0 || HICOST > 100) ||
200 (CAPACITATED < 0 || CAPACITATED > 100) ||
205 /*** Do a little bit of setting up. */
210 nodes_left = NODES - SINKS + TSINKS;
212 if ((SOURCES-TSOURCES)+(SINKS-TSINKS) == NODES &&
213 (SOURCES-TSOURCES) == (SINKS-TSINKS) &&
215 create_assignment(parms);
219 (void)memset((void *)B, 0, sizeof(B));/* set supplies and demands to zero */
221 create_supply((NODE)SOURCES, (CAPACITY)SUPPLY);
224 /*** Form most of the network skeleton. First, 60% of the transshipment
225 *** nodes are divided evenly among the various sources; the remainder
226 *** are chained onto the end of the chains belonging to random sources.
229 for (i = 1; i <= SOURCES; i++) /* point SOURCES at themselves */
231 handle = make_index_list((INDEX)(SOURCES + 1), (INDEX)(NODES - SINKS));
233 for (i = NODES-SOURCES-SINKS; i > (4*(NODES-SOURCES-SINKS)+9)/10; i--) {
234 node = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
235 pred[node] = pred[source];
237 if (++source > SOURCES)
240 for ( ; i > 0; --i) {
241 node = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
242 source = ng_random(1L, SOURCES);
243 pred[node] = pred[source];
246 free_index_list(handle);
249 /*** For each source chain, hook it to an "appropriate" number of sinks,
250 *** place capacities and costs on the skeleton edges, and then call
251 *** pick_head to add a bunch of rubbish edges at each node on the chain.
254 for (source = 1; source <= SOURCES; source++) {
257 while (node != source) {
259 head[sort_count] = node;
260 node = tail[sort_count] = pred[node];
262 if ((NODES-SOURCES-SINKS) == 0)
263 sinks_per_source = SINKS/SOURCES + 1;
265 /* changing to handle overflows with large n; Mar 18 -- jc */
266 sinks_per_source = ((double) 2*sort_count*SINKS) / ((double) NODES-SOURCES-SINKS);
267 sinks_per_source = MAX(2, MIN(sinks_per_source, SINKS));
268 sinks = (NODE*) malloc(sinks_per_source * sizeof(NODE));
269 handle = make_index_list((INDEX)(NODES - SINKS), (INDEX)(NODES - 1));
270 for (i = 0; i < sinks_per_source; i++) {
271 sinks[i] = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
273 if (source == SOURCES && index_size(handle) > 0) {
274 sinks = (NODE*) realloc((void *)sinks, (sinks_per_source + index_size(handle)) * sizeof(NODE));
275 while (index_size(handle) > 0) {
276 j = choose_index(handle, 1);
278 sinks[sinks_per_source++] = j;
281 free_index_list(handle);
283 chain_length = sort_count;
284 supply_per_sink = B[source-1] / sinks_per_source;
286 for (i = 0; i < sinks_per_source; i++) {
288 partial_supply = ng_random(1L, (long)supply_per_sink);
289 j = ng_random(0L, (long)sinks_per_source - 1);
290 tail[sort_count] = k;
291 head[sort_count] = sinks[i] + 1;
292 B[sinks[i]] -= partial_supply;
293 B[sinks[j]] -= (supply_per_sink - partial_supply);
295 for (j = ng_random(1L, (long)chain_length); j > 0; j--)
298 B[sinks[0]] -= (B[source-1] % sinks_per_source);
301 sort_skeleton(sort_count);
302 tail[sort_count+1] = 0;
303 for (i = 1; i <= sort_count; ) {
304 handle = make_index_list((INDEX)(SOURCES - TSOURCES + 1), (INDEX)NODES);
305 remove_index(handle, (INDEX)tail[i]);
307 while (it == tail[i]) {
308 remove_index(handle, (INDEX)head[i]);
310 if (ng_random(1L, 100L) <= CAPACITATED)
311 cap = MAX(B[source-1], MINCAP);
313 if (ng_random(1L, 100L) > HICOST)
314 cost = ng_random(MINCOST, MAXCOST);
315 SAVE_ARC(it,head[i],cost,cap);
318 pick_head(parms, handle, it);
319 free_index_list(handle);
324 /*** Add more rubbish edges out of the transshipment sinks. */
326 for (i = NODES - SINKS + 1; i <= NODES - SINKS + TSINKS; i++) {
327 handle = make_index_list((INDEX)(SOURCES - TSOURCES + 1), (INDEX)NODES);
328 remove_index(handle, (INDEX)i);
329 pick_head(parms, handle, i);
330 free_index_list(handle);
337 PRIVATE void create_supply(sources, supply)
341 CAPACITY supply_per_source = supply / sources;
342 CAPACITY partial_supply;
345 for (i = 0; i < sources; i++) {
346 B[i] += (partial_supply = ng_random(1L, (long)supply_per_source));
347 B[ng_random(0L, (long)(sources - 1))] += supply_per_source - partial_supply;
349 B[ng_random(0L, (long)(sources - 1))] += supply % sources;
353 PRIVATE void create_assignment(parms)
356 INDEX_LIST skeleton, handle;
360 for (source = 0; source < NODES/2; source++)
362 for ( ; source < NODES; source++)
365 skeleton = make_index_list((INDEX)(SOURCES + 1), (INDEX)NODES);
366 for (source = 1; source <= NODES/2; source++) {
367 index = choose_index(skeleton, (INDEX)ng_random(1L, (long)index_size(skeleton)));
368 SAVE_ARC(source, index, ng_random(MINCOST, MAXCOST), 1);
369 handle = make_index_list((INDEX)(SOURCES + 1), (INDEX)NODES);
370 remove_index(handle, index);
371 pick_head(parms, handle, source);
372 free_index_list(handle);
374 free_index_list(skeleton);
378 PRIVATE void sort_skeleton(sort_count) /* Shell sort */
385 while ((m /= 2) != 0) {
387 for (j = 1; j <= k; j++) {
389 while (i >= 1 && tail[i] > tail[i+m]) {
403 PRIVATE void pick_head(parms, handle, desired_tail)
408 NODE non_sources = NODES - SOURCES + TSOURCES;
410 /* changing Aug 29 -- jc
411 ARC remaining_arcs = DENSITY - arc_count;
413 int remaining_arcs = (int) DENSITY - (int) arc_count;
420 /* changing Aug 29 -- jc
423 if ((2 * (int) nodes_left) >= (int) remaining_arcs)
426 if ((remaining_arcs + non_sources - pseudo_size(handle) - 1) / (nodes_left + 1) >= non_sources - 1) {
429 upper_bound = 2 * (remaining_arcs / (nodes_left + 1) - 1);
431 limit = ng_random(1L, upper_bound);
433 limit = remaining_arcs;
434 /* changing to handle overflows with large n; Mar 18 -- jc */
435 } while ( ((double) nodes_left * (non_sources - 1)) < ((double) remaining_arcs - limit));
438 for ( ; limit > 0; limit--) {
439 index = choose_index(handle, (INDEX)ng_random(1L, (long)pseudo_size(handle)));
441 if (ng_random(1L, 100L) <= CAPACITATED)
442 cap = ng_random(MINCAP, MAXCAP);
444 /* adding Aug 29 -- jc */
445 if ((1 <= index) && (index <= NODES)) {
446 SAVE_ARC(desired_tail, index, ng_random(MINCOST, MAXCOST), cap);
453 /*** Print an appropriate error message and then exit with a nonzero code. */
455 PRIVATE void error_exit(rc)
460 fprintf(stderr, "NETGEN requires a positive random seed\n");
463 fprintf(stderr, "Problem too large for generator\n");
466 fprintf(stderr, "Inconsistent parameter settings - check the input\n");
468 case ALLOCATION_FAILURE:
469 fprintf(stderr, "Memory allocation failure\n");
472 fprintf(stderr, "Internal error\n");
475 exit(1000 - (int)rc);
478 #ifdef DIMACS /* generates network on standard output */
480 #define READ(v) /* read one variable using scanf */ \
481 switch( scanf("%ld", &v) ) { \
492 long parms[PROBLEM_PARMS];
496 /*** Read problem parameters and generate networks */
500 if (seed <= 0) exit(0);
502 if (problem <= 0) exit(0);
503 for (i = 0; i < PROBLEM_PARMS; i++)
505 printf("c NETGEN flow network generator (C version)\n");
506 printf("c Problem %2ld input parameters\n", problem);
507 printf("c ---------------------------\n");
508 printf("c Random seed: %10ld\n", seed);
509 printf("c Number of nodes: %10ld\n", NODES);
510 printf("c Source nodes: %10ld\n", SOURCES);
511 printf("c Sink nodes: %10ld\n", SINKS);
512 printf("c Number of arcs: %10ld\n", DENSITY);
513 printf("c Minimum arc cost: %10ld\n", MINCOST);
514 printf("c Maximum arc cost: %10ld\n", MAXCOST);
515 printf("c Total supply: %10ld\n", SUPPLY);
516 printf("c Transshipment -\n");
517 printf("c Sources: %10ld\n", TSOURCES);
518 printf("c Sinks: %10ld\n", TSINKS);
519 printf("c Skeleton arcs -\n");
520 printf("c With max cost: %10ld%%\n", HICOST);
521 printf("c Capacitated: %10ld%%\n", CAPACITATED);
522 printf("c Minimum arc capacity: %10ld\n", MINCAP);
523 printf("c Maximum arc capacity: %10ld\n", MAXCAP);
525 if ((arcs = netgen(seed, parms)) < 0)
527 if ((SOURCES-TSOURCES)+(SINKS-TSINKS) == NODES &&
528 (SOURCES-TSOURCES) == (SINKS-TSINKS) &&
531 printf("c *** Assignment ***\n");
533 printf("p asn %ld %ld\n", NODES, arcs);
534 for (i = 0; i < NODES; i++) {
536 printf("n %ld\n", i + 1);
538 for (i = 0; i < arcs; i++) {
539 printf("a %ld %ld %ld\n", FROM[i], TO[i], C[i]);
542 if (MINCOST == 1 && MAXCOST == 1) {
544 printf("c *** Maximum flow ***\n");
546 printf("p max %ld %ld\n", NODES, arcs);
547 for (i = 0; i < NODES; i++) {
549 printf("n %ld s\n", i + 1);
552 printf("n %ld t\n", i + 1);
554 for (i = 0; i < arcs; i++) {
555 printf("a %ld %ld %ld\n", FROM[i], TO[i], U[i]);
559 printf("c *** Minimum cost flow ***\n");
561 printf("p min %ld %ld\n", NODES, arcs);
562 for (i = 0; i < NODES; i++) {
564 printf("n %ld %ld\n", i + 1, B[i]);
566 for (i = 0; i < arcs; i++) {
567 printf("a %ld %ld %ld %ld %ld\n", FROM[i], TO[i], 0, U[i], C[i]);