Bug #1267: Integrate METIS graph partitioning library
[charm.git] / src / libs / ck-libs / metis / programs / io.c
blob469681991e728479c0d930196938421da35558cf
1 /*
2 * Copyright 1997, Regents of the University of Minnesota
4 * io.c
6 * This file contains routines related to I/O
8 * Started 8/28/94
9 * George
11 * $Id: io.c 11932 2012-05-10 18:18:23Z dominique $
15 #include "metisbin.h"
19 /*************************************************************************/
20 /*! This function reads in a sparse graph */
21 /*************************************************************************/
22 graph_t *ReadGraph(params_t *params)
24 idx_t i, j, k, l, fmt, ncon, nfields, readew, readvw, readvs, edge, ewgt;
25 idx_t *xadj, *adjncy, *vwgt, *adjwgt, *vsize;
26 char *line=NULL, fmtstr[256], *curstr, *newstr;
27 size_t lnlen=0;
28 FILE *fpin;
29 graph_t *graph;
31 if (!gk_fexists(params->filename))
32 errexit("File %s does not exist!\n", params->filename);
34 graph = CreateGraph();
36 fpin = gk_fopen(params->filename, "r", "ReadGRaph: Graph");
38 /* Skip comment lines until you get to the first valid line */
39 do {
40 if (gk_getline(&line, &lnlen, fpin) == -1)
41 errexit("Premature end of input file: file: %s\n", params->filename);
42 } while (line[0] == '%');
45 fmt = ncon = 0;
46 nfields = sscanf(line, "%"SCIDX" %"SCIDX" %"SCIDX" %"SCIDX,
47 &(graph->nvtxs), &(graph->nedges), &fmt, &ncon);
49 if (nfields < 2)
50 errexit("The input file does not specify the number of vertices and edges.\n");
52 if (graph->nvtxs <= 0 || graph->nedges <= 0)
53 errexit("The supplied nvtxs:%"PRIDX" and nedges:%"PRIDX" must be positive.\n",
54 graph->nvtxs, graph->nedges);
56 if (fmt > 111)
57 errexit("Cannot read this type of file format [fmt=%"PRIDX"]!\n", fmt);
59 sprintf(fmtstr, "%03"PRIDX, fmt%1000);
60 readvs = (fmtstr[0] == '1');
61 readvw = (fmtstr[1] == '1');
62 readew = (fmtstr[2] == '1');
64 /*printf("%s %"PRIDX" %"PRIDX" %"PRIDX"\n", fmtstr, readvs, readvw, readew); */
67 if (ncon > 0 && !readvw)
68 errexit(
69 "------------------------------------------------------------------------------\n"
70 "*** I detected an error in your input file ***\n\n"
71 "You specified ncon=%"PRIDX", but the fmt parameter does not specify vertex weights\n"
72 "Make sure that the fmt parameter is set to either 10 or 11.\n"
73 "------------------------------------------------------------------------------\n", ncon);
75 graph->nedges *=2;
76 ncon = graph->ncon = (ncon == 0 ? 1 : ncon);
78 xadj = graph->xadj = ismalloc(graph->nvtxs+1, 0, "ReadGraph: xadj");
79 adjncy = graph->adjncy = imalloc(graph->nedges, "ReadGraph: adjncy");
80 vwgt = graph->vwgt = ismalloc(ncon*graph->nvtxs, 1, "ReadGraph: vwgt");
81 adjwgt = graph->adjwgt = ismalloc(graph->nedges, 1, "ReadGraph: adjwgt");
82 vsize = graph->vsize = ismalloc(graph->nvtxs, 1, "ReadGraph: vsize");
85 /*----------------------------------------------------------------------
86 * Read the sparse graph file
87 *---------------------------------------------------------------------*/
88 for (xadj[0]=0, k=0, i=0; i<graph->nvtxs; i++) {
89 do {
90 if (gk_getline(&line, &lnlen, fpin) == -1)
91 errexit("Premature end of input file while reading vertex %"PRIDX".\n", i+1);
92 } while (line[0] == '%');
94 curstr = line;
95 newstr = NULL;
97 /* Read vertex sizes */
98 if (readvs) {
99 vsize[i] = strtoidx(curstr, &newstr, 10);
100 if (newstr == curstr)
101 errexit("The line for vertex %"PRIDX" does not have vsize information\n", i+1);
102 if (vsize[i] < 0)
103 errexit("The size for vertex %"PRIDX" must be >= 0\n", i+1);
104 curstr = newstr;
108 /* Read vertex weights */
109 if (readvw) {
110 for (l=0; l<ncon; l++) {
111 vwgt[i*ncon+l] = strtoidx(curstr, &newstr, 10);
112 if (newstr == curstr)
113 errexit("The line for vertex %"PRIDX" does not have enough weights "
114 "for the %"PRIDX" constraints.\n", i+1, ncon);
115 if (vwgt[i*ncon+l] < 0)
116 errexit("The weight vertex %"PRIDX" and constraint %"PRIDX" must be >= 0\n", i+1, l);
117 curstr = newstr;
121 while (1) {
122 edge = strtoidx(curstr, &newstr, 10);
123 if (newstr == curstr)
124 break; /* End of line */
125 curstr = newstr;
127 if (edge < 1 || edge > graph->nvtxs)
128 errexit("Edge %"PRIDX" for vertex %"PRIDX" is out of bounds\n", edge, i+1);
130 ewgt = 1;
131 if (readew) {
132 ewgt = strtoidx(curstr, &newstr, 10);
133 if (newstr == curstr)
134 errexit("Premature end of line for vertex %"PRIDX"\n", i+1);
135 if (ewgt <= 0)
136 errexit("The weight (%"PRIDX") for edge (%"PRIDX", %"PRIDX") must be positive.\n",
137 ewgt, i+1, edge);
138 curstr = newstr;
141 if (k == graph->nedges)
142 errexit("There are more edges in the file than the %"PRIDX" specified.\n",
143 graph->nedges/2);
145 adjncy[k] = edge-1;
146 adjwgt[k] = ewgt;
147 k++;
149 xadj[i+1] = k;
151 gk_fclose(fpin);
153 if (k != graph->nedges) {
154 printf("------------------------------------------------------------------------------\n");
155 printf("*** I detected an error in your input file ***\n\n");
156 printf("In the first line of the file, you specified that the graph contained\n"
157 "%"PRIDX" edges. However, I only found %"PRIDX" edges in the file.\n",
158 graph->nedges/2, k/2);
159 if (2*k == graph->nedges) {
160 printf("\n *> I detected that you specified twice the number of edges that you have in\n");
161 printf(" the file. Remember that the number of edges specified in the first line\n");
162 printf(" counts each edge between vertices v and u only once.\n\n");
164 printf("Please specify the correct number of edges in the first line of the file.\n");
165 printf("------------------------------------------------------------------------------\n");
166 exit(0);
169 gk_free((void *)&line, LTERM);
171 return graph;
175 /*************************************************************************/
176 /*! This function reads in a mesh */
177 /*************************************************************************/
178 mesh_t *ReadMesh(params_t *params)
180 idx_t i, j, k, l, nfields, ncon, node;
181 idx_t *eptr, *eind, *ewgt;
182 size_t nlines, ntokens;
183 char *line=NULL, *curstr, *newstr;
184 size_t lnlen=0;
185 FILE *fpin;
186 mesh_t *mesh;
188 if (!gk_fexists(params->filename))
189 errexit("File %s does not exist!\n", params->filename);
191 mesh = CreateMesh();
193 /* get some file stats */
194 gk_getfilestats(params->filename, &nlines, &ntokens, NULL, NULL);
196 fpin = gk_fopen(params->filename, "r", __func__);
198 /* Skip comment lines until you get to the first valid line */
199 do {
200 if (gk_getline(&line, &lnlen, fpin) == -1)
201 errexit("Premature end of input file: file: %s\n", params->filename);
202 } while (line[0] == '%');
205 mesh->ncon = 0;
206 nfields = sscanf(line, "%"SCIDX" %"SCIDX, &(mesh->ne), &(mesh->ncon));
208 if (nfields < 1)
209 errexit("The input file does not specify the number of elements.\n");
211 if (mesh->ne <= 0)
212 errexit("The supplied number of elements:%"PRIDX" must be positive.\n", mesh->ne);
214 if (mesh->ne > nlines)
215 errexit("The file has %zu lines which smaller than the number of "
216 "elements of %"PRIDX" specified in the header line.\n", nlines, mesh->ne);
218 ncon = mesh->ncon;
219 eptr = mesh->eptr = ismalloc(mesh->ne+1, 0, "ReadMesh: eptr");
220 eind = mesh->eind = imalloc(ntokens, "ReadMesh: eind");
221 ewgt = mesh->ewgt = ismalloc((ncon == 0 ? 1 : ncon)*mesh->ne, 1, "ReadMesh: ewgt");
224 /*----------------------------------------------------------------------
225 * Read the mesh file
226 *---------------------------------------------------------------------*/
227 for (eptr[0]=0, k=0, i=0; i<mesh->ne; i++) {
228 do {
229 if (gk_getline(&line, &lnlen, fpin) == -1)
230 errexit("Premature end of input file while reading element %"PRIDX".\n", i+1);
231 } while (line[0] == '%');
233 curstr = line;
234 newstr = NULL;
236 /* Read element weights */
237 for (l=0; l<ncon; l++) {
238 ewgt[i*ncon+l] = strtoidx(curstr, &newstr, 10);
239 if (newstr == curstr)
240 errexit("The line for vertex %"PRIDX" does not have enough weights "
241 "for the %"PRIDX" constraints.\n", i+1, ncon);
242 if (ewgt[i*ncon+l] < 0)
243 errexit("The weight for element %"PRIDX" and constraint %"PRIDX" must be >= 0\n", i+1, l);
244 curstr = newstr;
247 while (1) {
248 node = strtoidx(curstr, &newstr, 10);
249 if (newstr == curstr)
250 break; /* End of line */
251 curstr = newstr;
253 if (node < 1)
254 errexit("Node %"PRIDX" for element %"PRIDX" is out of bounds\n", node, i+1);
256 eind[k++] = node-1;
258 eptr[i+1] = k;
260 gk_fclose(fpin);
262 mesh->ncon = (ncon == 0 ? 1 : ncon);
263 mesh->nn = imax(eptr[mesh->ne], eind)+1;
265 gk_free((void *)&line, LTERM);
267 return mesh;
271 /*************************************************************************/
272 /*! This function reads in the target partition weights. If no file is
273 specified the weights are set to 1/nparts */
274 /*************************************************************************/
275 void ReadTPwgts(params_t *params, idx_t ncon)
277 idx_t i, j, from, to, fromcnum, tocnum, nleft;
278 real_t awgt=0.0, twgt;
279 char *line=NULL, *curstr, *newstr;
280 size_t lnlen=0;
281 FILE *fpin;
283 params->tpwgts = rsmalloc(params->nparts*ncon, -1.0, "ReadTPwgts: tpwgts");
285 if (params->tpwgtsfile == NULL) {
286 for (i=0; i<params->nparts; i++) {
287 for (j=0; j<ncon; j++)
288 params->tpwgts[i*ncon+j] = 1.0/params->nparts;
290 return;
293 if (!gk_fexists(params->tpwgtsfile))
294 errexit("Graph file %s does not exist!\n", params->tpwgtsfile);
296 fpin = gk_fopen(params->tpwgtsfile, "r", "ReadTPwgts: tpwgtsfile");
298 while (gk_getline(&line, &lnlen, fpin) != -1) {
299 gk_strchr_replace(line, " ", "");
300 /* start extracting the fields */
302 curstr = line;
303 newstr = NULL;
305 from = strtoidx(curstr, &newstr, 10);
306 if (newstr == curstr)
307 errexit("The 'from' component of line <%s> in the tpwgts file is incorrect.\n", line);
308 curstr = newstr;
310 if (curstr[0] == '-') {
311 to = strtoidx(curstr+1, &newstr, 10);
312 if (newstr == curstr)
313 errexit("The 'to' component of line <%s> in the tpwgts file is incorrect.\n", line);
314 curstr = newstr;
316 else {
317 to = from;
320 if (curstr[0] == ':') {
321 fromcnum = strtoidx(curstr+1, &newstr, 10);
322 if (newstr == curstr)
323 errexit("The 'fromcnum' component of line <%s> in the tpwgts file is incorrect.\n", line);
324 curstr = newstr;
326 if (curstr[0] == '-') {
327 tocnum = strtoidx(curstr+1, &newstr, 10);
328 if (newstr == curstr)
329 errexit("The 'tocnum' component of line <%s> in the tpwgts file is incorrect.\n", line);
330 curstr = newstr;
332 else {
333 tocnum = fromcnum;
336 else {
337 fromcnum = 0;
338 tocnum = ncon-1;
341 if (curstr[0] == '=') {
342 awgt = strtoreal(curstr+1, &newstr);
343 if (newstr == curstr)
344 errexit("The 'wgt' component of line <%s> in the tpwgts file is incorrect.\n", line);
345 curstr = newstr;
347 else {
348 errexit("The 'wgt' component of line <%s> in the tpwgts file is missing.\n", line);
351 /*printf("Read: %"PRIDX"-%"PRIDX":%"PRIDX"-%"PRIDX"=%"PRREAL"\n",
352 from, to, fromcnum, tocnum, awgt);*/
354 if (from < 0 || to < 0 || from >= params->nparts || to >= params->nparts)
355 errexit("Invalid partition range for %"PRIDX":%"PRIDX"\n", from, to);
356 if (fromcnum < 0 || tocnum < 0 || fromcnum >= ncon || tocnum >= ncon)
357 errexit("Invalid constraint number range for %"PRIDX":%"PRIDX"\n",
358 fromcnum, tocnum);
359 if (awgt <= 0.0 || awgt >= 1.0)
360 errexit("Invalid partition weight of %"PRREAL"\n", awgt);
361 for (i=from; i<=to; i++) {
362 for (j=fromcnum; j<=tocnum; j++)
363 params->tpwgts[i*ncon+j] = awgt;
367 gk_fclose(fpin);
369 /* Assign weight to the unspecified constraints x partitions */
370 for (j=0; j<ncon; j++) {
371 /* Sum up the specified weights for the jth constraint */
372 for (twgt=0.0, nleft=params->nparts, i=0; i<params->nparts; i++) {
373 if (params->tpwgts[i*ncon+j] > 0) {
374 twgt += params->tpwgts[i*ncon+j];
375 nleft--;
379 /* Rescale the weights to be on the safe side */
380 if (nleft == 0)
381 rscale(params->nparts, 1.0/twgt, params->tpwgts+j, ncon);
383 /* Assign the left-over weight to the remaining partitions */
384 if (nleft > 0) {
385 if (twgt > 1)
386 errexit("The total specified target partition weights for constraint #%"PRIDX
387 " of %"PRREAL" exceeds 1.0.\n", j, twgt);
389 awgt = (1.0 - twgt)/nleft;
390 for (i=0; i<params->nparts; i++)
391 params->tpwgts[i*ncon+j] =
392 (params->tpwgts[i*ncon+j] < 0 ? awgt : params->tpwgts[i*ncon+j]);
395 #ifdef HAVE_GETLINE
396 free(line);
397 line = NULL; /* set to null to match behavior of gk_free() */
398 #else
399 gk_free((void *)&line, LTERM);
400 #endif
404 /*************************************************************************/
405 /*! This function reads in a partition/ordering vector */
406 /**************************************************************************/
407 void ReadPOVector(graph_t *graph, char *filename, idx_t *vector)
409 idx_t i;
410 FILE *fpin;
412 fpin = gk_fopen(filename, "r", __func__);
413 for (i=0; i<graph->nvtxs; i++) {
414 if (fscanf(fpin, "%"SCIDX"\n", vector+i) != 1)
415 errexit("[%s] Premature end of file %s at line %d [nvtxs: %d]\n",
416 __func__, filename, i, graph->nvtxs);
418 gk_fclose(fpin);
422 /*************************************************************************/
423 /*! This function writes out the partition vector */
424 /*************************************************************************/
425 void WritePartition(char *fname, idx_t *part, idx_t n, idx_t nparts)
427 FILE *fpout;
428 idx_t i;
429 char filename[MAXLINE];
431 sprintf(filename, "%s.part.%"PRIDX, fname, nparts);
433 fpout = gk_fopen(filename, "w", __func__);
435 for (i=0; i<n; i++)
436 fprintf(fpout,"%" PRIDX "\n", part[i]);
438 gk_fclose(fpout);
442 /*************************************************************************/
443 /*! This function writes out the partition vectors for a mesh */
444 /*************************************************************************/
445 void WriteMeshPartition(char *fname, idx_t nparts, idx_t ne, idx_t *epart,
446 idx_t nn, idx_t *npart)
448 FILE *fpout;
449 idx_t i;
450 char filename[256];
452 sprintf(filename,"%s.epart.%"PRIDX,fname, nparts);
454 fpout = gk_fopen(filename, "w", __func__);
456 for (i=0; i<ne; i++)
457 fprintf(fpout,"%" PRIDX "\n", epart[i]);
459 gk_fclose(fpout);
462 sprintf(filename,"%s.npart.%"PRIDX,fname, nparts);
464 fpout = gk_fopen(filename, "w", __func__);
466 for (i=0; i<nn; i++)
467 fprintf(fpout, "%" PRIDX "\n", npart[i]);
469 gk_fclose(fpout);
474 /*************************************************************************/
475 /*! This function writes out the permutation vector */
476 /*************************************************************************/
477 void WritePermutation(char *fname, idx_t *iperm, idx_t n)
479 FILE *fpout;
480 idx_t i;
481 char filename[MAXLINE];
483 sprintf(filename, "%s.iperm", fname);
485 fpout = gk_fopen(filename, "w", __func__);
487 for (i=0; i<n; i++)
488 fprintf(fpout, "%" PRIDX "\n", iperm[i]);
490 gk_fclose(fpout);
494 /*************************************************************************/
495 /*! This function writes a graph into a file */
496 /*************************************************************************/
497 void WriteGraph(graph_t *graph, char *filename)
499 idx_t i, j, nvtxs, ncon;
500 idx_t *xadj, *adjncy, *adjwgt, *vwgt, *vsize;
501 int hasvwgt=0, hasewgt=0, hasvsize=0;
502 FILE *fpout;
504 nvtxs = graph->nvtxs;
505 ncon = graph->ncon;
506 xadj = graph->xadj;
507 adjncy = graph->adjncy;
508 vwgt = graph->vwgt;
509 vsize = graph->vsize;
510 adjwgt = graph->adjwgt;
512 /* determine if the graph has non-unity vwgt, vsize, or adjwgt */
513 if (vwgt) {
514 for (i=0; i<nvtxs*ncon; i++) {
515 if (vwgt[i] != 1) {
516 hasvwgt = 1;
517 break;
521 if (vsize) {
522 for (i=0; i<nvtxs; i++) {
523 if (vsize[i] != 1) {
524 hasvsize = 1;
525 break;
529 if (adjwgt) {
530 for (i=0; i<xadj[nvtxs]; i++) {
531 if (adjwgt[i] != 1) {
532 hasewgt = 1;
533 break;
538 fpout = gk_fopen(filename, "w", __func__);
540 /* write the header line */
541 fprintf(fpout, "%"PRIDX" %"PRIDX, nvtxs, xadj[nvtxs]/2);
542 if (hasvwgt || hasvsize || hasewgt) {
543 fprintf(fpout, " %d%d%d", hasvsize, hasvwgt, hasewgt);
544 if (hasvwgt)
545 fprintf(fpout, " %d", (int)graph->ncon);
549 /* write the rest of the graph */
550 for (i=0; i<nvtxs; i++) {
551 fprintf(fpout, "\n");
552 if (hasvsize)
553 fprintf(fpout, " %"PRIDX, vsize[i]);
555 if (hasvwgt) {
556 for (j=0; j<ncon; j++)
557 fprintf(fpout, " %"PRIDX, vwgt[i*ncon+j]);
560 for (j=xadj[i]; j<xadj[i+1]; j++) {
561 fprintf(fpout, " %"PRIDX, adjncy[j]+1);
562 if (hasewgt)
563 fprintf(fpout, " %"PRIDX, adjwgt[j]);
567 gk_fclose(fpout);