Cloned library METIS with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

568 lines
17 KiB

/*
* Copyright 1997, Regents of the University of Minnesota
*
* io.c
*
* This file contains routines related to I/O
*
* Started 8/28/94
* George
*
* $Id: io.c 17513 2014-08-05 16:20:50Z dominique $
*
*/
#include "metisbin.h"
/*************************************************************************/
/*! This function reads in a sparse graph */
/*************************************************************************/
graph_t *ReadGraph(params_t *params)
{
idx_t i, j, k, l, fmt, ncon, nfields, readew, readvw, readvs, edge, ewgt;
idx_t *xadj, *adjncy, *vwgt, *adjwgt, *vsize;
char *line=NULL, fmtstr[256], *curstr, *newstr;
size_t lnlen=0;
FILE *fpin;
graph_t *graph;
if (!gk_fexists(params->filename))
errexit("File %s does not exist!\n", params->filename);
graph = CreateGraph();
fpin = gk_fopen(params->filename, "r", "ReadGRaph: Graph");
/* Skip comment lines until you get to the first valid line */
do {
if (gk_getline(&line, &lnlen, fpin) == -1)
errexit("Premature end of input file: file: %s\n", params->filename);
} while (line[0] == '%');
fmt = ncon = 0;
nfields = sscanf(line, "%"SCIDX" %"SCIDX" %"SCIDX" %"SCIDX,
&(graph->nvtxs), &(graph->nedges), &fmt, &ncon);
if (nfields < 2)
errexit("The input file does not specify the number of vertices and edges.\n");
if (graph->nvtxs <= 0 || graph->nedges <= 0)
errexit("The supplied nvtxs:%"PRIDX" and nedges:%"PRIDX" must be positive.\n",
graph->nvtxs, graph->nedges);
if (fmt > 111)
errexit("Cannot read this type of file format [fmt=%"PRIDX"]!\n", fmt);
sprintf(fmtstr, "%03"PRIDX, fmt%1000);
readvs = (fmtstr[0] == '1');
readvw = (fmtstr[1] == '1');
readew = (fmtstr[2] == '1');
/*printf("%s %"PRIDX" %"PRIDX" %"PRIDX"\n", fmtstr, readvs, readvw, readew); */
if (ncon > 0 && !readvw)
errexit(
"------------------------------------------------------------------------------\n"
"*** I detected an error in your input file ***\n\n"
"You specified ncon=%"PRIDX", but the fmt parameter does not specify vertex weights\n"
"Make sure that the fmt parameter is set to either 10 or 11.\n"
"------------------------------------------------------------------------------\n", ncon);
graph->nedges *=2;
ncon = graph->ncon = (ncon == 0 ? 1 : ncon);
xadj = graph->xadj = ismalloc(graph->nvtxs+1, 0, "ReadGraph: xadj");
adjncy = graph->adjncy = imalloc(graph->nedges, "ReadGraph: adjncy");
vwgt = graph->vwgt = ismalloc(ncon*graph->nvtxs, 1, "ReadGraph: vwgt");
adjwgt = graph->adjwgt = (readew ? imalloc(graph->nedges, "ReadGraph: adjwgt") : NULL);
vsize = graph->vsize = ismalloc(graph->nvtxs, 1, "ReadGraph: vsize");
/*----------------------------------------------------------------------
* Read the sparse graph file
*---------------------------------------------------------------------*/
for (xadj[0]=0, k=0, i=0; i<graph->nvtxs; i++) {
do {
if (gk_getline(&line, &lnlen, fpin) == -1)
errexit("Premature end of input file while reading vertex %"PRIDX".\n", i+1);
} while (line[0] == '%');
curstr = line;
newstr = NULL;
/* Read vertex sizes */
if (readvs) {
vsize[i] = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
errexit("The line for vertex %"PRIDX" does not have vsize information\n", i+1);
if (vsize[i] < 0)
errexit("The size for vertex %"PRIDX" must be >= 0\n", i+1);
curstr = newstr;
}
/* Read vertex weights */
if (readvw) {
for (l=0; l<ncon; l++) {
vwgt[i*ncon+l] = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
errexit("The line for vertex %"PRIDX" does not have enough weights "
"for the %"PRIDX" constraints.\n", i+1, ncon);
if (vwgt[i*ncon+l] < 0)
errexit("The weight vertex %"PRIDX" and constraint %"PRIDX" must be >= 0\n", i+1, l);
curstr = newstr;
}
}
while (1) {
edge = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
break; /* End of line */
curstr = newstr;
if (edge < 1 || edge > graph->nvtxs)
errexit("Edge %"PRIDX" for vertex %"PRIDX" is out of bounds\n", edge, i+1);
ewgt = 1;
if (readew) {
ewgt = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
errexit("Premature end of line for vertex %"PRIDX"\n", i+1);
if (ewgt <= 0)
errexit("The weight (%"PRIDX") for edge (%"PRIDX", %"PRIDX") must be positive.\n",
ewgt, i+1, edge);
curstr = newstr;
}
if (k == graph->nedges)
errexit("There are more edges in the file than the %"PRIDX" specified.\n",
graph->nedges/2);
adjncy[k] = edge-1;
if (readew) adjwgt[k] = ewgt;
k++;
}
xadj[i+1] = k;
}
gk_fclose(fpin);
if (k != graph->nedges) {
printf("------------------------------------------------------------------------------\n");
printf("*** I detected an error in your input file ***\n\n");
printf("In the first line of the file, you specified that the graph contained\n"
"%"PRIDX" edges. However, I only found %"PRIDX" edges in the file.\n",
graph->nedges/2, k/2);
if (2*k == graph->nedges) {
printf("\n *> I detected that you specified twice the number of edges that you have in\n");
printf(" the file. Remember that the number of edges specified in the first line\n");
printf(" counts each edge between vertices v and u only once.\n\n");
}
printf("Please specify the correct number of edges in the first line of the file.\n");
printf("------------------------------------------------------------------------------\n");
exit(0);
}
gk_free((void *)&line, LTERM);
return graph;
}
/*************************************************************************/
/*! This function reads in a mesh */
/*************************************************************************/
mesh_t *ReadMesh(params_t *params)
{
idx_t i, j, k, l, nfields, ncon, node;
idx_t *eptr, *eind, *ewgt;
size_t nlines, ntokens;
char *line=NULL, *curstr, *newstr;
size_t lnlen=0;
FILE *fpin;
mesh_t *mesh;
if (!gk_fexists(params->filename))
errexit("File %s does not exist!\n", params->filename);
mesh = CreateMesh();
/* get some file stats */
gk_getfilestats(params->filename, &nlines, &ntokens, NULL, NULL);
fpin = gk_fopen(params->filename, "r", __func__);
/* Skip comment lines until you get to the first valid line */
do {
if (gk_getline(&line, &lnlen, fpin) == -1)
errexit("Premature end of input file: file: %s\n", params->filename);
} while (line[0] == '%');
mesh->ncon = 0;
nfields = sscanf(line, "%"SCIDX" %"SCIDX, &(mesh->ne), &(mesh->ncon));
if (nfields < 1)
errexit("The input file does not specify the number of elements.\n");
if (mesh->ne <= 0)
errexit("The supplied number of elements:%"PRIDX" must be positive.\n", mesh->ne);
if (mesh->ne > nlines)
errexit("The file has %zu lines which smaller than the number of "
"elements of %"PRIDX" specified in the header line.\n", nlines, mesh->ne);
ncon = mesh->ncon;
eptr = mesh->eptr = ismalloc(mesh->ne+1, 0, "ReadMesh: eptr");
eind = mesh->eind = imalloc(ntokens, "ReadMesh: eind");
ewgt = mesh->ewgt = ismalloc((ncon == 0 ? 1 : ncon)*mesh->ne, 1, "ReadMesh: ewgt");
/*----------------------------------------------------------------------
* Read the mesh file
*---------------------------------------------------------------------*/
for (eptr[0]=0, k=0, i=0; i<mesh->ne; i++) {
do {
if (gk_getline(&line, &lnlen, fpin) == -1)
errexit("Premature end of input file while reading element %"PRIDX".\n", i+1);
} while (line[0] == '%');
curstr = line;
newstr = NULL;
/* Read element weights */
for (l=0; l<ncon; l++) {
ewgt[i*ncon+l] = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
errexit("The line for vertex %"PRIDX" does not have enough weights "
"for the %"PRIDX" constraints.\n", i+1, ncon);
if (ewgt[i*ncon+l] < 0)
errexit("The weight for element %"PRIDX" and constraint %"PRIDX" must be >= 0\n", i+1, l);
curstr = newstr;
}
while (1) {
node = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
break; /* End of line */
curstr = newstr;
if (node < 1)
errexit("Node %"PRIDX" for element %"PRIDX" is out of bounds\n", node, i+1);
eind[k++] = node-1;
}
eptr[i+1] = k;
}
gk_fclose(fpin);
mesh->ncon = (ncon == 0 ? 1 : ncon);
mesh->nn = imax(eptr[mesh->ne], eind, 1)+1;
gk_free((void *)&line, LTERM);
return mesh;
}
/*************************************************************************/
/*! This function reads in the target partition weights. If no file is
specified the weights are set to 1/nparts */
/*************************************************************************/
void ReadTPwgts(params_t *params, idx_t ncon)
{
idx_t i, j, from, to, fromcnum, tocnum, nleft;
real_t awgt=0.0, twgt;
char *line=NULL, *curstr, *newstr;
size_t lnlen=0;
FILE *fpin;
params->tpwgts = rsmalloc(params->nparts*ncon, -1.0, "ReadTPwgts: tpwgts");
if (params->tpwgtsfile == NULL) {
for (i=0; i<params->nparts; i++) {
for (j=0; j<ncon; j++)
params->tpwgts[i*ncon+j] = 1.0/params->nparts;
}
return;
}
if (!gk_fexists(params->tpwgtsfile))
errexit("Graph file %s does not exist!\n", params->tpwgtsfile);
fpin = gk_fopen(params->tpwgtsfile, "r", "ReadTPwgts: tpwgtsfile");
while (gk_getline(&line, &lnlen, fpin) != -1) {
gk_strchr_replace(line, " ", "");
/* start extracting the fields */
curstr = line;
newstr = NULL;
from = strtoidx(curstr, &newstr, 10);
if (newstr == curstr)
errexit("The 'from' component of line <%s> in the tpwgts file is incorrect.\n", line);
curstr = newstr;
if (curstr[0] == '-') {
to = strtoidx(curstr+1, &newstr, 10);
if (newstr == curstr)
errexit("The 'to' component of line <%s> in the tpwgts file is incorrect.\n", line);
curstr = newstr;
}
else {
to = from;
}
if (curstr[0] == ':') {
fromcnum = strtoidx(curstr+1, &newstr, 10);
if (newstr == curstr)
errexit("The 'fromcnum' component of line <%s> in the tpwgts file is incorrect.\n", line);
curstr = newstr;
if (curstr[0] == '-') {
tocnum = strtoidx(curstr+1, &newstr, 10);
if (newstr == curstr)
errexit("The 'tocnum' component of line <%s> in the tpwgts file is incorrect.\n", line);
curstr = newstr;
}
else {
tocnum = fromcnum;
}
}
else {
fromcnum = 0;
tocnum = ncon-1;
}
if (curstr[0] == '=') {
awgt = strtoreal(curstr+1, &newstr);
if (newstr == curstr)
errexit("The 'wgt' component of line <%s> in the tpwgts file is incorrect.\n", line);
curstr = newstr;
}
else {
errexit("The 'wgt' component of line <%s> in the tpwgts file is missing.\n", line);
}
/*printf("Read: %"PRIDX"-%"PRIDX":%"PRIDX"-%"PRIDX"=%"PRREAL"\n",
from, to, fromcnum, tocnum, awgt);*/
if (from < 0 || to < 0 || from >= params->nparts || to >= params->nparts)
errexit("Invalid partition range for %"PRIDX":%"PRIDX"\n", from, to);
if (fromcnum < 0 || tocnum < 0 || fromcnum >= ncon || tocnum >= ncon)
errexit("Invalid constraint number range for %"PRIDX":%"PRIDX"\n",
fromcnum, tocnum);
if (awgt <= 0.0 || awgt >= 1.0)
errexit("Invalid partition weight of %"PRREAL"\n", awgt);
for (i=from; i<=to; i++) {
for (j=fromcnum; j<=tocnum; j++)
params->tpwgts[i*ncon+j] = awgt;
}
}
gk_fclose(fpin);
/* Assign weight to the unspecified constraints x partitions */
for (j=0; j<ncon; j++) {
/* Sum up the specified weights for the jth constraint */
for (twgt=0.0, nleft=params->nparts, i=0; i<params->nparts; i++) {
if (params->tpwgts[i*ncon+j] > 0) {
twgt += params->tpwgts[i*ncon+j];
nleft--;
}
}
/* Rescale the weights to be on the safe side */
if (nleft == 0)
rscale(params->nparts, 1.0/twgt, params->tpwgts+j, ncon);
/* Assign the left-over weight to the remaining partitions */
if (nleft > 0) {
if (twgt > 1)
errexit("The total specified target partition weights for constraint #%"PRIDX
" of %"PRREAL" exceeds 1.0.\n", j, twgt);
awgt = (1.0 - twgt)/nleft;
for (i=0; i<params->nparts; i++)
params->tpwgts[i*ncon+j] =
(params->tpwgts[i*ncon+j] < 0 ? awgt : params->tpwgts[i*ncon+j]);
}
}
#ifdef HAVE_GETLINE
free(line);
line = NULL; /* set to null to match behavior of gk_free() */
#else
gk_free((void *)&line, LTERM);
#endif
}
/*************************************************************************/
/*! This function reads in a partition/ordering vector */
/**************************************************************************/
void ReadPOVector(graph_t *graph, char *filename, idx_t *vector)
{
idx_t i;
FILE *fpin;
fpin = gk_fopen(filename, "r", __func__);
for (i=0; i<graph->nvtxs; i++) {
if (fscanf(fpin, "%"SCIDX"\n", vector+i) != 1)
errexit("[%s] Premature end of file %s at line %d [nvtxs: %d]\n",
__func__, filename, i, graph->nvtxs);
}
gk_fclose(fpin);
}
/*************************************************************************/
/*! This function writes out the partition vector */
/*************************************************************************/
void WritePartition(char *fname, idx_t *part, idx_t n, idx_t nparts)
{
FILE *fpout;
idx_t i;
char filename[MAXLINE];
sprintf(filename, "%s.part.%"PRIDX, fname, nparts);
fpout = gk_fopen(filename, "w", __func__);
for (i=0; i<n; i++)
fprintf(fpout,"%" PRIDX "\n", part[i]);
gk_fclose(fpout);
}
/*************************************************************************/
/*! This function writes out the partition vectors for a mesh */
/*************************************************************************/
void WriteMeshPartition(char *fname, idx_t nparts, idx_t ne, idx_t *epart,
idx_t nn, idx_t *npart)
{
FILE *fpout;
idx_t i;
char filename[256];
sprintf(filename,"%s.epart.%"PRIDX,fname, nparts);
fpout = gk_fopen(filename, "w", __func__);
for (i=0; i<ne; i++)
fprintf(fpout,"%" PRIDX "\n", epart[i]);
gk_fclose(fpout);
sprintf(filename,"%s.npart.%"PRIDX,fname, nparts);
fpout = gk_fopen(filename, "w", __func__);
for (i=0; i<nn; i++)
fprintf(fpout, "%" PRIDX "\n", npart[i]);
gk_fclose(fpout);
}
/*************************************************************************/
/*! This function writes out the permutation vector */
/*************************************************************************/
void WritePermutation(char *fname, idx_t *iperm, idx_t n)
{
FILE *fpout;
idx_t i;
char filename[MAXLINE];
sprintf(filename, "%s.iperm", fname);
fpout = gk_fopen(filename, "w", __func__);
for (i=0; i<n; i++)
fprintf(fpout, "%" PRIDX "\n", iperm[i]);
gk_fclose(fpout);
}
/*************************************************************************/
/*! This function writes a graph into a file */
/*************************************************************************/
void WriteGraph(graph_t *graph, char *filename)
{
idx_t i, j, nvtxs, ncon;
idx_t *xadj, *adjncy, *adjwgt, *vwgt, *vsize;
int hasvwgt=0, hasewgt=0, hasvsize=0;
FILE *fpout;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
vwgt = graph->vwgt;
vsize = graph->vsize;
adjwgt = graph->adjwgt;
/* determine if the graph has non-unity vwgt, vsize, or adjwgt */
if (vwgt) {
for (i=0; i<nvtxs*ncon; i++) {
if (vwgt[i] != 1) {
hasvwgt = 1;
break;
}
}
}
if (vsize) {
for (i=0; i<nvtxs; i++) {
if (vsize[i] != 1) {
hasvsize = 1;
break;
}
}
}
if (adjwgt) {
for (i=0; i<xadj[nvtxs]; i++) {
if (adjwgt[i] != 1) {
hasewgt = 1;
break;
}
}
}
fpout = gk_fopen(filename, "w", __func__);
/* write the header line */
fprintf(fpout, "%"PRIDX" %"PRIDX, nvtxs, xadj[nvtxs]/2);
if (hasvwgt || hasvsize || hasewgt) {
fprintf(fpout, " %d%d%d", hasvsize, hasvwgt, hasewgt);
if (hasvwgt)
fprintf(fpout, " %d", (int)graph->ncon);
}
/* write the rest of the graph */
for (i=0; i<nvtxs; i++) {
fprintf(fpout, "\n");
if (hasvsize)
fprintf(fpout, " %"PRIDX, vsize[i]);
if (hasvwgt) {
for (j=0; j<ncon; j++)
fprintf(fpout, " %"PRIDX, vwgt[i*ncon+j]);
}
for (j=xadj[i]; j<xadj[i+1]; j++) {
fprintf(fpout, " %"PRIDX, adjncy[j]+1);
if (hasewgt)
fprintf(fpout, " %"PRIDX, adjwgt[j]);
}
}
gk_fclose(fpout);
}