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@7
|
88 |
#include "main.h"
|
alpar@6
|
89 |
|
alpar@6
|
90 |
/*** Private interfaces */
|
alpar@6
|
91 |
|
alpar@6
|
92 |
#ifdef DEBUG
|
alpar@6
|
93 |
#define PRIVATE
|
alpar@6
|
94 |
#else
|
alpar@6
|
95 |
#define PRIVATE static
|
alpar@6
|
96 |
#endif
|
alpar@6
|
97 |
|
alpar@6
|
98 |
#ifdef __STDC__
|
alpar@6
|
99 |
PRIVATE void create_supply(NODE, CAPACITY); /* create supply nodes */
|
alpar@6
|
100 |
PRIVATE void create_assignment(long*); /* create assignment problem */
|
alpar@6
|
101 |
PRIVATE void sort_skeleton(int); /* sorts skeleton chains */
|
alpar@6
|
102 |
PRIVATE void pick_head(long*, int, NODE); /* choose destination nodes for rubbish arcs */
|
alpar@6
|
103 |
PRIVATE void error_exit(long); /* print error message and exit */
|
alpar@6
|
104 |
#else
|
alpar@6
|
105 |
PRIVATE void create_supply(); /* create supply nodes */
|
alpar@6
|
106 |
PRIVATE void create_assignment(); /* create assignment problem */
|
alpar@6
|
107 |
PRIVATE void sort_skeleton(); /* sorts skeleton chains */
|
alpar@6
|
108 |
PRIVATE void pick_head(); /* chooses destination nodes for rubbish arcs */
|
alpar@6
|
109 |
PRIVATE void error_exit(); /* print error message and exit */
|
alpar@6
|
110 |
#endif
|
alpar@6
|
111 |
|
alpar@6
|
112 |
/*** Private variables */
|
alpar@6
|
113 |
|
alpar@6
|
114 |
static NODE nodes_left;
|
alpar@6
|
115 |
static ARC arc_count;
|
alpar@6
|
116 |
static NODE pred[MAXARCS];
|
alpar@6
|
117 |
static NODE head[MAXARCS];
|
alpar@6
|
118 |
static NODE tail[MAXARCS];
|
alpar@6
|
119 |
|
alpar@6
|
120 |
|
alpar@6
|
121 |
/*** Local macros */
|
alpar@6
|
122 |
|
alpar@6
|
123 |
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
alpar@6
|
124 |
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
alpar@6
|
125 |
#define SAVE_ARC(tail, head, cost, capacity) /* records an arc where our caller can get it */ \
|
alpar@6
|
126 |
{ \
|
alpar@6
|
127 |
FROM[arc_count] = tail; \
|
alpar@6
|
128 |
TO [arc_count] = head; \
|
alpar@6
|
129 |
C [arc_count] = cost; \
|
alpar@6
|
130 |
U [arc_count] = capacity; \
|
alpar@6
|
131 |
arc_count++; \
|
alpar@6
|
132 |
}
|
alpar@6
|
133 |
|
alpar@6
|
134 |
|
alpar@6
|
135 |
/*** Fortran callable interface routine */
|
alpar@6
|
136 |
|
alpar@6
|
137 |
void netgen_(seed, parms, generated_nodes, generated_arcs)
|
alpar@6
|
138 |
long* seed; /* pointer to random seed */
|
alpar@6
|
139 |
long parms[PROBLEM_PARMS]; /* problem parameters */
|
alpar@6
|
140 |
long* generated_nodes; /* number of generated nodes */
|
alpar@6
|
141 |
long* generated_arcs; /* number of generated arcs */
|
alpar@6
|
142 |
{
|
alpar@6
|
143 |
*generated_nodes = NODES;
|
alpar@6
|
144 |
if ((*generated_arcs = netgen(*seed, parms)) < 0)
|
alpar@6
|
145 |
error_exit(*generated_arcs);
|
alpar@6
|
146 |
}
|
alpar@6
|
147 |
|
alpar@6
|
148 |
|
alpar@6
|
149 |
/*** C callable interface routine */
|
alpar@6
|
150 |
|
alpar@6
|
151 |
ARC netgen(seed, parms)
|
alpar@6
|
152 |
long seed; /* random seed */
|
alpar@6
|
153 |
long parms[]; /* problem parameters */
|
alpar@6
|
154 |
{
|
alpar@6
|
155 |
register NODE i,j,k;
|
alpar@6
|
156 |
NODE source;
|
alpar@6
|
157 |
NODE node;
|
alpar@6
|
158 |
NODE sinks_per_source;
|
alpar@6
|
159 |
NODE* sinks;
|
alpar@6
|
160 |
NODE it;
|
alpar@6
|
161 |
int chain_length;
|
alpar@6
|
162 |
COST cost;
|
alpar@6
|
163 |
CAPACITY cap;
|
alpar@6
|
164 |
INDEX_LIST handle;
|
alpar@6
|
165 |
int supply_per_sink;
|
alpar@6
|
166 |
int partial_supply;
|
alpar@6
|
167 |
int sort_count;
|
alpar@6
|
168 |
|
alpar@6
|
169 |
|
alpar@6
|
170 |
/*** Perform sanity checks on the input */
|
alpar@6
|
171 |
|
alpar@6
|
172 |
if (seed <= 0)
|
alpar@6
|
173 |
return BAD_SEED;
|
alpar@6
|
174 |
if (NODES > MAXNODES || DENSITY > MAXARCS)
|
alpar@6
|
175 |
return TOO_BIG;
|
alpar@6
|
176 |
if ((NODES <= 0) ||
|
alpar@6
|
177 |
(NODES > DENSITY) ||
|
alpar@6
|
178 |
(SOURCES <= 0) ||
|
alpar@6
|
179 |
(SINKS <= 0) ||
|
alpar@6
|
180 |
(SOURCES + SINKS > NODES) ||
|
alpar@6
|
181 |
(MINCOST > MAXCOST) ||
|
alpar@6
|
182 |
(SUPPLY < SOURCES) ||
|
alpar@6
|
183 |
(TSOURCES > SOURCES) ||
|
alpar@6
|
184 |
(TSINKS > SINKS) ||
|
alpar@6
|
185 |
(HICOST < 0 || HICOST > 100) ||
|
alpar@6
|
186 |
(CAPACITATED < 0 || CAPACITATED > 100) ||
|
alpar@6
|
187 |
(MINCAP > MAXCAP))
|
alpar@6
|
188 |
return BAD_PARMS;
|
alpar@6
|
189 |
|
alpar@6
|
190 |
|
alpar@6
|
191 |
/*** Do a little bit of setting up. */
|
alpar@6
|
192 |
|
alpar@6
|
193 |
set_random(seed);
|
alpar@6
|
194 |
|
alpar@6
|
195 |
arc_count = 0;
|
alpar@6
|
196 |
nodes_left = NODES - SINKS + TSINKS;
|
alpar@6
|
197 |
|
alpar@6
|
198 |
if ((SOURCES-TSOURCES)+(SINKS-TSINKS) == NODES &&
|
alpar@6
|
199 |
(SOURCES-TSOURCES) == (SINKS-TSINKS) &&
|
alpar@6
|
200 |
SOURCES == SUPPLY) {
|
alpar@6
|
201 |
create_assignment(parms);
|
alpar@6
|
202 |
return arc_count;
|
alpar@6
|
203 |
}
|
alpar@6
|
204 |
|
alpar@6
|
205 |
(void)memset((void *)B, 0, sizeof(B));/* set supplies and demands to zero */
|
alpar@6
|
206 |
|
alpar@6
|
207 |
create_supply((NODE)SOURCES, (CAPACITY)SUPPLY);
|
alpar@6
|
208 |
|
alpar@6
|
209 |
|
alpar@6
|
210 |
/*** Form most of the network skeleton. First, 60% of the transshipment
|
alpar@6
|
211 |
*** nodes are divided evenly among the various sources; the remainder
|
alpar@6
|
212 |
*** are chained onto the end of the chains belonging to random sources.
|
alpar@6
|
213 |
***/
|
alpar@6
|
214 |
|
alpar@6
|
215 |
for (i = 1; i <= SOURCES; i++) /* point SOURCES at themselves */
|
alpar@6
|
216 |
pred[i] = i;
|
alpar@6
|
217 |
handle = make_index_list((INDEX)(SOURCES + 1), (INDEX)(NODES - SINKS));
|
alpar@6
|
218 |
source = 1;
|
alpar@6
|
219 |
for (i = NODES-SOURCES-SINKS; i > (4*(NODES-SOURCES-SINKS)+9)/10; i--) {
|
alpar@6
|
220 |
node = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
|
alpar@6
|
221 |
pred[node] = pred[source];
|
alpar@6
|
222 |
pred[source] = node;
|
alpar@6
|
223 |
if (++source > SOURCES)
|
alpar@6
|
224 |
source = 1;
|
alpar@6
|
225 |
}
|
alpar@6
|
226 |
for ( ; i > 0; --i) {
|
alpar@6
|
227 |
node = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
|
alpar@6
|
228 |
source = ng_random(1L, SOURCES);
|
alpar@6
|
229 |
pred[node] = pred[source];
|
alpar@6
|
230 |
pred[source] = node;
|
alpar@6
|
231 |
}
|
alpar@6
|
232 |
free_index_list(handle);
|
alpar@6
|
233 |
|
alpar@6
|
234 |
|
alpar@6
|
235 |
/*** For each source chain, hook it to an "appropriate" number of sinks,
|
alpar@6
|
236 |
*** place capacities and costs on the skeleton edges, and then call
|
alpar@6
|
237 |
*** pick_head to add a bunch of rubbish edges at each node on the chain.
|
alpar@6
|
238 |
***/
|
alpar@6
|
239 |
|
alpar@6
|
240 |
for (source = 1; source <= SOURCES; source++) {
|
alpar@6
|
241 |
sort_count = 0;
|
alpar@6
|
242 |
node = pred[source];
|
alpar@6
|
243 |
while (node != source) {
|
alpar@6
|
244 |
sort_count++;
|
alpar@6
|
245 |
head[sort_count] = node;
|
alpar@6
|
246 |
node = tail[sort_count] = pred[node];
|
alpar@6
|
247 |
}
|
alpar@6
|
248 |
if ((NODES-SOURCES-SINKS) == 0)
|
alpar@6
|
249 |
sinks_per_source = SINKS/SOURCES + 1;
|
alpar@6
|
250 |
else
|
alpar@6
|
251 |
/* changing to handle overflows with large n; Mar 18 -- jc */
|
alpar@6
|
252 |
sinks_per_source = ((double) 2*sort_count*SINKS) / ((double) NODES-SOURCES-SINKS);
|
alpar@6
|
253 |
sinks_per_source = MAX(2, MIN(sinks_per_source, SINKS));
|
alpar@6
|
254 |
sinks = (NODE*) malloc(sinks_per_source * sizeof(NODE));
|
alpar@6
|
255 |
handle = make_index_list((INDEX)(NODES - SINKS), (INDEX)(NODES - 1));
|
alpar@6
|
256 |
for (i = 0; i < sinks_per_source; i++) {
|
alpar@6
|
257 |
sinks[i] = choose_index(handle, (INDEX)ng_random(1L, (long)index_size(handle)));
|
alpar@6
|
258 |
}
|
alpar@6
|
259 |
if (source == SOURCES && index_size(handle) > 0) {
|
alpar@6
|
260 |
sinks = (NODE*) realloc((void *)sinks, (sinks_per_source + index_size(handle)) * sizeof(NODE));
|
alpar@6
|
261 |
while (index_size(handle) > 0) {
|
alpar@6
|
262 |
j = choose_index(handle, 1);
|
alpar@6
|
263 |
if (B[j] == 0)
|
alpar@6
|
264 |
sinks[sinks_per_source++] = j;
|
alpar@6
|
265 |
}
|
alpar@6
|
266 |
}
|
alpar@6
|
267 |
free_index_list(handle);
|
alpar@6
|
268 |
|
alpar@6
|
269 |
chain_length = sort_count;
|
alpar@6
|
270 |
supply_per_sink = B[source-1] / sinks_per_source;
|
alpar@6
|
271 |
k = pred[source];
|
alpar@6
|
272 |
for (i = 0; i < sinks_per_source; i++) {
|
alpar@6
|
273 |
sort_count++;
|
alpar@6
|
274 |
partial_supply = ng_random(1L, (long)supply_per_sink);
|
alpar@6
|
275 |
j = ng_random(0L, (long)sinks_per_source - 1);
|
alpar@6
|
276 |
tail[sort_count] = k;
|
alpar@6
|
277 |
head[sort_count] = sinks[i] + 1;
|
alpar@6
|
278 |
B[sinks[i]] -= partial_supply;
|
alpar@6
|
279 |
B[sinks[j]] -= (supply_per_sink - partial_supply);
|
alpar@6
|
280 |
k = source;
|
alpar@6
|
281 |
for (j = ng_random(1L, (long)chain_length); j > 0; j--)
|
alpar@6
|
282 |
k = pred[k];
|
alpar@6
|
283 |
}
|
alpar@6
|
284 |
B[sinks[0]] -= (B[source-1] % sinks_per_source);
|
alpar@6
|
285 |
free((void *)sinks);
|
alpar@6
|
286 |
|
alpar@6
|
287 |
sort_skeleton(sort_count);
|
alpar@6
|
288 |
tail[sort_count+1] = 0;
|
alpar@6
|
289 |
for (i = 1; i <= sort_count; ) {
|
alpar@6
|
290 |
handle = make_index_list((INDEX)(SOURCES - TSOURCES + 1), (INDEX)NODES);
|
alpar@6
|
291 |
remove_index(handle, (INDEX)tail[i]);
|
alpar@6
|
292 |
it = tail[i];
|
alpar@6
|
293 |
while (it == tail[i]) {
|
alpar@6
|
294 |
remove_index(handle, (INDEX)head[i]);
|
alpar@6
|
295 |
cap = SUPPLY;
|
alpar@6
|
296 |
if (ng_random(1L, 100L) <= CAPACITATED)
|
alpar@6
|
297 |
cap = MAX(B[source-1], MINCAP);
|
alpar@6
|
298 |
cost = MAXCOST;
|
alpar@6
|
299 |
if (ng_random(1L, 100L) > HICOST)
|
alpar@6
|
300 |
cost = ng_random(MINCOST, MAXCOST);
|
alpar@6
|
301 |
SAVE_ARC(it,head[i],cost,cap);
|
alpar@6
|
302 |
i++;
|
alpar@6
|
303 |
}
|
alpar@6
|
304 |
pick_head(parms, handle, it);
|
alpar@6
|
305 |
free_index_list(handle);
|
alpar@6
|
306 |
}
|
alpar@6
|
307 |
}
|
alpar@6
|
308 |
|
alpar@6
|
309 |
|
alpar@6
|
310 |
/*** Add more rubbish edges out of the transshipment sinks. */
|
alpar@6
|
311 |
|
alpar@6
|
312 |
for (i = NODES - SINKS + 1; i <= NODES - SINKS + TSINKS; i++) {
|
alpar@6
|
313 |
handle = make_index_list((INDEX)(SOURCES - TSOURCES + 1), (INDEX)NODES);
|
alpar@6
|
314 |
remove_index(handle, (INDEX)i);
|
alpar@6
|
315 |
pick_head(parms, handle, i);
|
alpar@6
|
316 |
free_index_list(handle);
|
alpar@6
|
317 |
}
|
alpar@6
|
318 |
|
alpar@6
|
319 |
return arc_count;
|
alpar@6
|
320 |
}
|
alpar@6
|
321 |
|
alpar@6
|
322 |
|
alpar@6
|
323 |
PRIVATE void create_supply(sources, supply)
|
alpar@6
|
324 |
NODE sources;
|
alpar@6
|
325 |
CAPACITY supply;
|
alpar@6
|
326 |
{
|
alpar@6
|
327 |
CAPACITY supply_per_source = supply / sources;
|
alpar@6
|
328 |
CAPACITY partial_supply;
|
alpar@6
|
329 |
NODE i;
|
alpar@6
|
330 |
|
alpar@6
|
331 |
for (i = 0; i < sources; i++) {
|
alpar@6
|
332 |
B[i] += (partial_supply = ng_random(1L, (long)supply_per_source));
|
alpar@6
|
333 |
B[ng_random(0L, (long)(sources - 1))] += supply_per_source - partial_supply;
|
alpar@6
|
334 |
}
|
alpar@6
|
335 |
B[ng_random(0L, (long)(sources - 1))] += supply % sources;
|
alpar@6
|
336 |
}
|
alpar@6
|
337 |
|
alpar@6
|
338 |
|
alpar@6
|
339 |
PRIVATE void create_assignment(parms)
|
alpar@6
|
340 |
long parms[];
|
alpar@6
|
341 |
{
|
alpar@6
|
342 |
INDEX_LIST skeleton, handle;
|
alpar@6
|
343 |
INDEX index;
|
alpar@6
|
344 |
NODE source;
|
alpar@6
|
345 |
|
alpar@6
|
346 |
for (source = 0; source < NODES/2; source++)
|
alpar@6
|
347 |
B[source] = 1;
|
alpar@6
|
348 |
for ( ; source < NODES; source++)
|
alpar@6
|
349 |
B[source] = -1;
|
alpar@6
|
350 |
|
alpar@6
|
351 |
skeleton = make_index_list((INDEX)(SOURCES + 1), (INDEX)NODES);
|
alpar@6
|
352 |
for (source = 1; source <= NODES/2; source++) {
|
alpar@6
|
353 |
index = choose_index(skeleton, (INDEX)ng_random(1L, (long)index_size(skeleton)));
|
alpar@6
|
354 |
SAVE_ARC(source, index, ng_random(MINCOST, MAXCOST), 1);
|
alpar@6
|
355 |
handle = make_index_list((INDEX)(SOURCES + 1), (INDEX)NODES);
|
alpar@6
|
356 |
remove_index(handle, index);
|
alpar@6
|
357 |
pick_head(parms, handle, source);
|
alpar@6
|
358 |
free_index_list(handle);
|
alpar@6
|
359 |
}
|
alpar@6
|
360 |
free_index_list(skeleton);
|
alpar@6
|
361 |
}
|
alpar@6
|
362 |
|
alpar@6
|
363 |
|
alpar@6
|
364 |
PRIVATE void sort_skeleton(sort_count) /* Shell sort */
|
alpar@6
|
365 |
int sort_count;
|
alpar@6
|
366 |
{
|
alpar@6
|
367 |
int m,i,j,k;
|
alpar@6
|
368 |
int temp;
|
alpar@6
|
369 |
|
alpar@6
|
370 |
m = sort_count;
|
alpar@6
|
371 |
while ((m /= 2) != 0) {
|
alpar@6
|
372 |
k = sort_count - m;
|
alpar@6
|
373 |
for (j = 1; j <= k; j++) {
|
alpar@6
|
374 |
i = j;
|
alpar@6
|
375 |
while (i >= 1 && tail[i] > tail[i+m]) {
|
alpar@6
|
376 |
temp = tail[i];
|
alpar@6
|
377 |
tail[i] = tail[i+m];
|
alpar@6
|
378 |
tail[i+m] = temp;
|
alpar@6
|
379 |
temp = head[i];
|
alpar@6
|
380 |
head[i] = head[i+m];
|
alpar@6
|
381 |
head[i+m] = temp;
|
alpar@6
|
382 |
i -= m;
|
alpar@6
|
383 |
}
|
alpar@6
|
384 |
}
|
alpar@6
|
385 |
}
|
alpar@6
|
386 |
}
|
alpar@6
|
387 |
|
alpar@6
|
388 |
|
alpar@6
|
389 |
PRIVATE void pick_head(parms, handle, desired_tail)
|
alpar@6
|
390 |
long parms[];
|
alpar@6
|
391 |
INDEX_LIST handle;
|
alpar@6
|
392 |
NODE desired_tail;
|
alpar@6
|
393 |
{
|
alpar@6
|
394 |
NODE non_sources = NODES - SOURCES + TSOURCES;
|
alpar@6
|
395 |
|
alpar@6
|
396 |
/* changing Aug 29 -- jc
|
alpar@6
|
397 |
ARC remaining_arcs = DENSITY - arc_count;
|
alpar@6
|
398 |
*/
|
alpar@6
|
399 |
int remaining_arcs = (int) DENSITY - (int) arc_count;
|
alpar@6
|
400 |
|
alpar@6
|
401 |
INDEX index;
|
alpar@6
|
402 |
int limit;
|
alpar@6
|
403 |
long upper_bound;
|
alpar@6
|
404 |
CAPACITY cap;
|
alpar@6
|
405 |
|
alpar@6
|
406 |
/* changing Aug 29 -- jc
|
alpar@6
|
407 |
*/
|
alpar@6
|
408 |
nodes_left--;
|
alpar@6
|
409 |
if ((2 * (int) nodes_left) >= (int) remaining_arcs)
|
alpar@6
|
410 |
return;
|
alpar@6
|
411 |
|
alpar@6
|
412 |
if ((remaining_arcs + non_sources - pseudo_size(handle) - 1) / (nodes_left + 1) >= non_sources - 1) {
|
alpar@6
|
413 |
limit = non_sources;
|
alpar@6
|
414 |
} else {
|
alpar@6
|
415 |
upper_bound = 2 * (remaining_arcs / (nodes_left + 1) - 1);
|
alpar@6
|
416 |
do {
|
alpar@6
|
417 |
limit = ng_random(1L, upper_bound);
|
alpar@6
|
418 |
if (nodes_left == 0)
|
alpar@6
|
419 |
limit = remaining_arcs;
|
alpar@6
|
420 |
/* changing to handle overflows with large n; Mar 18 -- jc */
|
alpar@6
|
421 |
} while ( ((double) nodes_left * (non_sources - 1)) < ((double) remaining_arcs - limit));
|
alpar@6
|
422 |
}
|
alpar@6
|
423 |
|
alpar@6
|
424 |
for ( ; limit > 0; limit--) {
|
alpar@6
|
425 |
index = choose_index(handle, (INDEX)ng_random(1L, (long)pseudo_size(handle)));
|
alpar@6
|
426 |
cap = SUPPLY;
|
alpar@6
|
427 |
if (ng_random(1L, 100L) <= CAPACITATED)
|
alpar@6
|
428 |
cap = ng_random(MINCAP, MAXCAP);
|
alpar@6
|
429 |
|
alpar@6
|
430 |
/* adding Aug 29 -- jc */
|
alpar@6
|
431 |
if ((1 <= index) && (index <= NODES)) {
|
alpar@6
|
432 |
SAVE_ARC(desired_tail, index, ng_random(MINCOST, MAXCOST), cap);
|
alpar@6
|
433 |
}
|
alpar@6
|
434 |
|
alpar@6
|
435 |
}
|
alpar@6
|
436 |
}
|
alpar@6
|
437 |
|
alpar@6
|
438 |
|
alpar@6
|
439 |
/*** Print an appropriate error message and then exit with a nonzero code. */
|
alpar@6
|
440 |
|
alpar@6
|
441 |
PRIVATE void error_exit(rc)
|
alpar@6
|
442 |
long rc;
|
alpar@6
|
443 |
{
|
alpar@6
|
444 |
switch (rc) {
|
alpar@6
|
445 |
case BAD_SEED:
|
alpar@6
|
446 |
fprintf(stderr, "NETGEN requires a positive random seed\n");
|
alpar@6
|
447 |
break;
|
alpar@6
|
448 |
case TOO_BIG:
|
alpar@6
|
449 |
fprintf(stderr, "Problem too large for generator\n");
|
alpar@6
|
450 |
break;
|
alpar@6
|
451 |
case BAD_PARMS:
|
alpar@6
|
452 |
fprintf(stderr, "Inconsistent parameter settings - check the input\n");
|
alpar@6
|
453 |
break;
|
alpar@6
|
454 |
case ALLOCATION_FAILURE:
|
alpar@6
|
455 |
fprintf(stderr, "Memory allocation failure\n");
|
alpar@6
|
456 |
break;
|
alpar@6
|
457 |
default:
|
alpar@6
|
458 |
fprintf(stderr, "Internal error\n");
|
alpar@6
|
459 |
break;
|
alpar@6
|
460 |
}
|
alpar@6
|
461 |
exit(1000 - (int)rc);
|
alpar@6
|
462 |
}
|
alpar@6
|
463 |
|
alpar@6
|
464 |
#ifdef DIMACS /* generates network on standard output */
|
alpar@6
|
465 |
|
alpar@6
|
466 |
#define READ(v) /* read one variable using scanf */ \
|
alpar@6
|
467 |
switch( scanf("%ld", &v) ) { \
|
alpar@6
|
468 |
case 1: \
|
alpar@6
|
469 |
break; \
|
alpar@6
|
470 |
default: \
|
alpar@6
|
471 |
exit(0); \
|
alpar@6
|
472 |
}
|
alpar@6
|
473 |
|
alpar@7
|
474 |
int orig_main(long seed,long problem,long *parms)
|
alpar@6
|
475 |
{
|
alpar@6
|
476 |
long arcs;
|
alpar@6
|
477 |
int i;
|
alpar@6
|
478 |
|
alpar@6
|
479 |
/*** Read problem parameters and generate networks */
|
alpar@7
|
480 |
{
|
alpar@6
|
481 |
printf("c NETGEN flow network generator (C version)\n");
|
alpar@6
|
482 |
printf("c Problem %2ld input parameters\n", problem);
|
alpar@6
|
483 |
printf("c ---------------------------\n");
|
alpar@6
|
484 |
printf("c Random seed: %10ld\n", seed);
|
alpar@6
|
485 |
printf("c Number of nodes: %10ld\n", NODES);
|
alpar@6
|
486 |
printf("c Source nodes: %10ld\n", SOURCES);
|
alpar@6
|
487 |
printf("c Sink nodes: %10ld\n", SINKS);
|
alpar@6
|
488 |
printf("c Number of arcs: %10ld\n", DENSITY);
|
alpar@6
|
489 |
printf("c Minimum arc cost: %10ld\n", MINCOST);
|
alpar@6
|
490 |
printf("c Maximum arc cost: %10ld\n", MAXCOST);
|
alpar@6
|
491 |
printf("c Total supply: %10ld\n", SUPPLY);
|
alpar@6
|
492 |
printf("c Transshipment -\n");
|
alpar@6
|
493 |
printf("c Sources: %10ld\n", TSOURCES);
|
alpar@6
|
494 |
printf("c Sinks: %10ld\n", TSINKS);
|
alpar@6
|
495 |
printf("c Skeleton arcs -\n");
|
alpar@6
|
496 |
printf("c With max cost: %10ld%%\n", HICOST);
|
alpar@6
|
497 |
printf("c Capacitated: %10ld%%\n", CAPACITATED);
|
alpar@6
|
498 |
printf("c Minimum arc capacity: %10ld\n", MINCAP);
|
alpar@6
|
499 |
printf("c Maximum arc capacity: %10ld\n", MAXCAP);
|
alpar@6
|
500 |
|
alpar@6
|
501 |
if ((arcs = netgen(seed, parms)) < 0)
|
alpar@6
|
502 |
error_exit(arcs);
|
alpar@6
|
503 |
if ((SOURCES-TSOURCES)+(SINKS-TSINKS) == NODES &&
|
alpar@6
|
504 |
(SOURCES-TSOURCES) == (SINKS-TSINKS) &&
|
alpar@6
|
505 |
SOURCES == SUPPLY) {
|
alpar@6
|
506 |
printf("c\n");
|
alpar@6
|
507 |
printf("c *** Assignment ***\n");
|
alpar@6
|
508 |
printf("c\n");
|
alpar@6
|
509 |
printf("p asn %ld %ld\n", NODES, arcs);
|
alpar@6
|
510 |
for (i = 0; i < NODES; i++) {
|
alpar@6
|
511 |
if (B[i] > 0)
|
alpar@6
|
512 |
printf("n %ld\n", i + 1);
|
alpar@6
|
513 |
}
|
alpar@6
|
514 |
for (i = 0; i < arcs; i++) {
|
alpar@6
|
515 |
printf("a %ld %ld %ld\n", FROM[i], TO[i], C[i]);
|
alpar@6
|
516 |
}
|
alpar@6
|
517 |
} else
|
alpar@6
|
518 |
if (MINCOST == 1 && MAXCOST == 1) {
|
alpar@6
|
519 |
printf("c\n");
|
alpar@6
|
520 |
printf("c *** Maximum flow ***\n");
|
alpar@6
|
521 |
printf("c\n");
|
alpar@6
|
522 |
printf("p max %ld %ld\n", NODES, arcs);
|
alpar@6
|
523 |
for (i = 0; i < NODES; i++) {
|
alpar@6
|
524 |
if (B[i] > 0)
|
alpar@6
|
525 |
printf("n %ld s\n", i + 1);
|
alpar@6
|
526 |
else
|
alpar@6
|
527 |
if (B[i] < 0)
|
alpar@6
|
528 |
printf("n %ld t\n", i + 1);
|
alpar@6
|
529 |
}
|
alpar@6
|
530 |
for (i = 0; i < arcs; i++) {
|
alpar@6
|
531 |
printf("a %ld %ld %ld\n", FROM[i], TO[i], U[i]);
|
alpar@6
|
532 |
}
|
alpar@6
|
533 |
} else {
|
alpar@6
|
534 |
printf("c\n");
|
alpar@6
|
535 |
printf("c *** Minimum cost flow ***\n");
|
alpar@6
|
536 |
printf("c\n");
|
alpar@6
|
537 |
printf("p min %ld %ld\n", NODES, arcs);
|
alpar@6
|
538 |
for (i = 0; i < NODES; i++) {
|
alpar@6
|
539 |
if (B[i] != 0)
|
alpar@6
|
540 |
printf("n %ld %ld\n", i + 1, B[i]);
|
alpar@6
|
541 |
}
|
alpar@6
|
542 |
for (i = 0; i < arcs; i++) {
|
alpar@6
|
543 |
printf("a %ld %ld %ld %ld %ld\n", FROM[i], TO[i], 0, U[i], C[i]);
|
alpar@6
|
544 |
}
|
alpar@6
|
545 |
}
|
alpar@6
|
546 |
}
|
alpar@6
|
547 |
return 0;
|
alpar@6
|
548 |
}
|
alpar@6
|
549 |
|
alpar@6
|
550 |
#endif
|