23 |
|
/* number of children (-1 in child) */ |
24 |
|
static int nchild = 0; |
25 |
|
|
26 |
+ |
/* Create a new migration holder (sharing memory for multiprocessing) */ |
27 |
+ |
static MIGRATION * |
28 |
+ |
new_migration(RBFNODE *from_rbf, RBFNODE *to_rbf) |
29 |
+ |
{ |
30 |
+ |
size_t memlen = sizeof(MIGRATION) + |
31 |
+ |
sizeof(float)*(from_rbf->nrbf*to_rbf->nrbf - 1); |
32 |
+ |
MIGRATION *newmig; |
33 |
+ |
#ifdef _WIN32 |
34 |
+ |
if (nprocs > 1) |
35 |
+ |
fprintf(stderr, "%s: warning - multiprocessing not supported\n", |
36 |
+ |
progname); |
37 |
+ |
nprocs = 1; |
38 |
+ |
newmig = (MIGRATION *)malloc(memlen); |
39 |
+ |
#else |
40 |
+ |
if (nprocs <= 1) { /* single process? */ |
41 |
+ |
newmig = (MIGRATION *)malloc(memlen); |
42 |
+ |
} else { /* else need to share memory */ |
43 |
+ |
newmig = (MIGRATION *)mmap(NULL, memlen, PROT_READ|PROT_WRITE, |
44 |
+ |
MAP_ANON|MAP_SHARED, -1, 0); |
45 |
+ |
if ((void *)newmig == MAP_FAILED) |
46 |
+ |
newmig = NULL; |
47 |
+ |
} |
48 |
+ |
#endif |
49 |
+ |
if (newmig == NULL) { |
50 |
+ |
fprintf(stderr, "%s: cannot allocate new migration\n", progname); |
51 |
+ |
exit(1); |
52 |
+ |
} |
53 |
+ |
newmig->rbfv[0] = from_rbf; |
54 |
+ |
newmig->rbfv[1] = to_rbf; |
55 |
+ |
/* insert in edge lists */ |
56 |
+ |
newmig->enxt[0] = from_rbf->ejl; |
57 |
+ |
from_rbf->ejl = newmig; |
58 |
+ |
newmig->enxt[1] = to_rbf->ejl; |
59 |
+ |
to_rbf->ejl = newmig; |
60 |
+ |
newmig->next = mig_list; /* push onto global list */ |
61 |
+ |
return(mig_list = newmig); |
62 |
+ |
} |
63 |
+ |
|
64 |
+ |
#ifdef _WIN32 |
65 |
+ |
#define await_children(n) (void)(n) |
66 |
+ |
#define run_subprocess() 0 |
67 |
+ |
#define end_subprocess() (void)0 |
68 |
+ |
#else |
69 |
+ |
|
70 |
+ |
/* Wait for the specified number of child processes to complete */ |
71 |
+ |
static void |
72 |
+ |
await_children(int n) |
73 |
+ |
{ |
74 |
+ |
int exit_status = 0; |
75 |
+ |
|
76 |
+ |
if (n > nchild) |
77 |
+ |
n = nchild; |
78 |
+ |
while (n-- > 0) { |
79 |
+ |
int status; |
80 |
+ |
if (wait(&status) < 0) { |
81 |
+ |
fprintf(stderr, "%s: missing child(ren)!\n", progname); |
82 |
+ |
nchild = 0; |
83 |
+ |
break; |
84 |
+ |
} |
85 |
+ |
--nchild; |
86 |
+ |
if (status) { /* something wrong */ |
87 |
+ |
if ((status = WEXITSTATUS(status))) |
88 |
+ |
exit_status = status; |
89 |
+ |
else |
90 |
+ |
exit_status += !exit_status; |
91 |
+ |
fprintf(stderr, "%s: subprocess died\n", progname); |
92 |
+ |
n = nchild; /* wait for the rest */ |
93 |
+ |
} |
94 |
+ |
} |
95 |
+ |
if (exit_status) |
96 |
+ |
exit(exit_status); |
97 |
+ |
} |
98 |
+ |
|
99 |
+ |
/* Start child process if multiprocessing selected */ |
100 |
+ |
static pid_t |
101 |
+ |
run_subprocess(void) |
102 |
+ |
{ |
103 |
+ |
int status; |
104 |
+ |
pid_t pid; |
105 |
+ |
|
106 |
+ |
if (nprocs <= 1) /* any children requested? */ |
107 |
+ |
return(0); |
108 |
+ |
await_children(nchild + 1 - nprocs); /* free up child process */ |
109 |
+ |
if ((pid = fork())) { |
110 |
+ |
if (pid < 0) { |
111 |
+ |
fprintf(stderr, "%s: cannot fork subprocess\n", |
112 |
+ |
progname); |
113 |
+ |
exit(1); |
114 |
+ |
} |
115 |
+ |
++nchild; /* subprocess started */ |
116 |
+ |
return(pid); |
117 |
+ |
} |
118 |
+ |
nchild = -1; |
119 |
+ |
return(0); /* put child to work */ |
120 |
+ |
} |
121 |
+ |
|
122 |
+ |
/* If we are in subprocess, call exit */ |
123 |
+ |
#define end_subprocess() if (nchild < 0) _exit(0); else |
124 |
+ |
|
125 |
+ |
#endif /* ! _WIN32 */ |
126 |
+ |
|
127 |
|
/* Compute (and allocate) migration price matrix for optimization */ |
128 |
|
static float * |
129 |
|
price_routes(const RBFNODE *from_rbf, const RBFNODE *to_rbf) |
207 |
|
migration_step(MIGRATION *mig, double *src_rem, double *dst_rem, const float *pmtx) |
208 |
|
{ |
209 |
|
const double maxamt = .1; |
210 |
< |
const double minamt = maxamt*.0001; |
210 |
> |
const double minamt = maxamt*5e-6; |
211 |
|
static double *src_cost = NULL; |
212 |
|
static int n_alloc = 0; |
213 |
|
struct { |
237 |
|
for (cur.s = mtx_nrows(mig); cur.s--; ) { |
238 |
|
const float *price = pmtx + cur.s*mtx_ncols(mig); |
239 |
|
double cost_others = 0; |
240 |
< |
if (src_rem[cur.s] < minamt) |
240 |
> |
if (src_rem[cur.s] <= minamt) |
241 |
|
continue; |
242 |
|
cur.d = -1; /* examine cheapest dest. */ |
243 |
|
for (i = mtx_ncols(mig); i--; ) |
265 |
|
if ((best.s < 0) | (best.d < 0)) |
266 |
|
return(.0); |
267 |
|
/* make the actual move */ |
268 |
< |
mig->mtx[mtx_ndx(mig,best.s,best.d)] += best.amt; |
268 |
> |
mtx_coef(mig,best.s,best.d) += best.amt; |
269 |
|
src_rem[best.s] -= best.amt; |
270 |
|
dst_rem[best.d] -= best.amt; |
271 |
|
return(best.amt); |
286 |
|
} |
287 |
|
#endif |
288 |
|
|
188 |
– |
/* Create a new migration holder (sharing memory for multiprocessing) */ |
189 |
– |
static MIGRATION * |
190 |
– |
new_migration(RBFNODE *from_rbf, RBFNODE *to_rbf) |
191 |
– |
{ |
192 |
– |
size_t memlen = sizeof(MIGRATION) + |
193 |
– |
sizeof(float)*(from_rbf->nrbf*to_rbf->nrbf - 1); |
194 |
– |
MIGRATION *newmig; |
195 |
– |
#ifdef _WIN32 |
196 |
– |
if (nprocs > 1) |
197 |
– |
fprintf(stderr, "%s: warning - multiprocessing not supported\n", |
198 |
– |
progname); |
199 |
– |
nprocs = 1; |
200 |
– |
newmig = (MIGRATION *)malloc(memlen); |
201 |
– |
#else |
202 |
– |
if (nprocs <= 1) { /* single process? */ |
203 |
– |
newmig = (MIGRATION *)malloc(memlen); |
204 |
– |
} else { /* else need to share memory */ |
205 |
– |
newmig = (MIGRATION *)mmap(NULL, memlen, PROT_READ|PROT_WRITE, |
206 |
– |
MAP_ANON|MAP_SHARED, -1, 0); |
207 |
– |
if ((void *)newmig == MAP_FAILED) |
208 |
– |
newmig = NULL; |
209 |
– |
} |
210 |
– |
#endif |
211 |
– |
if (newmig == NULL) { |
212 |
– |
fprintf(stderr, "%s: cannot allocate new migration\n", progname); |
213 |
– |
exit(1); |
214 |
– |
} |
215 |
– |
newmig->rbfv[0] = from_rbf; |
216 |
– |
newmig->rbfv[1] = to_rbf; |
217 |
– |
/* insert in edge lists */ |
218 |
– |
newmig->enxt[0] = from_rbf->ejl; |
219 |
– |
from_rbf->ejl = newmig; |
220 |
– |
newmig->enxt[1] = to_rbf->ejl; |
221 |
– |
to_rbf->ejl = newmig; |
222 |
– |
newmig->next = mig_list; /* push onto global list */ |
223 |
– |
return(mig_list = newmig); |
224 |
– |
} |
225 |
– |
|
226 |
– |
#ifdef _WIN32 |
227 |
– |
#define await_children(n) (void)(n) |
228 |
– |
#define run_subprocess() 0 |
229 |
– |
#define end_subprocess() (void)0 |
230 |
– |
#else |
231 |
– |
|
232 |
– |
/* Wait for the specified number of child processes to complete */ |
233 |
– |
static void |
234 |
– |
await_children(int n) |
235 |
– |
{ |
236 |
– |
int exit_status = 0; |
237 |
– |
|
238 |
– |
if (n > nchild) |
239 |
– |
n = nchild; |
240 |
– |
while (n-- > 0) { |
241 |
– |
int status; |
242 |
– |
if (wait(&status) < 0) { |
243 |
– |
fprintf(stderr, "%s: missing child(ren)!\n", progname); |
244 |
– |
nchild = 0; |
245 |
– |
break; |
246 |
– |
} |
247 |
– |
--nchild; |
248 |
– |
if (status) { /* something wrong */ |
249 |
– |
if ((status = WEXITSTATUS(status))) |
250 |
– |
exit_status = status; |
251 |
– |
else |
252 |
– |
exit_status += !exit_status; |
253 |
– |
fprintf(stderr, "%s: subprocess died\n", progname); |
254 |
– |
n = nchild; /* wait for the rest */ |
255 |
– |
} |
256 |
– |
} |
257 |
– |
if (exit_status) |
258 |
– |
exit(exit_status); |
259 |
– |
} |
260 |
– |
|
261 |
– |
/* Start child process if multiprocessing selected */ |
262 |
– |
static pid_t |
263 |
– |
run_subprocess(void) |
264 |
– |
{ |
265 |
– |
int status; |
266 |
– |
pid_t pid; |
267 |
– |
|
268 |
– |
if (nprocs <= 1) /* any children requested? */ |
269 |
– |
return(0); |
270 |
– |
await_children(nchild + 1 - nprocs); /* free up child process */ |
271 |
– |
if ((pid = fork())) { |
272 |
– |
if (pid < 0) { |
273 |
– |
fprintf(stderr, "%s: cannot fork subprocess\n", |
274 |
– |
progname); |
275 |
– |
exit(1); |
276 |
– |
} |
277 |
– |
++nchild; /* subprocess started */ |
278 |
– |
return(pid); |
279 |
– |
} |
280 |
– |
nchild = -1; |
281 |
– |
return(0); /* put child to work */ |
282 |
– |
} |
283 |
– |
|
284 |
– |
/* If we are in subprocess, call exit */ |
285 |
– |
#define end_subprocess() if (nchild < 0) _exit(0); else |
286 |
– |
|
287 |
– |
#endif /* ! _WIN32 */ |
288 |
– |
|
289 |
|
/* Compute and insert migration along directed edge (may fork child) */ |
290 |
|
static MIGRATION * |
291 |
|
create_migration(RBFNODE *from_rbf, RBFNODE *to_rbf) |
292 |
|
{ |
293 |
< |
const double end_thresh = 0.1/(from_rbf->nrbf*to_rbf->nrbf); |
294 |
< |
const double check_thresh = 0.01; |
295 |
< |
const double rel_thresh = 5e-6; |
293 |
> |
const double end_thresh = 5e-6; |
294 |
|
float *pmtx; |
295 |
|
MIGRATION *newmig; |
296 |
|
double *src_rem, *dst_rem; |
316 |
|
#ifdef DEBUG |
317 |
|
fprintf(stderr, "Building path from (theta,phi) %s ", |
318 |
|
thetaphi(from_rbf->invec)); |
319 |
< |
fprintf(stderr, "to %s", thetaphi(to_rbf->invec)); |
320 |
< |
/* if (nchild) */ fputc('\n', stderr); |
319 |
> |
fprintf(stderr, "to %s with %d x %d matrix\n", |
320 |
> |
thetaphi(to_rbf->invec), |
321 |
> |
from_rbf->nrbf, to_rbf->nrbf); |
322 |
|
#endif |
323 |
|
/* starting quantities */ |
324 |
|
memset(newmig->mtx, 0, sizeof(float)*from_rbf->nrbf*to_rbf->nrbf); |
331 |
|
total_rem -= move_amt; |
332 |
|
#ifdef DEBUG |
333 |
|
if (!nchild) |
334 |
< |
/* fputc('.', stderr); */ |
336 |
< |
fprintf(stderr, "%.9f remaining...\r", total_rem); |
334 |
> |
fprintf(stderr, "\r%.9f remaining...", total_rem); |
335 |
|
#endif |
336 |
< |
} while (total_rem > end_thresh && (total_rem > check_thresh) | |
339 |
< |
(move_amt > rel_thresh*total_rem)); |
336 |
> |
} while ((total_rem > end_thresh) & (move_amt > 0)); |
337 |
|
#ifdef DEBUG |
338 |
< |
if (!nchild) fputs("\ndone.\n", stderr); |
338 |
> |
if (!nchild) fputs("done.\n", stderr); |
339 |
|
else fprintf(stderr, "finished with %.9f remaining\n", total_rem); |
340 |
|
#endif |
341 |
|
for (i = from_rbf->nrbf; i--; ) { /* normalize final matrix */ |
344 |
|
if (nf <= FTINY) continue; |
345 |
|
nf = from_rbf->vtotal / nf; |
346 |
|
for (j = to_rbf->nrbf; j--; ) |
347 |
< |
newmig->mtx[mtx_ndx(newmig,i,j)] *= nf; |
347 |
> |
mtx_coef(newmig,i,j) *= nf; |
348 |
|
} |
349 |
|
end_subprocess(); /* exit here if subprocess */ |
350 |
|
free(pmtx); /* free working arrays */ |