alpar@1
|
1 |
/* glpnet05.c (Goldfarb's maximum flow 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 a modified version of the program RMFGEN, a maxflow
|
alpar@1
|
7 |
* problem generator developed by D.Goldfarb and M.Grigoriadis, and
|
alpar@1
|
8 |
* originally implemented by Tamas Badics <badics@rutcor.rutgers.edu>.
|
alpar@1
|
9 |
* The original code is publically available on the DIMACS ftp site at:
|
alpar@1
|
10 |
* <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>.
|
alpar@1
|
11 |
*
|
alpar@1
|
12 |
* All changes concern only the program interface, so this modified
|
alpar@1
|
13 |
* version produces exactly the same instances as the original version.
|
alpar@1
|
14 |
*
|
alpar@1
|
15 |
* Changes were made by Andrew Makhorin <mao@gnu.org>.
|
alpar@1
|
16 |
*
|
alpar@1
|
17 |
* GLPK is free software: you can redistribute it and/or modify it
|
alpar@1
|
18 |
* under the terms of the GNU General Public License as published by
|
alpar@1
|
19 |
* the Free Software Foundation, either version 3 of the License, or
|
alpar@1
|
20 |
* (at your option) any later version.
|
alpar@1
|
21 |
*
|
alpar@1
|
22 |
* GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@1
|
23 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@1
|
24 |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@1
|
25 |
* License for more details.
|
alpar@1
|
26 |
*
|
alpar@1
|
27 |
* You should have received a copy of the GNU General Public License
|
alpar@1
|
28 |
* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@1
|
29 |
***********************************************************************/
|
alpar@1
|
30 |
|
alpar@1
|
31 |
#include "glpapi.h"
|
alpar@1
|
32 |
#include "glprng.h"
|
alpar@1
|
33 |
|
alpar@1
|
34 |
/***********************************************************************
|
alpar@1
|
35 |
* NAME
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* glp_rmfgen - Goldfarb's maximum flow problem generator
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* SYNOPSIS
|
alpar@1
|
40 |
*
|
alpar@1
|
41 |
* int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
|
alpar@1
|
42 |
* const int parm[1+5]);
|
alpar@1
|
43 |
*
|
alpar@1
|
44 |
* DESCRIPTION
|
alpar@1
|
45 |
*
|
alpar@1
|
46 |
* The routine glp_rmfgen is a maximum flow problem generator developed
|
alpar@1
|
47 |
* by D.Goldfarb and M.Grigoriadis.
|
alpar@1
|
48 |
*
|
alpar@1
|
49 |
* The parameter G specifies the graph object, to which the generated
|
alpar@1
|
50 |
* problem data have to be stored. Note that on entry the graph object
|
alpar@1
|
51 |
* is erased with the routine glp_erase_graph.
|
alpar@1
|
52 |
*
|
alpar@1
|
53 |
* The pointer s specifies a location, to which the routine stores the
|
alpar@1
|
54 |
* source node number. If s is NULL, the node number is not stored.
|
alpar@1
|
55 |
*
|
alpar@1
|
56 |
* The pointer t specifies a location, to which the routine stores the
|
alpar@1
|
57 |
* sink node number. If t is NULL, the node number is not stored.
|
alpar@1
|
58 |
*
|
alpar@1
|
59 |
* The parameter a_cap specifies an offset of the field of type double
|
alpar@1
|
60 |
* in the arc data block, to which the routine stores the arc capacity.
|
alpar@1
|
61 |
* If a_cap < 0, the capacity is not stored.
|
alpar@1
|
62 |
*
|
alpar@1
|
63 |
* The array parm contains description of the network to be generated:
|
alpar@1
|
64 |
*
|
alpar@1
|
65 |
* parm[0] not used
|
alpar@1
|
66 |
* parm[1] (seed) random number seed (a positive integer)
|
alpar@1
|
67 |
* parm[2] (a) frame size
|
alpar@1
|
68 |
* parm[3] (b) depth
|
alpar@1
|
69 |
* parm[4] (c1) minimal arc capacity
|
alpar@1
|
70 |
* parm[5] (c2) maximal arc capacity
|
alpar@1
|
71 |
*
|
alpar@1
|
72 |
* RETURNS
|
alpar@1
|
73 |
*
|
alpar@1
|
74 |
* If the instance was successfully generated, the routine glp_netgen
|
alpar@1
|
75 |
* returns zero; otherwise, if specified parameters are inconsistent,
|
alpar@1
|
76 |
* the routine returns a non-zero error code.
|
alpar@1
|
77 |
*
|
alpar@1
|
78 |
* COMMENTS
|
alpar@1
|
79 |
*
|
alpar@1
|
80 |
* The generated network is as follows. It has b pieces of frames of
|
alpar@1
|
81 |
* size a * a. (So alltogether the number of vertices is a * a * b)
|
alpar@1
|
82 |
*
|
alpar@1
|
83 |
* In each frame all the vertices are connected with their neighbours
|
alpar@1
|
84 |
* (forth and back). In addition the vertices of a frame are connected
|
alpar@1
|
85 |
* one to one with the vertices of next frame using a random permutation
|
alpar@1
|
86 |
* of those vertices.
|
alpar@1
|
87 |
*
|
alpar@1
|
88 |
* The source is the lower left vertex of the first frame, the sink is
|
alpar@1
|
89 |
* the upper right vertex of the b'th frame.
|
alpar@1
|
90 |
*
|
alpar@1
|
91 |
* t
|
alpar@1
|
92 |
* +-------+
|
alpar@1
|
93 |
* | .|
|
alpar@1
|
94 |
* | . |
|
alpar@1
|
95 |
* / | / |
|
alpar@1
|
96 |
* +-------+/ -+ b
|
alpar@1
|
97 |
* | | |/.
|
alpar@1
|
98 |
* a | -v- |/
|
alpar@1
|
99 |
* | | |/
|
alpar@1
|
100 |
* +-------+ 1
|
alpar@1
|
101 |
* s a
|
alpar@1
|
102 |
*
|
alpar@1
|
103 |
* The capacities are randomly chosen integers from the range of [c1,c2]
|
alpar@1
|
104 |
* in the case of interconnecting edges, and c2 * a * a for the in-frame
|
alpar@1
|
105 |
* edges.
|
alpar@1
|
106 |
*
|
alpar@1
|
107 |
* REFERENCES
|
alpar@1
|
108 |
*
|
alpar@1
|
109 |
* D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the
|
alpar@1
|
110 |
* Dinic and network simplex methods for maximum flow." Annals of Op.
|
alpar@1
|
111 |
* Res. 13 (1988), pp. 83-123.
|
alpar@1
|
112 |
*
|
alpar@1
|
113 |
* U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm:
|
alpar@1
|
114 |
* A computational investigation." Zeitschrift fuer Operations Research
|
alpar@1
|
115 |
* 33 (1989), pp. 383-403. */
|
alpar@1
|
116 |
|
alpar@1
|
117 |
typedef struct VERTEX
|
alpar@1
|
118 |
{ struct EDGE **edgelist;
|
alpar@1
|
119 |
/* Pointer to the list of pointers to the adjacent edges.
|
alpar@1
|
120 |
(No matter that to or from edges) */
|
alpar@1
|
121 |
struct EDGE **current;
|
alpar@1
|
122 |
/* Pointer to the current edge */
|
alpar@1
|
123 |
int degree;
|
alpar@1
|
124 |
/* Number of adjacent edges (both direction) */
|
alpar@1
|
125 |
int index;
|
alpar@1
|
126 |
} vertex;
|
alpar@1
|
127 |
|
alpar@1
|
128 |
typedef struct EDGE
|
alpar@1
|
129 |
{ int from;
|
alpar@1
|
130 |
int to;
|
alpar@1
|
131 |
int cap;
|
alpar@1
|
132 |
/* Capacity */
|
alpar@1
|
133 |
} edge;
|
alpar@1
|
134 |
|
alpar@1
|
135 |
typedef struct NETWORK
|
alpar@1
|
136 |
{ struct NETWORK *next, *prev;
|
alpar@1
|
137 |
int vertnum;
|
alpar@1
|
138 |
int edgenum;
|
alpar@1
|
139 |
vertex *verts;
|
alpar@1
|
140 |
/* Vertex array[1..vertnum] */
|
alpar@1
|
141 |
edge *edges;
|
alpar@1
|
142 |
/* Edge array[1..edgenum] */
|
alpar@1
|
143 |
int source;
|
alpar@1
|
144 |
/* Pointer to the source */
|
alpar@1
|
145 |
int sink;
|
alpar@1
|
146 |
/* Pointer to the sink */
|
alpar@1
|
147 |
} network;
|
alpar@1
|
148 |
|
alpar@1
|
149 |
struct csa
|
alpar@1
|
150 |
{ /* common storage area */
|
alpar@1
|
151 |
glp_graph *G;
|
alpar@1
|
152 |
int *s, *t, a_cap;
|
alpar@1
|
153 |
RNG *rand;
|
alpar@1
|
154 |
network *N;
|
alpar@1
|
155 |
int *Parr;
|
alpar@1
|
156 |
int A, AA, C2AA, Ec;
|
alpar@1
|
157 |
};
|
alpar@1
|
158 |
|
alpar@1
|
159 |
#define G (csa->G)
|
alpar@1
|
160 |
#define s (csa->s)
|
alpar@1
|
161 |
#define t (csa->t)
|
alpar@1
|
162 |
#define a_cap (csa->a_cap)
|
alpar@1
|
163 |
#define N (csa->N)
|
alpar@1
|
164 |
#define Parr (csa->Parr)
|
alpar@1
|
165 |
#define A (csa->A)
|
alpar@1
|
166 |
#define AA (csa->AA)
|
alpar@1
|
167 |
#define C2AA (csa->C2AA)
|
alpar@1
|
168 |
#define Ec (csa->Ec)
|
alpar@1
|
169 |
|
alpar@1
|
170 |
#undef random
|
alpar@1
|
171 |
#define random(A) (int)(rng_unif_01(csa->rand) * (double)(A))
|
alpar@1
|
172 |
#define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A))
|
alpar@1
|
173 |
#define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1)
|
alpar@1
|
174 |
|
alpar@1
|
175 |
static void make_edge(struct csa *csa, int from, int to, int c1, int c2)
|
alpar@1
|
176 |
{ Ec++;
|
alpar@1
|
177 |
N->edges[Ec].from = from;
|
alpar@1
|
178 |
N->edges[Ec].to = to;
|
alpar@1
|
179 |
N->edges[Ec].cap = RANDOM(c1, c2);
|
alpar@1
|
180 |
return;
|
alpar@1
|
181 |
}
|
alpar@1
|
182 |
|
alpar@1
|
183 |
static void permute(struct csa *csa)
|
alpar@1
|
184 |
{ int i, j, tmp;
|
alpar@1
|
185 |
for (i = 1; i < AA; i++)
|
alpar@1
|
186 |
{ j = RANDOM(i, AA);
|
alpar@1
|
187 |
tmp = Parr[i];
|
alpar@1
|
188 |
Parr[i] = Parr[j];
|
alpar@1
|
189 |
Parr[j] = tmp;
|
alpar@1
|
190 |
}
|
alpar@1
|
191 |
return;
|
alpar@1
|
192 |
}
|
alpar@1
|
193 |
|
alpar@1
|
194 |
static void connect(struct csa *csa, int offset, int cv, int x1, int y1)
|
alpar@1
|
195 |
{ int cv1;
|
alpar@1
|
196 |
cv1 = offset + (x1 - 1) * A + y1;
|
alpar@1
|
197 |
Ec++;
|
alpar@1
|
198 |
N->edges[Ec].from = cv;
|
alpar@1
|
199 |
N->edges[Ec].to = cv1;
|
alpar@1
|
200 |
N->edges[Ec].cap = C2AA;
|
alpar@1
|
201 |
return;
|
alpar@1
|
202 |
}
|
alpar@1
|
203 |
|
alpar@1
|
204 |
static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2)
|
alpar@1
|
205 |
{ /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges
|
alpar@1
|
206 |
random_frame network:
|
alpar@1
|
207 |
Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */
|
alpar@1
|
208 |
int x, y, z, offset, cv;
|
alpar@1
|
209 |
A = a;
|
alpar@1
|
210 |
AA = a * a;
|
alpar@1
|
211 |
C2AA = c2 * AA;
|
alpar@1
|
212 |
Ec = 0;
|
alpar@1
|
213 |
N = (network *)xmalloc(sizeof(network));
|
alpar@1
|
214 |
N->vertnum = AA * b;
|
alpar@1
|
215 |
N->edgenum = 5 * AA * b - 4 * A * b - AA;
|
alpar@1
|
216 |
N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge));
|
alpar@1
|
217 |
N->source = 1;
|
alpar@1
|
218 |
N->sink = N->vertnum;
|
alpar@1
|
219 |
Parr = (int *)xcalloc(AA + 1, sizeof(int));
|
alpar@1
|
220 |
for (x = 1; x <= AA; x++)
|
alpar@1
|
221 |
Parr[x] = x;
|
alpar@1
|
222 |
for (z = 1; z <= b; z++)
|
alpar@1
|
223 |
{ offset = AA * (z - 1);
|
alpar@1
|
224 |
if (z != b)
|
alpar@1
|
225 |
permute(csa);
|
alpar@1
|
226 |
for (x = 1; x <= A; x++)
|
alpar@1
|
227 |
{ for (y = 1; y <= A; y++)
|
alpar@1
|
228 |
{ cv = offset + (x - 1) * A + y;
|
alpar@1
|
229 |
if (z != b)
|
alpar@1
|
230 |
make_edge(csa, cv, offset + AA + Parr[cv - offset],
|
alpar@1
|
231 |
c1, c2); /* the intermediate edges */
|
alpar@1
|
232 |
if (y < A)
|
alpar@1
|
233 |
connect(csa, offset, cv, x, y + 1);
|
alpar@1
|
234 |
if (y > 1)
|
alpar@1
|
235 |
connect(csa, offset, cv, x, y - 1);
|
alpar@1
|
236 |
if (x < A)
|
alpar@1
|
237 |
connect(csa, offset, cv, x + 1, y);
|
alpar@1
|
238 |
if (x > 1)
|
alpar@1
|
239 |
connect(csa, offset, cv, x - 1, y);
|
alpar@1
|
240 |
}
|
alpar@1
|
241 |
}
|
alpar@1
|
242 |
}
|
alpar@1
|
243 |
xfree(Parr);
|
alpar@1
|
244 |
return N;
|
alpar@1
|
245 |
}
|
alpar@1
|
246 |
|
alpar@1
|
247 |
static void print_max_format(struct csa *csa, network *n, char *comm[],
|
alpar@1
|
248 |
int dim)
|
alpar@1
|
249 |
{ /* prints a network heading with dim lines of comments (no \n
|
alpar@1
|
250 |
needs at the ends) */
|
alpar@1
|
251 |
int i, vnum, e_num;
|
alpar@1
|
252 |
edge *e;
|
alpar@1
|
253 |
vnum = n->vertnum;
|
alpar@1
|
254 |
e_num = n->edgenum;
|
alpar@1
|
255 |
if (G == NULL)
|
alpar@1
|
256 |
{ for (i = 0; i < dim; i++)
|
alpar@1
|
257 |
xprintf("c %s\n", comm[i]);
|
alpar@1
|
258 |
xprintf("p max %7d %10d\n", vnum, e_num);
|
alpar@1
|
259 |
xprintf("n %7d s\n", n->source);
|
alpar@1
|
260 |
xprintf("n %7d t\n", n->sink);
|
alpar@1
|
261 |
}
|
alpar@1
|
262 |
else
|
alpar@1
|
263 |
{ glp_add_vertices(G, vnum);
|
alpar@1
|
264 |
if (s != NULL) *s = n->source;
|
alpar@1
|
265 |
if (t != NULL) *t = n->sink;
|
alpar@1
|
266 |
}
|
alpar@1
|
267 |
for (i = 1; i <= e_num; i++)
|
alpar@1
|
268 |
{ e = &n->edges[i];
|
alpar@1
|
269 |
if (G == NULL)
|
alpar@1
|
270 |
xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap);
|
alpar@1
|
271 |
else
|
alpar@1
|
272 |
{ glp_arc *a = glp_add_arc(G, e->from, e->to);
|
alpar@1
|
273 |
if (a_cap >= 0)
|
alpar@1
|
274 |
{ double temp = (double)e->cap;
|
alpar@1
|
275 |
memcpy((char *)a->data + a_cap, &temp, sizeof(double));
|
alpar@1
|
276 |
}
|
alpar@1
|
277 |
}
|
alpar@1
|
278 |
}
|
alpar@1
|
279 |
return;
|
alpar@1
|
280 |
}
|
alpar@1
|
281 |
|
alpar@1
|
282 |
static void gen_free_net(network *n)
|
alpar@1
|
283 |
{ xfree(n->edges);
|
alpar@1
|
284 |
xfree(n);
|
alpar@1
|
285 |
return;
|
alpar@1
|
286 |
}
|
alpar@1
|
287 |
|
alpar@1
|
288 |
int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap,
|
alpar@1
|
289 |
const int parm[1+5])
|
alpar@1
|
290 |
{ struct csa _csa, *csa = &_csa;
|
alpar@1
|
291 |
network *n;
|
alpar@1
|
292 |
char comm[10][80], *com1[10];
|
alpar@1
|
293 |
int seed, a, b, c1, c2, ret;
|
alpar@1
|
294 |
G = G_;
|
alpar@1
|
295 |
s = _s;
|
alpar@1
|
296 |
t = _t;
|
alpar@1
|
297 |
a_cap = _a_cap;
|
alpar@1
|
298 |
if (G != NULL)
|
alpar@1
|
299 |
{ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
|
alpar@1
|
300 |
xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap);
|
alpar@1
|
301 |
}
|
alpar@1
|
302 |
seed = parm[1];
|
alpar@1
|
303 |
a = parm[2];
|
alpar@1
|
304 |
b = parm[3];
|
alpar@1
|
305 |
c1 = parm[4];
|
alpar@1
|
306 |
c2 = parm[5];
|
alpar@1
|
307 |
if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 &&
|
alpar@1
|
308 |
0 <= c1 && c1 <= c2 && c2 <= 1000))
|
alpar@1
|
309 |
{ ret = 1;
|
alpar@1
|
310 |
goto done;
|
alpar@1
|
311 |
}
|
alpar@1
|
312 |
if (G != NULL)
|
alpar@1
|
313 |
{ glp_erase_graph(G, G->v_size, G->a_size);
|
alpar@1
|
314 |
glp_set_graph_name(G, "RMFGEN");
|
alpar@1
|
315 |
}
|
alpar@1
|
316 |
csa->rand = rng_create_rand();
|
alpar@1
|
317 |
rng_init_rand(csa->rand, seed);
|
alpar@1
|
318 |
n = gen_rmf(csa, a, b, c1, c2);
|
alpar@1
|
319 |
sprintf(comm[0], "This file was generated by genrmf.");
|
alpar@1
|
320 |
sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d",
|
alpar@1
|
321 |
a, b, c1, c2);
|
alpar@1
|
322 |
com1[0] = comm[0];
|
alpar@1
|
323 |
com1[1] = comm[1];
|
alpar@1
|
324 |
print_max_format(csa, n, com1, 2);
|
alpar@1
|
325 |
gen_free_net(n);
|
alpar@1
|
326 |
rng_delete_rand(csa->rand);
|
alpar@1
|
327 |
ret = 0;
|
alpar@1
|
328 |
done: return ret;
|
alpar@1
|
329 |
}
|
alpar@1
|
330 |
|
alpar@1
|
331 |
/**********************************************************************/
|
alpar@1
|
332 |
|
alpar@1
|
333 |
#if 0
|
alpar@1
|
334 |
int main(int argc, char *argv[])
|
alpar@1
|
335 |
{ int seed, a, b, c1, c2, i, parm[1+5];
|
alpar@1
|
336 |
seed = 123;
|
alpar@1
|
337 |
a = b = c1 = c2 = -1;
|
alpar@1
|
338 |
for (i = 1; i < argc; i++)
|
alpar@1
|
339 |
{ if (strcmp(argv[i], "-seed") == 0)
|
alpar@1
|
340 |
seed = atoi(argv[++i]);
|
alpar@1
|
341 |
else if (strcmp(argv[i], "-a") == 0)
|
alpar@1
|
342 |
a = atoi(argv[++i]);
|
alpar@1
|
343 |
else if (strcmp(argv[i], "-b") == 0)
|
alpar@1
|
344 |
b = atoi(argv[++i]);
|
alpar@1
|
345 |
else if (strcmp(argv[i], "-c1") == 0)
|
alpar@1
|
346 |
c1 = atoi(argv[++i]);
|
alpar@1
|
347 |
else if (strcmp(argv[i], "-c2") == 0)
|
alpar@1
|
348 |
c2 = atoi(argv[++i]);
|
alpar@1
|
349 |
}
|
alpar@1
|
350 |
if (a < 0 || b < 0 || c1 < 0 || c2 < 0)
|
alpar@1
|
351 |
{ xprintf("Usage:\n");
|
alpar@1
|
352 |
xprintf("genrmf [-seed seed] -a frame_size -b depth\n");
|
alpar@1
|
353 |
xprintf(" -c1 cap_range1 -c2 cap_range2\n");
|
alpar@1
|
354 |
}
|
alpar@1
|
355 |
else
|
alpar@1
|
356 |
{ parm[1] = seed;
|
alpar@1
|
357 |
parm[2] = a;
|
alpar@1
|
358 |
parm[3] = b;
|
alpar@1
|
359 |
parm[4] = c1;
|
alpar@1
|
360 |
parm[5] = c2;
|
alpar@1
|
361 |
glp_rmfgen(NULL, NULL, NULL, 0, parm);
|
alpar@1
|
362 |
}
|
alpar@1
|
363 |
return 0;
|
alpar@1
|
364 |
}
|
alpar@1
|
365 |
#endif
|
alpar@1
|
366 |
|
alpar@1
|
367 |
/* eof */
|